353 lines
19 KiB
PHP
353 lines
19 KiB
PHP
<?php
|
|
// RMLWorkorderCompanyController.php
|
|
|
|
class RMLWorkorderCompanyController extends TTCrud
|
|
{
|
|
protected string $headerTitle = 'Meine Arbeitsaufträge';
|
|
protected bool $createText = false;
|
|
protected array $permissionCheck = ['RMLCompany'];
|
|
protected array $columns = [
|
|
['key' => 'id', 'text' => 'Auftrags-Nr.', 'table' => ['sortable' => true]],
|
|
['key' => 'preorderInfo', 'text' => 'Kunde', 'modal' => false, 'table' => ['sortable' => false]],
|
|
['key' => 'rimo_fcp_name', 'text' => 'FCP', 'modal' => false, 'table' => ['sortable' => false]],
|
|
['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' => 'correction_requested', 'text' => 'Korrektur angefordert', 'icon' => 'fas fa-exclamation-triangle text-danger'],
|
|
['value' => 'intervention_required', 'text' => 'Eingriff erforderlich', 'icon' => 'fas fa-times-circle text-danger'],
|
|
['value' => 'problem_solved', 'text' => 'Problem gelöst', 'icon' => 'fas fa-check-circle text-success'],
|
|
['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'],
|
|
]]],
|
|
['key' => 'additionalInfo', 'text' => 'Notiz', 'modal' => false, 'table' => ['sortable' => true]],
|
|
['key' => 'deadlineDate', 'text' => 'Deadline', 'modal' => false, 'table' => ['filter' => 'date', 'sortable' => true]],
|
|
['key' => 'appointmentDate', 'text' => 'Termin', 'modal' => false, 'table' => ['filter' => 'date', 'sortable' => true]],
|
|
];
|
|
|
|
protected array $additionalJSVariables = ['COMPANY_ID' => '0'];
|
|
|
|
private function getStatusText(string $statusKey): string
|
|
{
|
|
foreach ($this->columns as $column) {
|
|
if ($column['key'] === 'status') {
|
|
foreach ($column['table']['filterOptions'] as $option) {
|
|
if ($option['value'] === $statusKey) {
|
|
return $option['text'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ucfirst(str_replace('_', ' ', $statusKey)); // Fallback
|
|
}
|
|
|
|
protected function prepareCrudConfig()
|
|
{
|
|
$company = RMLWorkorderCompanyModel::getFirst(['addressId' => $this->user->address_id]);
|
|
if ($company) {
|
|
$this->additionalJSVariables['COMPANY_ID'] = $company->id;
|
|
} else {
|
|
$this->additionalJSVariables['COMPANY_ID'] = 0;
|
|
}
|
|
}
|
|
|
|
protected function indexAction()
|
|
{
|
|
Helper::renderVue($this, 'RMLWorkorderCompany', $this->headerTitle, [
|
|
"CRUD_CONFIG" => $this->getCrudConfig(),
|
|
"TABLE_URL" => $this::getUrl("RMLWorkorderCompany/get"),
|
|
"COMPANY_ID" => $this->additionalJSVariables['COMPANY_ID'],
|
|
]);
|
|
}
|
|
|
|
protected function getAction()
|
|
{
|
|
$json = json_decode(file_get_contents('php://input'), true);
|
|
$pagination = $json['pagination'] ?? ['page' => 1, 'per_page' => 10];
|
|
$filters = $json['filters'] ?? [];
|
|
$order = $json['order'] ?? [];
|
|
|
|
$company = RMLWorkorderCompanyModel::getFirst(['addressId' => $this->user->address_id]);
|
|
if (!$company) {
|
|
self::returnJson(['rows' => [], 'pagination' => array_merge($pagination, ['total_rows' => 0, 'total_pages' => 0, 'filtered_available' => 0])]);
|
|
return;
|
|
}
|
|
$companyId = $company->id;
|
|
|
|
$workorders = RMLWorkorderModel::getCompanyWorkorders($filters, $pagination['per_page'], ($pagination['page'] - 1) * $pagination['per_page'], $order, $companyId);
|
|
$totalCount = RMLWorkorderModel::countCompanyWorkorders($filters, $companyId);
|
|
|
|
$rows = array_map(function ($workorder) {
|
|
$row = (array)$workorder;
|
|
$row['preorderInfo'] = $this->getPreorderInfoTextByData($row);
|
|
unset($row['customerName'], $row['customerCompany'], $row['street'], $row['hausnummer'], $row['stiege'], $row['oaid'], $row['apartment'], $row['plz'], $row['city'], $row['phone'], $row['email']);
|
|
return $row;
|
|
}, $workorders);
|
|
|
|
self::returnJson([
|
|
'rows' => $rows,
|
|
'pagination' => [
|
|
'page' => $pagination['page'], 'per_page' => $pagination['per_page'],
|
|
'total_rows' => $totalCount, 'total_pages' => ceil($totalCount / $pagination['per_page']),
|
|
'filtered_available' => $totalCount
|
|
]
|
|
]);
|
|
}
|
|
|
|
private function getPreorderInfoTextByData($data)
|
|
{
|
|
$anschlussadresse = "{$data['street']} {$data['hausnummer']}";
|
|
if ($data['stiege']) $anschlussadresse .= "/{$data['stiege']}";
|
|
if ($data['apartment']) $anschlussadresse .= " / WE: {$data['apartment']}";
|
|
$anschlussadresse .= ", {$data['plz']} {$data['city']}";
|
|
$kunde = $data['customerCompany'] ?: $data['customerName'];
|
|
return "<strong>Kunde:</strong> {$kunde}<br>" . "<strong>Anschluss:</strong> {$anschlussadresse}<br>" . "<strong>Kontakt:</strong> {$data['phone']} / {$data['email']}<br>" . "<strong>OAID:</strong> <span class='text-pink'>{$data['oaid']}</span>";
|
|
}
|
|
|
|
public function getWorkorderByIdAction()
|
|
{
|
|
$id = $this->request->id;
|
|
if (!$id) self::sendError("ID fehlt");
|
|
$workorder = RMLWorkorderModel::get($id);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden");
|
|
$workorder->preorderInfo = $this->getPreorderInfoText($workorder->preorderId);
|
|
self::returnJson((array)$workorder);
|
|
}
|
|
|
|
private function getPreorderInfoText($preorderId)
|
|
{
|
|
$preorder = new Preorder($preorderId);
|
|
$anschlussadresse = 'N/A';
|
|
if ($preorder->adb_hausnummer_id) {
|
|
$hn = $preorder->adb_hausnummer;
|
|
$anschlussadresse = "{$hn->strasse->name} {$hn->hausnummer}";
|
|
if ($hn->stiege) $anschlussadresse .= "/{$hn->stiege}";
|
|
if ($preorder->adb_wohneinheit_id) $anschlussadresse .= " / WE: {$preorder->adb_wohneinheit->bezeichner}";
|
|
$anschlussadresse .= ", {$hn->plz->plz} {$hn->ortschaft->name}";
|
|
}
|
|
$kunde = ($preorder->company) ?: "{$preorder->firstname} {$preorder->lastname}";
|
|
return "<strong>Kunde:</strong> {$kunde}<br>" . "<strong>Anschluss:</strong> {$anschlussadresse}<br>" . "<strong>Kontakt:</strong> {$preorder->phone} / {$preorder->email}<br>" . "<strong>OAID:</strong> <span class='text-pink'>{$preorder->oaid}</span>";
|
|
}
|
|
|
|
protected function scheduleAppointmentAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderId']) || empty($post['appointmentDate'])) self::sendError("Erforderliche Felder fehlen.");
|
|
$workorder = RMLWorkorderModel::get($post['workorderId']);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden");
|
|
$hour = (int)date('H', $post['appointmentDate']);
|
|
if ($hour >= 23 || $hour < 1) self::sendError("Bitte geben Sie eine Uhrzeit an!");
|
|
|
|
$workorder->appointmentDate = $post['appointmentDate'];
|
|
$workorder->status = 'scheduled';
|
|
RMLWorkorderModel::update((array)$workorder);
|
|
RMLWorkorderJournalModel::create([
|
|
'workorderId' => $workorder->id, 'text' => 'Termin festgelegt auf: ' . date('d.m.Y H:i', $post['appointmentDate']),
|
|
'create' => time(), 'createBy' => $this->user->id,
|
|
]);
|
|
self::returnJson(['success' => true, 'message' => 'Termin erfolgreich gespeichert.']);
|
|
}
|
|
|
|
protected function rescheduleAppointmentAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderId']) || empty($post['appointmentDate']) || empty($post['reason'])) self::sendError("Erforderliche Felder fehlen.");
|
|
$workorder = RMLWorkorderModel::get($post['workorderId']);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
$hour = (int)date('H', $post['appointmentDate']);
|
|
if ($hour >= 23 || $hour < 1) self::sendError("Bitte geben Sie eine Uhrzeit an!");
|
|
|
|
$oldDateFormatted = $workorder->appointmentDate ? date('d.m.Y H:i', $workorder->appointmentDate) : 'N/A';
|
|
$newDateFormatted = date('d.m.Y H:i', $post['appointmentDate']);
|
|
$workorder->appointmentDate = $post['appointmentDate'];
|
|
RMLWorkorderModel::update((array)$workorder);
|
|
RMLWorkorderJournalModel::create([
|
|
'workorderId' => $workorder->id, 'text' => "Termin verschoben von {$oldDateFormatted} auf {$newDateFormatted}. Grund: " . $post['reason'],
|
|
'create' => time(), 'createBy' => $this->user->id,
|
|
]);
|
|
self::returnJson(['success' => true, 'message' => 'Termin erfolgreich verschoben.']);
|
|
}
|
|
|
|
protected function requestInterventionAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderId']) || empty($post['journalText'])) self::sendError("Erforderliche Felder fehlen.");
|
|
$workorder = RMLWorkorderModel::get($post['workorderId']);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
|
|
$oldStatus = $workorder->status;
|
|
$workorder->status = 'intervention_required';
|
|
RMLWorkorderModel::update((array)$workorder);
|
|
RMLWorkorderJournalModel::create([
|
|
'workorderId' => $workorder->id, 'text' => "Eingriff erforderlich: " . $post['journalText'],
|
|
'statusChange' => $this->getStatusText($oldStatus) . " -> " . $this->getStatusText('intervention_required'),
|
|
'create' => time(), 'createBy' => $this->user->id,
|
|
]);
|
|
self::returnJson(['success' => true, 'message' => 'Eingriff wurde angefordert.']);
|
|
}
|
|
|
|
protected function uploadDocumentationAction()
|
|
{
|
|
if (empty($_FILES['files']) || empty($_POST['workorderId'])) {
|
|
self::returnJson(['error' => 'Erforderliche Daten fehlen.']);
|
|
return;
|
|
}
|
|
$workorderId = $_POST['workorderId'];
|
|
$description = $_POST['description'] ?? '';
|
|
$documentType = $_POST['documentType'] ?? 'general';
|
|
$files = $_FILES['files'];
|
|
$uploadCount = 0;
|
|
|
|
foreach ($files['name'] as $index => $name) {
|
|
if ($files['error'][$index] === UPLOAD_ERR_OK) {
|
|
$_FILES['file'] = ['name' => $files['name'][$index], 'type' => $files['type'][$index], 'tmp_name' => $files['tmp_name'][$index], 'error' => $files['error'][$index], 'size' => $files['size'][$index]];
|
|
try {
|
|
$uploaded = mfUpload::handleFormUpload("file", false, "/RMLWorkorder");
|
|
RMLWorkorderDocumentationModel::create(['workorderId' => $workorderId, 'fileId' => $uploaded->id, 'description' => $description, 'documentType' => $documentType, 'create' => time(), 'createBy' => $this->user->id]);
|
|
$uploadCount++;
|
|
} catch (Exception $e) {
|
|
error_log("Dateiupload für $name fehlgeschlagen: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
$workorder = RMLWorkorderModel::get($workorderId);
|
|
if ($workorder->status === 'correction_requested' || $workorder->status === 'problem_solved') {
|
|
$workorder->status = 'assigned';
|
|
RMLWorkorderModel::update((array)$workorder);
|
|
$workorder = RMLWorkorderModel::get($workorderId);
|
|
}
|
|
$formattedDocs = $this->getFormattedDocs($workorderId);
|
|
self::returnJson(['success' => true, 'message' => "$uploadCount Datei(en) erfolgreich hochgeladen.", 'docs' => $formattedDocs, 'workorder' => (array)$workorder]);
|
|
}
|
|
|
|
private function getFormattedDocs($workorderId)
|
|
{
|
|
$docs = RMLWorkorderDocumentationModel::getAll(['workorderId' => $workorderId], null, 0, ['key' => 'create', 'order' => 'ASC']);
|
|
$responseDocs = [];
|
|
$typeCounts = [];
|
|
$translationMap = [
|
|
'photo_hup_mounted' => 'Foto_montierter_HÜP', 'photo_hup_open' => 'Foto_offener_HÜP',
|
|
'photo_splice_cassette_hup' => 'Foto_Spleißkassette_HÜP', 'photo_splice_cassette_fcp' => 'Foto_Spleißkassette_FCP',
|
|
'photo_hup_closed_stickers' => 'Foto_geschlossener_HÜP_mit_Aufklebern', 'photo_fcp_labeled' => 'Foto_FCP_beschriftet',
|
|
'photo_patch_position_osp' => 'Foto_Patch-Position_OSP-Seite', 'photo_patch_position_anb' => 'Foto_Patch-Position_ANB-Seite',
|
|
'measurement_protocol_otdr' => 'ODTR_Messung', 'other' => 'Sonstiges_Dokument'
|
|
];
|
|
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);
|
|
$translatedType = $translationMap[$documentTypeKey] ?? $documentTypeKey;
|
|
$newFilename = "{$translatedType}_{$typeCounts[$documentTypeKey]}." . strtolower($extension);
|
|
$responseDocs[] = ['id' => $doc->id, 'fileId' => $doc->fileId, 'fileName' => $newFilename, 'description' => $doc->description, 'documentType' => $documentTypeKey, 'mimetype' => $file->mimetype];
|
|
}
|
|
return $responseDocs;
|
|
}
|
|
|
|
protected function getDocumentationAction()
|
|
{
|
|
if (empty($this->request->workorderId)) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
$docs = $this->getFormattedDocs($this->request->workorderId);
|
|
$journals = array_map(function ($j) {
|
|
$j->createByName = UserModel::getOne($j->createBy)->getAbbrName();
|
|
return (array)$j;
|
|
},
|
|
RMLWorkorderJournalModel::getAll(['workorderId' => $this->request->workorderId], null, 0, ['key' => 'create', 'order' => 'DESC'])
|
|
);
|
|
self::returnJson(['docs' => $docs, 'journals' => $journals]);
|
|
}
|
|
|
|
protected function completeWorkorderAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderId'])) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
$workorder = RMLWorkorderModel::get($post['workorderId']);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
$workorder->status = 'documented';
|
|
RMLWorkorderModel::update((array)$workorder);
|
|
self::returnJson(['success' => true, 'message' => 'Arbeitsauftrag abgeschlossen.']);
|
|
}
|
|
|
|
protected function deleteDocumentationAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['id'])) self::sendError("Dokumenten-ID fehlt.");
|
|
$doc = RMLWorkorderDocumentationModel::get($post['id']);
|
|
if (!$doc) self::sendError("Dokument nicht gefunden.");
|
|
$workorderId = $doc->workorderId;
|
|
RMLWorkorderDocumentationModel::delete($post['id']);
|
|
$formattedDocs = $this->getFormattedDocs($workorderId);
|
|
self::returnJson(['success' => true, 'message' => 'Dokument gelöscht.', 'docs' => $formattedDocs]);
|
|
}
|
|
|
|
protected function updateDocumentationAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['id'])) self::sendError("Dokumenten-ID fehlt.");
|
|
$doc = RMLWorkorderDocumentationModel::get($post['id']);
|
|
if (!$doc) self::sendError("Dokument nicht gefunden.");
|
|
if (isset($post['documentType'])) $doc->documentType = $post['documentType'];
|
|
RMLWorkorderDocumentationModel::update((array)$doc);
|
|
$formattedDocs = $this->getFormattedDocs($doc->workorderId);
|
|
self::returnJson(['success' => true, 'message' => 'Dokument aktualisiert.', 'docs' => $formattedDocs]);
|
|
}
|
|
|
|
protected function addJournalAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderId']) || empty(trim($post['text']))) self::sendError("Arbeitsauftrags-ID und Text sind erforderlich.");
|
|
RMLWorkorderJournalModel::create(['workorderId' => $post['workorderId'], 'text' => $post['text'], 'createBy' => $this->user->id, 'create' => time()]);
|
|
$journals = array_map(function ($j) {
|
|
$j->createByName = UserModel::getOne($j->createBy)->getAbbrName();
|
|
return (array)$j;
|
|
},
|
|
RMLWorkorderJournalModel::getAll(['workorderId' => $post['workorderId']], null, 0, ['key' => 'create', 'order' => 'DESC'])
|
|
);
|
|
self::returnJson(['success' => true, 'message' => 'Journaleintrag hinzugefügt.', 'journals' => $journals]);
|
|
}
|
|
|
|
protected function getTenantConfigAction()
|
|
{
|
|
if (empty($this->request->workorderId)) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
$workorder = RMLWorkorderModel::get($this->request->workorderId);
|
|
if (!$workorder) self::sendError("Arbeitsauftrag nicht gefunden.");
|
|
$preorder = new Preorder($workorder->preorderId);
|
|
if (!$preorder->id) self::sendError("Vorbestellung nicht gefunden.");
|
|
$campaign = new Preordercampaign($preorder->preordercampaign_id);
|
|
if (!$campaign->id) self::sendError("Kampagne nicht gefunden.");
|
|
$network = NetworkModel::getOne($campaign->network_id);
|
|
if (!$network) self::sendError("Netzwerk nicht gefunden.");
|
|
$tenantId = $network->owner_id;
|
|
$tenantConfig = RMLWorkorderTenantConfigModel::getFirst(['addressId' => $tenantId]) ?? RMLWorkorderTenantConfigModel::getFirst(['addressId' => 4807]);
|
|
if (!$tenantConfig) {
|
|
self::returnJson(['success' => false, 'message' => 'Keine Mandantenkonfiguration gefunden.']);
|
|
return;
|
|
}
|
|
self::returnJson(['success' => true, 'documentationTypes' => json_decode($tenantConfig->documentationTypes, true)]);
|
|
}
|
|
|
|
protected function updateAdditionalInfoAction()
|
|
{
|
|
$post = json_decode(file_get_contents('php://input'), true);
|
|
if (empty($post['workorderId'])) self::sendError("Arbeitsauftrags-ID fehlt.");
|
|
|
|
$company = RMLWorkorderCompanyModel::getFirst(['addressId' => $this->user->address_id]);
|
|
if (!$company) self::sendError("Firma nicht gefunden.");
|
|
|
|
$workorder = RMLWorkorderModel::get($post['workorderId']);
|
|
if (!$workorder || $workorder->companyId !== $company->id) self::sendError("Arbeitsauftrag nicht gefunden oder nicht Ihrer Firma zugewiesen.");
|
|
|
|
$oldInfo = $workorder->additionalInfo;
|
|
$workorder->additionalInfo = $post['additionalInfo'] ?? null;
|
|
RMLWorkorderModel::update((array)$workorder);
|
|
|
|
RMLWorkorderJournalModel::create([
|
|
'workorderId' => $workorder->id, 'text' => "Zusatzinfo geändert.\nAlt: '{$oldInfo}'\nNeu: '{$workorder->additionalInfo}'",
|
|
'create' => time(), 'createBy' => $this->user->id,
|
|
]);
|
|
self::returnJson(['success' => true, 'message' => 'Zusatzinfo aktualisiert.']);
|
|
}
|
|
} |