'title', 'text' => 'Titel', 'required' => true, 'table' => ['priority' => 9]], ['key' => 'articleNumber', 'text' => 'Nr.', 'required' => true], ['key' => 'description', 'text' => 'Beschreibung', 'required' => true,'modal' => ['type' => 'textarea'], 'table' => ['sortable' => false]], ['key' => 'category_id', 'text' => 'Kategorie', 'required' => true, 'modal' => ['type' => 'select', 'items' => []], 'table' => ['filter' => 'select']], ['key' => 'unit', 'text' => 'Einheit', 'required' => true,'table' => false], ['key' => 'revenueAccount', 'text' => 'Erlöskonto', 'required' => true,'modal' => ['type' => 'select', 'items' => [['value' => 0, 'text' => 'Dienstleistungen'], ['value' => 1, 'text' => 'Handelswaren']]], 'table' => false], ['key' => 'cheapestPurchasePrice', 'text' => 'Einkauf', 'modal' => false, 'table' => ['class' => 'text-center', 'suffix' => ' €']], ['key' => 'cheapestSellPrice', 'text' => 'Verkauf', 'modal' => false, 'table' => ['class' => 'text-center', 'suffix' => ' €']], ['key' => 'warningAmount', 'text' => 'Warnmenge', 'required' => true,'modal' => ['type' => 'number'], 'table' => false], ['key' => 'criticalAmount', 'text' => 'Kritische Menge', 'required' => true,'modal' => ['type' => 'number'], 'table' => false], ['key' => 'isSerialDocumentation', 'text' => 'Seriennummern', 'required' => false,'modal' => ['type' => 'checkbox'], 'table' => false], ['key' => 'isEndOfLife', 'text' => 'End of Life', 'required' => false,'modal' => ['type' => 'checkbox', 'items' => [ ['value' => 0, 'text' => 'Nicht End of Life', 'icon' => 'fa-regular fa-circle-check text-success'], ['value' => 1, 'text' => 'End of Life', 'icon' => 'fa-regular fa-circle-xmark text-danger']]], 'table' => ['filter' => 'iconSelect']], ['key' => 'isEShop', 'text' => 'Ist E-Shop', 'required' => false,'modal' => ['type' => 'checkbox'], 'table' => false], ['key' => 'isEShopHide', 'text' => 'E-Shop Versteckt', 'required' => false,'modal' => ['type' => 'checkbox'], 'table' => false], ['key' => 'isSbidiShop', 'text' => 'Ist SBIDI-Shop', 'required' => false,'modal' => ['type' => 'checkbox'], 'table' => false], ['key' => 'isSbidiShopHide', 'text' => 'SBIDI-Shop Versteckt', 'required' => false,'modal' => ['type' => 'checkbox'], 'table' => false], ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center', 'priority' => 8]] ]; protected array $autocompleteColumns = ['articleNumber', 'title', 'description']; protected array $permissionCheck = ['WarehouseUser']; protected array $additionalActions = [['key' => 'openHistory','title' => 'Historie','class' => 'fas fa-history text-secondary']]; // @formatter:on protected array $additionalJSVariables = ['WAREHOUSE_ADMIN' => true]; protected function prepareCrudConfig() { $categories = array_map(fn($category) => ['value' => $category->id, 'text' => $category->name], WarehouseCategory::getAll()); $this->columns[array_search('category_id', array_column($this->columns, 'key'))]['modal']['items'] = $categories; if ($this->user->can('WarehouseAdmin')) return; array_walk($this->columns, fn(&$col) => in_array($col['key'], ['actions', 'cheapestPurchasePrice', 'warningAmount', 'criticalAmount']) && $col['table'] = false); $this->createText = false; $this->additionalJSVariables['WAREHOUSE_ADMIN'] = false; } protected function beforeCreate() { if (!in_array($this->user->id, [2, 5, 6, 145])) self::sendError("Sie haben keine Berechtigung, Artikel zu erstellen."); return true; } protected function beforeUpdate($postData): bool { if (!in_array($this->user->id, [2, 5, 6, 145])) self::sendError("Sie haben keine Berechtigung, Artikel zu bearbeiten."); (new WarehouseHistoryController)->create($postData, $this->mod); return true; } protected function afterUpdate($postData) { self::updateCheapestPurchasePrice($postData['id']); } public static function updateCheapestPurchasePrice(int $id): void { $article = WarehouseArticleModel::get($id); if (!$article instanceof WarehouseArticleModel) throw new Exception("Invalid article type"); $distributor = WarehouseArticleDistributorModel::getAll(['articleId' => $id], 1, 0, ['key' => 'purchasePrice', 'order' => 'ASC']); if (count($distributor) == 0) WarehouseArticleModel::update(array_merge(get_object_vars($article), ['cheapestPurchasePrice' => null])); else if ($article->cheapestPurchasePrice != $distributor[0]->purchasePrice) WarehouseArticleModel::update(array_merge(get_object_vars($article), ['cheapestPurchasePrice' => $distributor[0]->purchasePrice])); } protected function afterCreate($postData) { self::updateCheapestPurchasePrice($postData['id']); self::updateSellPrices($postData['id']); } public static function updateSellPrices(int $id): void { // Added return type hint $a = WarehouseArticleModel::get($id); if (!$a instanceof WarehouseArticleModel) throw new Exception("Invalid article type"); $aptsById = array_column(WarehouseArticlePriceModel::getAll(['articleId' => $id]), null, 'articlePriceTypeId'); $prices = []; $cpp = $a->cheapestPurchasePrice; foreach (WarehouseArticlePriceTypeModel::getAll() as $pt) { $apt = $aptsById[$pt->id] ?? null; $p = $apt ? ($apt->priceOverride ?? $apt->priceMultiplier * $cpp) : ($pt->defaultPriceFactor * $cpp); $prices[] = ['title' => $pt->title, 'price' => round($p, 2)]; // Add title and rounded price } usort($prices, function($x, $y) { $priorityX = 4; $titleX = isset($x['title']) ? $x['title'] : null; switch ($titleX) { case 'Verkauf': $priorityX = 1; break; case 'Partner': $priorityX = 2; break; case 'Energie Steiermark': $priorityX = 3; break; } $priorityY = 4; $titleY = isset($y['title']) ? $y['title'] : null; switch ($titleY) { case 'Verkauf': $priorityY = 1; break; case 'Partner': $priorityY = 2; break; case 'Energie Steiermark': $priorityY = 3; break; } return $priorityX <=> $priorityY; }); $a->cheapestSellPrice = json_encode($prices); WarehouseArticleModel::update(get_object_vars($a)); } public function updatePricesAction() { foreach (WarehouseArticleModel::getAll() as $article) { self::updateCheapestPurchasePrice($article->id); self::updateSellPrices($article->id); } self::returnJson(['success' => true, 'message' => 'Preise wurden aktualisiert']); } protected function getHistoryAction() { self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns)); } protected function autocompleteAction() { $textKey = property_exists($this->model, 'name') ? 'name' : 'title'; if (strlen($this->request->searchedID) > 0) { $filter = ['id' => $this->request->searchedID]; $data = $this->model::getAll($filter, 10); } else { if (isset($this->autocompleteColumns) && is_array($this->autocompleteColumns)) { $filterKey = join('|', $this->autocompleteColumns); } else { $filterKey = $textKey; } $data = []; if (count($data) < 11) { if (isset($_GET['hideEndOfLife'])) { $data = $this->model::getAll([$textKey => $this->request->q . '%', 'isEndOfLife' => 0], 10); $lazyData = $this->model::getAll([$filterKey => $this->request->q, 'isEndOfLife' => 0], 10); } else { $data = $this->model::getAll([$textKey => $this->request->q . '%'], 10); $lazyData = $this->model::getAll([$filterKey => $this->request->q], 10); } $data = array_merge($data, $lazyData); $data = array_unique($data, SORT_REGULAR); $data = array_slice($data, 0, 10); } } self::returnJson(array_map(function ($item) use ($textKey) { return ['value' => $item->id, 'text' => $item->$textKey]; }, $data)); } }