378 lines
16 KiB
PHP
378 lines
16 KiB
PHP
<?php
|
|
|
|
class WorkorderMphBaseController extends TTCrud
|
|
{
|
|
protected array $statusColumn = [
|
|
'key' => 'status', 'text' => 'Status', 'modal' => false, 'table' => ['filter' => 'iconSelect', 'filterOptions' => [
|
|
['value' => 'new', 'text' => 'Neu', 'icon' => 'fas fa-star text-primary'],
|
|
['value' => 'assigned', 'text' => 'Zugewiesen', 'icon' => 'fas fa-user-check text-info'],
|
|
['value' => 'scheduled', 'text' => 'Geplant', 'icon' => 'fas fa-calendar-check text-warning'],
|
|
['value' => 'in_progress', 'text' => 'In Bearbeitung', 'icon' => 'fas fa-cog text-warning'],
|
|
['value' => 'documented', 'text' => 'Dokumentiert', 'icon' => 'fas fa-file-alt text-success'],
|
|
['value' => 'completed', 'text' => 'Abgeschlossen', 'icon' => 'fas fa-check-double text-secondary'],
|
|
['value' => 'cancelled', 'text' => 'Abgebrochen', 'icon' => 'fas fa-ban text-danger'],
|
|
['value' => 'archived', 'text' => 'Archiviert', 'icon' => 'fas fa-archive text-muted'],
|
|
]]
|
|
];
|
|
|
|
protected array $additionalJS = ["js/pages/WorkorderMphBase/WorkorderMphBase.js"];
|
|
protected array $additionalHead = ["<link rel='stylesheet' href='/js/pages/WorkorderMphBase/WorkorderMphBase.css'>"];
|
|
|
|
protected function getStatusText(string $statusKey): string
|
|
{
|
|
$statusMap = array_column($this->statusColumn['table']['filterOptions'] ?? [], 'text', 'value');
|
|
return $statusMap[$statusKey] ?? ucfirst(str_replace('_', ' ', $statusKey));
|
|
}
|
|
|
|
//region SHARED ACTIONS
|
|
/**
|
|
* Fetches documentation and journal entries for a given workorder.
|
|
*/
|
|
protected function getDocumentationAction()
|
|
{
|
|
if (empty($this->request->workorderMphId)) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
|
|
$docs = WorkorderMphDocumentationModel::getAll(['workorderMphId' => intval($this->request->workorderMphId)], null, 0, ['key' => 'create', 'order' => 'ASC']);
|
|
$journals = WorkorderMphJournalModel::getAll(['workorderMphId' => intval($this->request->workorderMphId)], null, 0, ['key' => 'create', 'order' => 'DESC']);
|
|
|
|
$responseDocs = [];
|
|
$typeCounts = [];
|
|
|
|
foreach ($docs as $doc) {
|
|
$file = new File($doc->fileId);
|
|
$documentTypeKey = $doc->documentType;
|
|
$typeCounts[$documentTypeKey] = ($typeCounts[$documentTypeKey] ?? 0) + 1;
|
|
$originalFilename = $file->orig_filename ?? $file->filename;
|
|
$extension = pathinfo($originalFilename, PATHINFO_EXTENSION);
|
|
$newFilename = "{$documentTypeKey}_{$typeCounts[$documentTypeKey]}." . strtolower($extension);
|
|
|
|
$responseDocs[] = [
|
|
'id' => $doc->id,
|
|
'fileId' => $doc->fileId,
|
|
'fileName' => $newFilename,
|
|
'description' => $doc->description,
|
|
'documentType' => $documentTypeKey,
|
|
'userName' => UserModel::getOne($doc->createBy)->name ?? 'Unbekannt',
|
|
'mimetype' => $file->mimetype ?? 'application/octet-stream',
|
|
'create' => $doc->create
|
|
];
|
|
}
|
|
|
|
foreach ($journals as $journal) {
|
|
$journal->createByName = UserModel::getOne($journal->createBy)->name ?? 'Unbekannt';
|
|
}
|
|
|
|
self::returnJson(['docs' => $responseDocs, 'journals' => $journals]);
|
|
}
|
|
|
|
/**
|
|
* Adds a new entry to a workorder's journal.
|
|
*/
|
|
protected function addJournalAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderMphId']) || empty(trim($post['text']))) self::sendError("Arbeitsauftrags-ID und Text sind erforderlich.");
|
|
|
|
WorkorderMphJournalModel::create([
|
|
'workorderMphId' => $post['workorderMphId'],
|
|
'text' => $post['text'],
|
|
'createBy' => $this->user->id,
|
|
'create' => time()
|
|
]);
|
|
|
|
$journals = WorkorderMphJournalModel::getAll(['workorderMphId' => intval($post['workorderMphId'])], null, 0, ['key' => 'create', 'order' => 'DESC']);
|
|
foreach ($journals as $journal) {
|
|
$journal->createByName = UserModel::getOne($journal->createBy)->name ?? 'Unbekannt';
|
|
}
|
|
self::returnJson(['success' => true, 'message' => 'Journaleintrag hinzugefügt.', 'journals' => $journals]);
|
|
}
|
|
|
|
/**
|
|
* Updates the additional info field for a workorder.
|
|
*/
|
|
protected function updateAdditionalInfoAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderMphId'])) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
$workorder = WorkorderMphModel::get($post['workorderMphId']);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
|
|
$oldInfo = $workorder->additionalInfo;
|
|
$newInfo = $post['additionalInfo'] ?? null;
|
|
$workorder->additionalInfo = $newInfo;
|
|
WorkorderMphModel::update((array)$workorder);
|
|
|
|
WorkorderMphJournalModel::create([
|
|
'workorderMphId' => $workorder->id,
|
|
'text' => "Zusatzinfo geändert.\nAlt: '{$oldInfo}'\nNeu: '{$newInfo}'",
|
|
'create' => time(),
|
|
'createBy' => $this->user->id,
|
|
]);
|
|
self::returnJson(['success' => true, 'message' => 'Zusatzinfo aktualisiert.', 'newInfo' => $newInfo]);
|
|
}
|
|
|
|
/**
|
|
* Get all Wohneinheiten for a specific workorder with their statuses and notes
|
|
*/
|
|
protected function getWohneinheitenAction()
|
|
{
|
|
if (empty($this->request->workorderMphId)) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
|
|
$workorderMphId = intval($this->request->workorderMphId);
|
|
$workorder = WorkorderMphModel::get($workorderMphId);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
|
|
// Get all Wohneinheiten for this Hausnummer from addressdb
|
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
|
$hausnummerId = $db->escape($workorder->hausnummerId);
|
|
|
|
// Fetch statuses from addressdb
|
|
$statusSql = "SELECT id, code, name FROM Status WHERE type = 'wohneinheit' ORDER BY code ASC";
|
|
$statusResult = $db->query($statusSql);
|
|
$statuses = $statusResult ? $statusResult->fetch_all(MYSQLI_ASSOC) : [];
|
|
|
|
$statusOptions = array_map(function($s) {
|
|
return ['value' => intval($s['id']), 'text' => $s['code'] . ' - ' . $s['name'], 'code' => intval($s['code'])];
|
|
}, $statuses);
|
|
|
|
// Fetch Wohneinheiten directly
|
|
$sql = "SELECT w.id, w.zusatz, w.tuer, w.contact, w.oaid, w.note, w.status_id, w.splice_hak_completed
|
|
FROM Wohneinheit w
|
|
WHERE w.hausnummer_id = $hausnummerId
|
|
ORDER BY w.zusatz";
|
|
$result = $db->query($sql);
|
|
$wohneinheiten = $result ? $result->fetch_all(MYSQLI_ASSOC) : [];
|
|
|
|
// Get Preorders for this Hausnummer to fallback contact info
|
|
$preorders = [];
|
|
if (class_exists('PreorderModel')) {
|
|
$preorderList = PreorderModel::search(['adb_hausnummer_id' => $workorder->hausnummerId, 'deleted' => 0]);
|
|
foreach ($preorderList as $preorder) {
|
|
if ($preorder->adb_wohneinheit_id) {
|
|
$preorders[$preorder->adb_wohneinheit_id] = $preorder;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Merge data
|
|
$response = [];
|
|
foreach ($wohneinheiten as $we) {
|
|
// Contact info logic
|
|
$contact = $we['contact'];
|
|
$preorderContact = null;
|
|
$preorderUcode = null;
|
|
|
|
if (isset($preorders[$we['id']])) {
|
|
$p = $preorders[$we['id']];
|
|
$preorderUcode = $p->ucode;
|
|
$pContact = trim($p->firstname . ' ' . $p->lastname);
|
|
if ($p->phone) $pContact .= ' (' . $p->phone . ')';
|
|
|
|
$preorderContact = $pContact;
|
|
|
|
// If address contact is empty, use preorder contact
|
|
if (empty($contact)) {
|
|
$contact = $pContact;
|
|
}
|
|
}
|
|
|
|
$response[] = [
|
|
'wohneinheitId' => intval($we['id']),
|
|
'zusatz' => $we['zusatz'],
|
|
'tuer' => $we['tuer'],
|
|
'contact' => $contact,
|
|
'preorderContact' => $preorderContact,
|
|
'preorderUcode' => $preorderUcode,
|
|
'oaid' => $we['oaid'],
|
|
'status' => intval($we['status_id']),
|
|
'spliceCompleted' => intval($we['splice_hak_completed'] ?? 0),
|
|
'note' => $we['note'],
|
|
];
|
|
}
|
|
|
|
self::returnJson([
|
|
'wohneinheiten' => $response,
|
|
'statusOptions' => $statusOptions,
|
|
'hausnummerId' => $workorder->hausnummerId
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Update status and note for a specific Wohneinheit
|
|
*/
|
|
protected function updateWohneinheitAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderMphId']) || empty($post['wohneinheitId'])) {
|
|
self::sendError("Arbeitsauftrags-ID und Wohneinheit-ID sind erforderlich.");
|
|
}
|
|
|
|
$workorderMphId = intval($post['workorderMphId']);
|
|
$wohneinheitId = intval($post['wohneinheitId']);
|
|
$newStatusId = intval($post['status'] ?? 1);
|
|
$spliceCompleted = isset($post['spliceCompleted']) ? intval($post['spliceCompleted']) : 0;
|
|
$tuer = $post['tuer'] ?? null;
|
|
$zusatz = $post['zusatz'] ?? null;
|
|
|
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
|
$escapedWohneinheitId = $db->escape($wohneinheitId);
|
|
|
|
// Fetch current state
|
|
$currentSql = "SELECT status_id, tuer, zusatz, splice_hak_completed FROM Wohneinheit WHERE id = $escapedWohneinheitId";
|
|
$result = $db->query($currentSql);
|
|
$current = $result ? $result->fetch_assoc() : null;
|
|
|
|
if (!$current) self::sendError("Wohneinheit nicht gefunden.");
|
|
|
|
$oldStatusId = intval($current['status_id']);
|
|
$oldTuer = $current['tuer'];
|
|
$oldZusatz = $current['zusatz'];
|
|
$oldSplice = intval($current['splice_hak_completed'] ?? 0);
|
|
|
|
// Update Wohneinheit
|
|
$escapedTuer = $tuer !== null ? "'" . $db->escape($tuer) . "'" : "NULL";
|
|
$escapedZusatz = $zusatz !== null ? "'" . $db->escape($zusatz) . "'" : "NULL";
|
|
$escapedStatusId = $db->escape($newStatusId);
|
|
$escapedSplice = $db->escape($spliceCompleted);
|
|
|
|
$updateSql = "UPDATE Wohneinheit SET
|
|
status_id = $escapedStatusId,
|
|
tuer = $escapedTuer,
|
|
zusatz = $escapedZusatz,
|
|
splice_hak_completed = $escapedSplice
|
|
WHERE id = $escapedWohneinheitId";
|
|
|
|
$db->query($updateSql);
|
|
|
|
// Journaling
|
|
$changes = [];
|
|
if ($oldStatusId !== $newStatusId) {
|
|
// Fetch status names for better logging
|
|
$statusNamesSql = "SELECT id, code, name FROM Status WHERE id IN ($oldStatusId, $newStatusId)";
|
|
$statusRes = $db->query($statusNamesSql);
|
|
$statusMap = [];
|
|
if ($statusRes) {
|
|
while($row = $statusRes->fetch_assoc()) {
|
|
$statusMap[$row['id']] = $row['code'] . ' - ' . $row['name'];
|
|
}
|
|
}
|
|
$oldText = $statusMap[$oldStatusId] ?? "ID $oldStatusId";
|
|
$newText = $statusMap[$newStatusId] ?? "ID $newStatusId";
|
|
$changes[] = "Status: $oldText → $newText";
|
|
}
|
|
|
|
if ($oldSplice !== $spliceCompleted) {
|
|
$changes[] = "Spleiß: " . ($spliceCompleted ? 'Erledigt' : 'Nicht erledigt');
|
|
}
|
|
|
|
if ($oldTuer !== $tuer) {
|
|
$changes[] = "Tür aktualisiert: '$oldTuer' -> '$tuer'";
|
|
}
|
|
if ($oldZusatz !== $zusatz) {
|
|
$changes[] = "Zusatz aktualisiert: '$oldZusatz' -> '$zusatz'";
|
|
}
|
|
|
|
if (!empty($changes)) {
|
|
WorkorderMphJournalModel::create([
|
|
'workorderMphId' => $workorderMphId,
|
|
'text' => "Wohneinheit $wohneinheitId: " . implode(', ', $changes),
|
|
'create' => time(),
|
|
'createBy' => $this->user->id,
|
|
]);
|
|
}
|
|
|
|
// Status flag logic for BEP MD (241) and ONT (300). Need to check codes for these IDs.
|
|
// Since we only have IDs, we need to check the code of the newStatusId.
|
|
$newStatusCodeSql = "SELECT code FROM Status WHERE id = $escapedStatusId";
|
|
$resCode = $db->query($newStatusCodeSql);
|
|
$newStatusCode = $resCode ? intval($resCode->fetch_assoc()['code']) : 0;
|
|
|
|
if (in_array($newStatusCode, [241, 300])) { // 241=BEP MD, 300=ONT
|
|
$this->setWohneinheitStatusflag($wohneinheitId, 200);
|
|
}
|
|
|
|
self::returnJson(['success' => true, 'message' => 'Wohneinheit aktualisiert.']);
|
|
}
|
|
|
|
/**
|
|
* Set statusflag on Wohneinheit in addressdb
|
|
*/
|
|
private function setWohneinheitStatusflag(int $wohneinheitId, int $statusflagId)
|
|
{
|
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
|
$weId = $db->escape($wohneinheitId);
|
|
$sfId = $db->escape($statusflagId);
|
|
|
|
// Check if statusflag already exists
|
|
$checkSql = "SELECT COUNT(*) as count FROM WohneinheitStatusflagValue WHERE wohneinheit_id = $weId AND statusflag_id = $sfId";
|
|
$result = $db->query($checkSql);
|
|
$exists = $result->fetch_assoc()['count'] > 0;
|
|
|
|
if (!$exists) {
|
|
$insertSql = "INSERT INTO WohneinheitStatusflagValue (wohneinheit_id, statusflag_id, create, createBy)
|
|
VALUES ($weId, $sfId, " . time() . ", " . $this->user->id . ")";
|
|
$db->query($insertSql);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update checkbox documentation fields
|
|
*/
|
|
protected function updateCheckboxesAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderMphId'])) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
|
|
$workorder = WorkorderMphModel::get($post['workorderMphId']);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
|
|
$changes = [];
|
|
$checkboxFields = ['easement', 'btb', 'fttxLocationSupplied', 'conduitToHuepLaid', 'huepMounted', 'dropCableAvailable', 'spliceCompleted'];
|
|
|
|
$updateHausnummerStatus = false;
|
|
|
|
foreach ($checkboxFields as $field) {
|
|
if (array_key_exists($field, $post)) {
|
|
$oldValue = $workorder->$field;
|
|
$newValue = $post[$field] ? 1 : 0;
|
|
if ($oldValue !== $newValue) {
|
|
$workorder->$field = $newValue;
|
|
$changes[] = "$field: " . ($newValue ? 'ja' : 'nein');
|
|
|
|
// Check for FTTx Location mit Leerrohr versorgt
|
|
if ($field === 'fttxLocationSupplied' && $newValue === 1) {
|
|
$updateHausnummerStatus = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!empty($changes)) {
|
|
WorkorderMphModel::update((array)$workorder);
|
|
|
|
if ($updateHausnummerStatus) {
|
|
$db = FronkDB::singleton(ADDRESSDB_DBHOST, ADDRESSDB_DBUSER, ADDRESSDB_DBPASS, ADDRESSDB_DBNAME);
|
|
// Find status ID for code 200
|
|
$statusSql = "SELECT id FROM Status WHERE code = 200 AND type = 'hausnummer' LIMIT 1";
|
|
$statusResult = $db->query($statusSql);
|
|
if ($statusResult && $row = $statusResult->fetch_assoc()) {
|
|
$statusId = $row['id'];
|
|
$hnId = $db->escape($workorder->hausnummerId);
|
|
$updateHnSql = "UPDATE Hausnummer SET status_id = $statusId WHERE id = $hnId";
|
|
$db->query($updateHnSql);
|
|
}
|
|
}
|
|
|
|
WorkorderMphJournalModel::create([
|
|
'workorderMphId' => $workorder->id,
|
|
'text' => "Dokumentation aktualisiert:\n" . implode("\n", $changes),
|
|
'create' => time(),
|
|
'createBy' => $this->user->id,
|
|
]);
|
|
}
|
|
|
|
self::returnJson(['success' => true, 'message' => 'Dokumentation aktualisiert.']);
|
|
}
|
|
//endregion
|
|
}
|