'id', 'text' => 'ID', 'modal' => false, 'table' => false], ['key' => 'orderNumber', 'text' => 'Bestellnummer', 'required' => true, 'modal' => false], ['key' => 'distributorId', 'text' => 'Lieferant', 'required' => false, 'modal' => ['type' => 'select', 'items' => []], 'table' => ['filter' => 'select']], ['key' => 'delAddrCity', 'text' => 'Stadt', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrEMail', 'text' => 'E-Mail', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrLine', 'text' => 'Adresse', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrName', 'text' => 'Name', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'delAddrPLZ', 'text' => 'PLZ', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'editor', 'text' => 'Bearbeiter', 'required' => true, 'modal' => ['type' => 'select'], 'table' => ['filter' => 'select']], ['key' => 'note', 'text' => 'Notiz', 'required' => false, 'modal' => false, 'table' => false], ['key' => 'sum', 'text' => 'Summe', 'required' => false, 'modal' => false, 'table' => ['class' => 'text-right']], ['key' => 'status', 'text' => 'Status', 'required' => false, 'modal' => ['type' => 'select', 'items' => [ ['value' => 'new', 'text' => 'Neu'], ['value' => 'accepted', 'text' => 'Akzeptiert'], ['value' => 'ordered', 'text' => 'Bestellt'], ['value' => 'sent', 'text' => 'Versendet'], ['value' => 'partiallyDelivered', 'text' => 'Teilweise geliefert'], ['value' => 'fullyDelivered', 'text' => 'Geliefert'], ['value' => 'cancelled', 'text' => 'Storniert'], ]], 'table' => ['filter' => 'select']], ['key' => 'positions', 'text' => 'Positionen', 'required' => true, 'modal' => false, 'table' => false], ['key' => 'extReference', 'text' => 'Externe Referenz', 'required' => false, 'modal' => false], ['key' => 'createBy', 'text' => 'Erstellt von', 'required' => true, 'modal' => ['type' => 'select'], 'table' => ['filter' => 'select']], ['key' => 'create', 'text' => 'Erstellt', 'required' => true, 'modal' => false], ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']], ]; //@formatter:on protected array $infoMessages = ['create' => 'Bestellung wurde erfolgreich erstellt.', 'update' => 'Bestellung wurde aktualisiert.', 'delete' => 'Bestellung wurde gelöscht', 'noChanges' => 'Keine Änderungen',]; protected array $additionalActions = [['key' => 'openpdf', 'title' => 'PDF öffnen', 'class' => 'fas fa-file-pdf', 'color' => 'primary']]; protected function prepareCrudConfig(): void { $editorColumnIndex = array_search('editor', array_column($this->columns, 'key')); $this->columns[$editorColumnIndex]['modal']['items'] = array_map(function ($user) { return ['value' => intval($user->id), 'text' => $user->name]; }, UserModel::search(['employee' => true])); $distributorIndex = array_search('distributorId', array_column($this->columns, 'key')); $this->columns[$distributorIndex]['modal']['items'] = array_map(function ($distributor) { return ['value' => intval($distributor->id), 'text' => $distributor->name]; }, WarehouseDistributorModel::getAll()); $this->additionalActions[] = [ 'key' => 'changeStatus', 'title' => 'Status ändern', 'class' => 'fas fa-exchange-alt', 'color' => 'warning', ]; } protected function beforeCreate(): bool { $this->postData['orderNumber'] = 'PO' . date('Y') . '-' . str_pad(WarehouseOrderModel::count(['create' => ['from' => strtotime(date('Y-01-01'))]]) + 1, 4, '0', STR_PAD_LEFT); return true; } protected function getArticleDistributorDataAction() { $articleId = $this->request->articleId; if ($this->request->allDistributor === 'true') self::returnJson(array_map(fn($d) => ['id' => $d->id, 'name' => $d->name], WarehouseDistributorModel::getAll())); else if (!empty($articleId)) self::returnJson(array_map(fn($d) => ['id' => $d->distributorId, 'name' => WarehouseDistributorModel::get($d->distributorId)->name, 'purchasePrice' => $d->purchasePrice, 'externalArticleNumber' => $d->externalArticleNumber], WarehouseArticleDistributorModel::getAll(['articleId' => $articleId]))); else self::returnJson([]); } protected function getByIdParse(array $order): array { $order['positions'] = json_decode($order['positions'], true); foreach ($order['positions'] as &$position) { $position['distributorName'] = WarehouseDistributorModel::get($position['distributorId'])->name; $position['articleName'] = WarehouseArticleModel::get($position['article'])->title; } return $order; } protected function createPDFAction() { $order = (array) WarehouseOrderModel::get($this->request->id); $order['positions'] = json_decode($order['positions'], true); // check if all positions have the same distributor $distributorId = $order['positions'][0]['distributorId']; foreach ($order['positions'] as $key => $position) { if ($position['distributorId'] !== $distributorId) { self::returnJson(['error' => 'Die Bestellung enthält Positionen von verschiedenen Lieferanten.']); } // we need to get the article name and distributor name for the pdf $position['distributorName'] = WarehouseDistributorModel::get($position['distributorId'])->name; $position['articleName'] = WarehouseArticleModel::get($position['article'])->title; $position['articleDescription'] = WarehouseArticleModel::get($position['article'])->description; $order['positions'][$key] = $position; } $pdf_vars = ['order' => $order, 'distributor' => WarehouseDistributorModel::get($distributorId), 'distributorCountryText' => (new Country(WarehouseDistributorModel::get($distributorId)->countryId))->name, "bank_iban" => TT_INVOICE_BANK_IBAN, "bank_bic" => TT_INVOICE_BANK_BIC, "bank_bank" => TT_INVOICE_BANK_BANK, "bank_owner" => TT_INVOICE_BANK_OWNER]; $countryText = (new Country(WarehouseDistributorModel::get($distributorId)->countryId))->name; $shouldGenerateEnglisch = !in_array($countryText, ['Österreich', 'Deutschland', 'Schweiz']); $headerHtml = file_get_contents(BASEDIR . "/Layout/default/WarehouseOrder/PDF_HEADER.html"); $headerHtml = str_replace("{{ basedir }}", BASEDIR, $headerHtml); $headerHtml = str_replace("{{ externalReference }}", !empty($order['extReference']) && count($order['extReference']) > 0 ? "Ext. Ref.: ". $order['extReference'] : "", $headerHtml); $headerHtml = str_replace("{{ addressLine_header }}", $shouldGenerateEnglisch ? "Supplier" : "Lieferant", $headerHtml); $headerHtml = str_replace("{{ addressLine_1 }}", WarehouseDistributorModel::get($distributorId)->name, $headerHtml); $headerHtml = str_replace("{{ addressLine_2 }}", WarehouseDistributorModel::get($distributorId)->address, $headerHtml); $headerHtml = str_replace("{{ addressLine_3 }}", WarehouseDistributorModel::get($distributorId)->plz . " " . WarehouseDistributorModel::get($distributorId)->city, $headerHtml); $headerHtml = str_replace("{{ addressLine_4 }}", $countryText, $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_header }}", $shouldGenerateEnglisch ? "Billing Address" : "Rechnungsadresse", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_1 }}", "Xinon GmbH", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_2 }}", "Fladnitz im Raabtal 150", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_3 }}", "A-8322 Studenzen", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_4 }}", "UID: ATU68711968", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_5 }}", "EORI-Nr.: ATEOS1000085074", $headerHtml); $headerHtml = str_replace("{{ billingAddressLine_6 }}", "Referenz: ". $order["orderNumber"] . "", $headerHtml); $chk = $order['delAddrLine'] == "Fladnitz im Raabtal 150"; $headerHtml = str_replace("{{ shippingAddressLine_header }}", $chk ? "" : ($shouldGenerateEnglisch ? "Shipping Address" : "Lieferadresse"), $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_1 }}", $chk ? "" : $order['delAddrName'], $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_2 }}", $chk ? "" : $order['delAddrLine'], $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_3 }}", $chk ? "" : $order['delAddrPLZ'] . " " . $order['delAddrCity'], $headerHtml); $headerHtml = str_replace("{{ shippingAddressLine_4 }}", $chk ? "" : $order['delAddrEMail'], $headerHtml); $headerFile = BASEDIR . "/var/temp/order_header-" . date("U") . "-" . rand(1000, 9999) . ".html"; file_put_contents($headerFile, $headerHtml); $footerHtml = file_get_contents(BASEDIR . "/Layout/default/WarehouseOrder/PDF_FOOTER.html"); $footerHtml = str_replace("{{ bank_iban }}", TT_INVOICE_BANK_IBAN_FORMATTED, $footerHtml); $footerHtml = str_replace("{{ bank_bic }}", TT_INVOICE_BANK_BIC, $footerHtml); $footerHtml = str_replace("{{ bank_bank }}", TT_INVOICE_BANK_BANK, $footerHtml); $footerHtml = str_replace("{{ bank_owner }}", TT_INVOICE_BANK_OWNER, $footerHtml); $footerFile = BASEDIR . "/var/temp/order_footer-" . date("U") . "-" . rand(1000, 9999) . ".html"; file_put_contents($footerFile, $footerHtml); $pdf = new PdfForm("WarehouseOrder/PDF_MAIN", $pdf_vars); $wkhtmltopdfArgs = "--header-html $headerFile --footer-html $footerFile"; $filename = $pdf->render($wkhtmltopdfArgs); // return the pdf and die so the client sees the pdf not the filename header('Content-Type: application/pdf'); header('Content-Disposition: inline; filename="' . $filename . '"'); readfile($filename); } protected function getLogAction() { $orderId = $this->request->orderId; if (empty($orderId)) { self::returnJson(['error' => 'Order ID is required']); return; } $logs = WarehouseLogModel::getAll(['table' => 'WarehouseOrder','rowId' => $orderId], ['timestamp' => 'DESC']); self::returnJson($logs); } protected function createNewLogAction() { $postData = json_decode(file_get_contents('php://input'), true); if (empty($postData['orderId']) || empty($postData['status'])) { self::returnJson(['error' => 'Order ID and Status are required']); return; } $log = [ "table" => "WarehouseOrder", "rowId" => intval($postData['orderId']), "type" => $postData['status'] === 'noChanges' ? 'noChanges' : 'statusChange', "fileIds" => $postData['fileIds'] ?? null, "message" => $postData['note'] ?? null, "createBy" => intval($this->user->id), "create" => time() ]; try { $order = WarehouseOrderModel::get($log['orderId']); if ($postData['status'] !== 'noChanges') { $oldStatusText = array_values(array_filter($this->columns, fn($c) => $c['key'] === 'status'))[0]['modal']['items'][array_search($order->status, array_column(array_values(array_filter($this->columns, fn($c) => $c['key'] === 'status'))[0]['modal']['items'], 'value'))]['text']; $newStatusText = array_values(array_filter($this->columns, fn($c) => $c['key'] === 'status'))[0]['modal']['items'][array_search($postData['status'], array_column(array_values(array_filter($this->columns, fn($c) => $c['key'] === 'status'))[0]['modal']['items'], 'value'))]['text']; $log['message'] = 'Status wurde geändert von ' . $oldStatusText . ' auf ' . $newStatusText . ($log['message'] ? ': ' . $log['message'] : ''); $order->status = $postData['status']; $order = (array) $order; WarehouseOrderModel::update($order); } WarehouseLogModel::create($log); self::returnJson(['success' => 'Log entry created']); } catch (Exception $e) { self::returnJson(['error' => 'Error creating log entry']); } } protected function uploadFileAction() { if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) { self::returnJson(['error' => 'No file uploaded or upload error occurred']); return; } $_FILES = ['WarehouseOrder' => $_FILES['file']]; try { $file = mfUpload::handleFormUpload("WarehouseOrder", false, "/WarehouseOrder"); // Return the file ID self::returnJson(['success' => true, 'fileId' => $file->id]); } catch (Exception $ex) { self::returnJson(['error' => 'Error uploading file: ' . $ex->getMessage()]); } } protected function getLogByIdAction() { $orderId = $this->request->id; if (empty($orderId)) { self::returnJson(['error' => 'Order ID is required']); return; } $log = WarehouseLogModel::getAll(['table' => 'WarehouseOrder', 'rowId' => $orderId]); self::returnJson($log); } protected function afterUpdate($postData) { $this->updateOrderRequestLinkedOrderIds($postData['id']); } protected function afterCreate($postData) { $this->updateOrderRequestLinkedOrderIds($postData['id']); } protected function updateOrderRequestLinkedOrderIds($id) { $order = (array) WarehouseOrderModel::get($id); foreach (json_decode($order['positions'], true) as $position) { if (!empty($position['linkedOrderRequestId'])) { $warehouseOrderRequest = (array) WarehouseOrderRequestModel::get($position['linkedOrderRequestId']); if (is_null($warehouseOrderRequest['linkedOrderIds'])) { $warehouseOrderRequest['linkedOrderIds'] = [$id]; WarehouseOrderRequestModel::update($warehouseOrderRequest); } else { if (!in_array($id, $warehouseOrderRequest['linkedOrderIds'])) { $warehouseOrderRequest['linkedOrderIds'][] = $id; WarehouseOrderRequestModel::update($warehouseOrderRequest); } } } } } }