'name', 'text' => 'Name', 'required' => true,], ['key' => 'description', 'text' => 'Beschreibung', 'required' => true], ['key' => 'articleNumberPrefix', 'text' => 'Artikelnummerprefix', 'required' => false, 'modal' => ['disabled' => true, 'placeholder' => 'Wird automatisch generiert']], ['key' => 'create', 'text' => 'Erstellt am', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']], ['key' => 'create_by', 'text' => 'Erstellt von', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']], ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center', 'priority' => 10]], ]; // @formatter:on protected array $additionalActions = [ ['key' => 'printLabels', 'title' => 'Labels drucken', 'class' => 'fas fa-print text-primary'], ['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'] ]; protected array $additionalJSVariables = ['WAREHOUSE_ADMIN' => true]; public function printLabelsAction() { $categoryId = intval($this->request->id); $articles = WarehouseArticleModel::getAll(['category_id' => $categoryId], 10000, 0, ['key' => 'articleNumber', 'order' => 'ASC']); if (empty($articles)) { echo "Keine Artikel in dieser Kategorie."; die(); } $pdf_vars = [ 'articles' => $articles ]; $pdf = new PdfForm("WarehouseArticle/LABEL_BULK", $pdf_vars); $wkhtmltopdfArgs = "--page-height 25mm --page-width 63mm --margin-top 0 --margin-bottom 0 --margin-left 0 --margin-right 0 --disable-smart-shrinking --encoding utf-8 --dpi 96"; $filename = $pdf->render($wkhtmltopdfArgs); $category = WarehouseCategory::get($categoryId); $categoryName = $category ? $category->name : 'category-' . $categoryId; header('Content-Type: application/pdf'); header('Content-Disposition: inline; filename="labels-' . str_replace(' ', '_', $categoryName) . '.pdf"'); readfile($filename); die(); } protected function beforeCreate(): bool { $this->postData['articleNumberPrefix'] = $this->getNextFreePrefix(); return true; } protected function beforeUpdate($postData): bool { // Preserve existing prefix - don't allow changes $existing = WarehouseCategory::get($postData['id']); if ($existing) { $this->postData['articleNumberPrefix'] = $existing->articleNumberPrefix; } (new WarehouseHistoryController)->create($postData, $this->mod); return true; } private function getNextFreePrefix(): string { $db = FronkDB::singleton(); $result = $db->query("SELECT articleNumberPrefix FROM WarehouseCategory WHERE articleNumberPrefix IS NOT NULL ORDER BY CAST(articleNumberPrefix AS UNSIGNED) DESC LIMIT 1"); $row = $db->fetch_array($result); if ($row && $row['articleNumberPrefix']) { $lastPrefix = intval($row['articleNumberPrefix']); // Skip special ranges (9900+) if ($lastPrefix >= 9900) { // Find highest non-special prefix $result = $db->query("SELECT articleNumberPrefix FROM WarehouseCategory WHERE articleNumberPrefix IS NOT NULL AND CAST(articleNumberPrefix AS UNSIGNED) < 9900 ORDER BY CAST(articleNumberPrefix AS UNSIGNED) DESC LIMIT 1"); $row = $db->fetch_array($result); $lastPrefix = $row ? intval($row['articleNumberPrefix']) : 1800; } $nextPrefix = $lastPrefix + 100; // Skip 9900+ range if ($nextPrefix >= 9900) $nextPrefix = 9900; } else { $nextPrefix = 1900; } return str_pad($nextPrefix, 4, '0', STR_PAD_LEFT); } protected function getHistoryAction() { self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns)); } protected function beforeDelete($postData): bool { if (count(WarehouseArticleModel::getAll(['category_id' => $postData['id']])) === 0) return true; http_response_code(500); self::returnJson(['status' => 'error', 'message' => 'Die Kategorie kann nicht gelöscht werden, da sie in mindestens einem Artikel verwendet wird.']); return false; } }