Feature/warehouse
This commit is contained in:
@@ -24,20 +24,7 @@ class VoiceCallHistoryController extends mfBaseController {
|
||||
}
|
||||
|
||||
protected function indexAction(): void {
|
||||
$JSGlobals = ["BASE_URL" => self::getUrl("Domain"),
|
||||
"DASHBOARD_URL" => self::getUrl("Dashboard"),
|
||||
"MFAPPNAME" => MFAPPNAME_SLUG,
|
||||
"PAGE_TITLE" => "Voice Call History",
|
||||
"PATH" => [
|
||||
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
|
||||
["text" => "Voice Call History", "href" => self::getUrl("VoiceCallHistory")]
|
||||
],
|
||||
"VOICE_CALL_HISTORY_API_URL" => self::getUrl("VoiceCallHistory/api"),
|
||||
];
|
||||
|
||||
$this->layout()->set("vueViewName", "VoiceCallHistory");
|
||||
$this->layout()->set("JSGlobals", $JSGlobals);
|
||||
$this->layout()->setTemplate("VueViews/Vue");
|
||||
Helper::renderVue($this, "Voice Call History", $this->mod, ["VOICE_CALL_HISTORY_API_URL" => $this->getUrl("VoiceCallHistory", "api")]);
|
||||
}
|
||||
|
||||
protected function apiAction() {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseArticle extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticleController extends TTCrud {
|
||||
protected string $headerTitle = 'Artikel';
|
||||
protected string $createText = 'Artikel erstellen';
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'title', 'text' => 'Titel', 'required' => true, 'table' => ['priority' => 9]],
|
||||
['key' => 'description', 'text' => 'Beschreibung', 'required' => true, 'table' => false],
|
||||
['key' => 'category', 'text' => 'Kategorie', 'required' => true],
|
||||
['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', 'modal' => ['type' => 'number'], 'table' => ['class' => 'text-center']], // Stock/inventory related
|
||||
['key' => 'criticalAmount', 'text' => 'Kritische Menge', 'modal' => ['type' => 'number'], 'table' => ['class' => 'text-center']], // Stock/inventory related
|
||||
['key' => 'isEShop', 'text' => 'Ist E-Shop', 'modal' => ['type' => 'checkbox'], 'table' => false], // Boolean value
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center', 'priority' => 8]]
|
||||
];
|
||||
|
||||
protected array $additionalActions = [
|
||||
['key' => 'openHistory','title' => 'Historie','class' => 'fas fa-history text-secondary'],
|
||||
['key' => 'editDistributorEntries','title' => 'Lieferanten','class' => 'fas fa-truck text-cyan'],
|
||||
['key' => 'editThresholdEntries','title' => 'Schwellenwerte','class' => 'far fa-fw fa-box-full text-orange'],
|
||||
['key' => 'editPricesEntries','title' => 'Preise','class' => 'fas fa-euro-sign text-green'],
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $infoMessages = ['create' => 'Artikel wurde erstellt',
|
||||
'update' => 'Artikel wurde aktualisiert',
|
||||
'delete' => 'Artikel wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',];
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function afterUpdate($postData) {
|
||||
self::updateCheapestPurchasePrice($postData['id']);
|
||||
}
|
||||
|
||||
public static function updateCheapestPurchasePrice($articleId) {
|
||||
$cheapestPurchasePrice = WarehouseArticleDistributorModel::getAll(['articleId' => $articleId], 1, 0,
|
||||
['key' => 'purchasePrice', 'order' => 'ASC'])[0]->purchasePrice;
|
||||
|
||||
$article = WarehouseArticleModel::get($articleId);
|
||||
|
||||
if (!$article instanceof WarehouseArticleModel) {
|
||||
throw new Exception("Article is not an instance of WarehouseArticleModel");
|
||||
}
|
||||
|
||||
//TODO: think of a new way as we have multiple sell prices now and article sellPriceOverride and sellPriceMultiplier do not exist anymore
|
||||
// $cheapestSellPrice = $article->sellPriceOverride ?? $article->sellPriceMultiplier * $cheapestPurchasePrice;
|
||||
|
||||
if ($article->cheapestPurchasePrice != $cheapestPurchasePrice) {
|
||||
WarehouseArticleModel::update([...get_object_vars($article), // Unpack properties into an array
|
||||
'cheapestPurchasePrice' => $cheapestPurchasePrice]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function afterCreate($postData) {
|
||||
self::updateCheapestPurchasePrice($postData['id']);
|
||||
}
|
||||
|
||||
protected function updateAllCheapestPurchasePricesAction() {
|
||||
$articles = WarehouseArticleModel::getAll();
|
||||
foreach ($articles as $article) {
|
||||
self::updateCheapestPurchasePrice($article->id);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns));
|
||||
}
|
||||
|
||||
protected function importAction() {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
// read import.json from directory of this file
|
||||
$json = fopen(dirname(__FILE__) . '/import.json', 'r') or die('Unable to open file!');
|
||||
|
||||
// read file content
|
||||
$data = fread($json, filesize(dirname(__FILE__) . '/import.json'));
|
||||
|
||||
// decode json
|
||||
$data = json_decode($data, true);
|
||||
|
||||
// close file
|
||||
fclose($json);
|
||||
|
||||
// die with data length
|
||||
// loop through data
|
||||
echo 'Importing ' . count($data) . ' items' . PHP_EOL;
|
||||
$count = 0;
|
||||
foreach ($data as $item) {
|
||||
// echo count + 1
|
||||
echo ++$count . PHP_EOL;
|
||||
// Check if Distributor exists
|
||||
$distributor = WarehouseDistributorModel::getAll(['name' => $item['Lieferant']]);
|
||||
if (empty($distributor)) {
|
||||
$distributorId = WarehouseDistributorModel::create(['name' => $item['Lieferant'],
|
||||
'address' => 'Missing',
|
||||
'plz' => 'Missing',
|
||||
'city' => 'Missing',
|
||||
'countryId' => 1,
|
||||
'email' => 'Missing',
|
||||
'phone' => 'Missing',
|
||||
'contactPerson' => 'Missing',]);
|
||||
} else {
|
||||
$distributorId = $distributor[0]->id;
|
||||
}
|
||||
|
||||
// only continue if PRODUKT 1.ZEILE and PRODUKT 2.ZEILE and ARTIKEL GRUPPE and VK and EK and Lieferant/ Hersteller Artikelnr: are set
|
||||
if (!isset($item['PRODUKT 1.ZEILE'])) {
|
||||
echo 'Missing data for ' . $item['PRODUKT 1.ZEILE'] . PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($item['VK'])) {
|
||||
$item['VK'] = 0;
|
||||
$calcSellPriceMultiplier = 0;
|
||||
} else {
|
||||
$item['VK'] = floatval(str_replace(',', '', $item['VK']));
|
||||
}
|
||||
|
||||
if (empty($item['EK'])) {
|
||||
$item['EK'] = 0;
|
||||
$calcSellPriceMultiplier = 0;
|
||||
$purchasePrice = 0;
|
||||
} else {
|
||||
$item['EK'] = floatval(str_replace(',', '', $item['EK']));
|
||||
}
|
||||
|
||||
if (!empty($item['VK']) && !empty($item['EK'])) {
|
||||
$calcSellPriceMultiplier = $item['VK'] / $item['EK'];
|
||||
|
||||
// if calcSellPriceMultiplier has more than 2 decimal places assign $calcSellPriceOverride
|
||||
echo strlen(substr(strrchr($calcSellPriceMultiplier, "."), 1)) . PHP_EOL;
|
||||
if (strlen(substr(strrchr($calcSellPriceMultiplier, "."), 1)) > 2) {
|
||||
$calcSellPriceOverride = $item['VK'];
|
||||
}
|
||||
|
||||
$purchasePrice = str_replace(',', '', $item['EK']);
|
||||
}
|
||||
|
||||
if (!isset($calcSellPriceMultiplier) && !isset($calcSellPriceOverride) || !isset($purchasePrice)) {
|
||||
echo 'Missing data for ' . $item['PRODUKT 1.ZEILE'] . PHP_EOL;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if Article exists
|
||||
$article = WarehouseArticleModel::getAll(['title' => ['exact' => $item['PRODUKT 1.ZEILE']]]);
|
||||
if (empty($article)) {
|
||||
$articleCreateData = ['title' => $item['PRODUKT 1.ZEILE'],
|
||||
'description' => $item['PRODUKT 2. ZEILE'],
|
||||
'category' => $item['ARTIKEL GRUPPE'],
|
||||
'cheapestPurchasePrice' => 0,
|
||||
'warningAmount' => 25,
|
||||
'criticalAmount' => 10,
|
||||
'isEShop' => 0,];
|
||||
|
||||
// if calcSellPriceOverride is set, add it to the $articleCreateData array
|
||||
if (isset($calcSellPriceOverride)) {
|
||||
$articleCreateData['sellPriceOverride'] = $calcSellPriceOverride;
|
||||
} else if (isset($calcSellPriceMultiplier)) {
|
||||
$articleCreateData['sellPriceMultiplier'] = $calcSellPriceMultiplier;
|
||||
}
|
||||
|
||||
$articleId = WarehouseArticleModel::create($articleCreateData);
|
||||
} else {
|
||||
echo 'Article already exists with title ' . $item['PRODUKT 1.ZEILE'] . PHP_EOL;
|
||||
$articleId = $article[0]->id;
|
||||
}
|
||||
|
||||
// Check if ArticleDistributor exists
|
||||
$articleDistributor = WarehouseArticleDistributorModel::getAll(['articleId' => $articleId,
|
||||
'distributorId' => $distributorId]);
|
||||
if (empty($articleDistributor)) {
|
||||
WarehouseArticleDistributorModel::create(['articleId' => $articleId,
|
||||
'distributorId' => $distributorId,
|
||||
'purchasePrice' => $purchasePrice,
|
||||
'externalArticleNumber' => $item['Lieferant/ Hersteller Artikelnr:'],]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticleModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public string $title;
|
||||
public string $description;
|
||||
public string $category;
|
||||
public ?float $cheapestPurchasePrice;
|
||||
public ?float $cheapestSellPrice;
|
||||
public int $warningAmount;
|
||||
public int $criticalAmount;
|
||||
public int $isEShop;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseArticleDistributor extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticleDistributorController extends TTCrud {
|
||||
protected string $headerTitle = 'Lieferanteintrag';
|
||||
protected string $createText = 'Lieferanteintrag erstellen';
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'purchasePrice', 'text' => 'Einkaufspreis', 'required' => true, 'modal' => ['type' => 'number']],
|
||||
['key' => 'articleId', 'text' => 'Artikel', 'required' => true, 'modal' => ['type' => 'select', 'data' => 'WarehouseArticle']],
|
||||
['key' => 'distributorId', 'text' => 'Lieferant', 'required' => true, 'modal' => ['type' => 'select', 'data' => 'WarehouseDistributor']],
|
||||
['key' => 'externalArticleNumber', 'text' => 'Externe Artikelnummer', 'required' => true],
|
||||
['key' => 'note', 'text' => 'Notiz', 'required' => false, 'modal' => ['type' => 'textarea']],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']]
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $infoMessages = ['create' => 'Lieferanteintrag wurde erstellt',
|
||||
'update' => 'Lieferanteintrag wurde aktualisiert',
|
||||
'delete' => 'Lieferanteintrag wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',];
|
||||
|
||||
protected function checkExistingThresholdEntry($postData): bool {
|
||||
$count = WarehouseLocationThresholdOverrideModel::count(['articleId' => $postData['articleId'],
|
||||
'distributorId' => $postData['distributorId']]);
|
||||
|
||||
if ($count > 0) {
|
||||
self::returnJson(['success' => false,
|
||||
'message' => 'Es existiert bereits ein Eintrag mit dieser Artikelnummer und diesem Lieferanten.']);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function beforeCreate($postData): bool {
|
||||
return $this->checkExistingThresholdEntry($postData);
|
||||
}
|
||||
|
||||
protected function afterCreate($postData) {
|
||||
WarehouseArticleController::updateCheapestPurchasePrice($postData['articleId']);
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
$existing = $this->checkExistingThresholdEntry($postData);
|
||||
|
||||
if (!$existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function afterUpdate($postData) {
|
||||
WarehouseArticleController::updateCheapestPurchasePrice($postData['articleId']);
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
$history = WarehouseHistoryModel::getByRowId($this->request->id, $this->mod);
|
||||
|
||||
$history = array_map(function ($item) {
|
||||
$item = (array) $item;
|
||||
|
||||
$item['columnHeader'] = $this->columns[array_search($item['key'], array_column($this->columns, 'key'))]['text'];
|
||||
return $item;
|
||||
}, $history);
|
||||
|
||||
self::returnJson($history);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticleDistributorModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public int $articleId;
|
||||
public int $distributorId;
|
||||
public float $purchasePrice;
|
||||
public string $externalArticleNumber;
|
||||
public ?string $note;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseArticlePrice extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticlePriceController extends TTCrud {
|
||||
protected string $headerTitle = 'Artikel Verkaufspreise';
|
||||
protected string $createText = 'Artikel Verkaufspreis erstellen';
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'articleId', 'text' => 'Artikel', 'required' => true],
|
||||
['key' => 'articlePriceTypeId', 'text' => 'Preistyp', 'required' => true],
|
||||
['key' => 'priceMultiplier', 'text' => 'Preismultiplikator', 'required' => false],
|
||||
['key' => 'priceOverride', 'text' => 'Preisüberschreibung', 'required' => false]
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $infoMessages = ['create' => 'Artikel Verkaufspreis wurde erstellt',
|
||||
'update' => 'Artikel Verkaufspreis wurde aktualisiert',
|
||||
'delete' => 'Artikel Verkaufspreis wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen'];
|
||||
|
||||
protected function beforeCreate($postData): bool {
|
||||
return $this->validate($postData);
|
||||
}
|
||||
|
||||
protected function validate($postData): bool {
|
||||
// check if postData priceOverride or priceMultiplier is set but only one of them
|
||||
if (isset($postData['priceOverride']) && isset($postData['priceMultiplier'])) {
|
||||
self::returnJson(['success' => false,
|
||||
'message' => 'Entweder Preismultiplikator oder Preisüberschreibung kann gesetzt werden.']);
|
||||
return false;
|
||||
} else if (!isset($postData['priceOverride']) && !isset($postData['priceMultiplier'])) {
|
||||
self::returnJson(['success' => false,
|
||||
'message' => 'Entweder Preismultiplikator oder Preisüberschreibung muss gesetzt werden.']);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (isset($postData['id'])) {
|
||||
$count = WarehouseArticlePriceModel::count(['articleId' => $postData['articleId'],
|
||||
'articlePriceTypeId' => $postData['articlePriceTypeId'],
|
||||
'id' => $postData['id']]);
|
||||
if ($count > 0) return true;
|
||||
} else {
|
||||
$count = WarehouseArticlePriceModel::count(['articleId' => $postData['articleId'],
|
||||
'articlePriceTypeId' => $postData['articlePriceTypeId']]);
|
||||
if ($count > 0) {
|
||||
self::returnJson(['success' => false,
|
||||
'message' => 'Es existiert bereits ein Preis für diesen Artikel und diesen Preistyp.']);
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
$existing = $this->validate($postData);
|
||||
|
||||
if (!$existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
$history = WarehouseHistoryModel::getByRowId($this->request->id, 'WarehouseArticleDistributor');
|
||||
|
||||
$history = array_map(function ($item) {
|
||||
$item = (array) $item;
|
||||
|
||||
$item['columnHeader'] = $this->columns[array_search($item['key'], array_column($this->columns, 'key'))]['text'];
|
||||
return $item;
|
||||
}, $history);
|
||||
|
||||
self::returnJson($history);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticlePriceModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public int $articleId;
|
||||
public int $articlePriceTypeId;
|
||||
public ?float $priceMultiplier;
|
||||
public ?float $priceOverride;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseArticlePriceType extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticlePriceTypeController extends TTCrud {
|
||||
protected string $headerTitle = 'Artikel Verkaufspreise';
|
||||
protected string $createText = 'Artikel Verkaufspreis erstellen';
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'title', 'text' => 'Titel', 'required' => true],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center', 'priority' => 10]],
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $infoMessages = ['create' => 'Artikel Verkaufspreis wurde erstellt',
|
||||
'update' => 'Artikel Verkaufspreis wurde aktualisiert',
|
||||
'delete' => 'Artikel Verkaufspreis wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen'];
|
||||
|
||||
protected function checkExistingDistributorEntry($postData): bool {
|
||||
// if postData id exists check if there is already an entry with the same articleId and locationId if postdata id and WarehouseLocationThresholdOverrideModel id are different return false
|
||||
if (isset($postData['id'])) {
|
||||
$count = WarehouseArticlePriceTypeModel::count(['title' => $postData['title'], 'id' => $postData['id']]);
|
||||
if ($count > 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$count = WarehouseArticlePriceTypeModel::count(['title' => $postData['title']]);
|
||||
if ($count > 0) {
|
||||
self::returnJson(['success' => false,
|
||||
'message' => 'Es existiert bereits ein Preis Typ mit diesem Titel.']);
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function beforeCreate($postData): bool {
|
||||
return $this->checkExistingDistributorEntry($postData);
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
$existing = $this->checkExistingDistributorEntry($postData);
|
||||
|
||||
if (!$existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
$history = WarehouseHistoryModel::getByRowId($this->request->id, $this->mod);
|
||||
|
||||
$history = array_map(function ($item) {
|
||||
$item = (array) $item;
|
||||
|
||||
$item['columnHeader'] = $this->columns[array_search($item['key'], array_column($this->columns, 'key'))]['text'];
|
||||
return $item;
|
||||
}, $history);
|
||||
|
||||
self::returnJson($history);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
class WarehouseArticlePriceTypeModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public string $title;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseDistributor extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
class WarehouseDistributorController extends TTCrud {
|
||||
protected string $headerTitle = 'Lieferant';
|
||||
protected string $createText = 'Lieferant erstellen';
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'name', 'text' => 'Name', 'required' => true, 'table' => ['priority' => 11]],
|
||||
['key' => 'address', 'text' => 'Adresse', 'required' => true],
|
||||
['key' => 'plz', 'text' => 'PLZ', 'required' => true],
|
||||
['key' => 'city', 'text' => 'Stadt', 'required' => true],
|
||||
['key' => 'countryId', 'text' => 'Land', 'required' => true, 'modal' => ['type' => 'select', 'items' => []]],
|
||||
['key' => 'email', 'text' => 'E-Mail', 'required' => true],
|
||||
['key' => 'phone', 'text' => 'Telefon', 'required' => true],
|
||||
['key' => 'contactPerson', 'text' => 'Kontaktperson', 'required' => true],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center', 'priority' => 10]],
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $additionalActions = [['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary']];
|
||||
|
||||
protected array $infoMessages = ['create' => 'Lieferant wurde erstellt',
|
||||
'update' => 'Lieferant wurde aktualisiert',
|
||||
'delete' => 'Lieferant wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',];
|
||||
|
||||
public function prepareCrudConfig() {
|
||||
$countries = array_map(function ($country) {
|
||||
return ['value' => $country->id, 'text' => $country->name];
|
||||
}, CountryModel::getAll());
|
||||
|
||||
$this->columns[4]['modal']['items'] = $countries;
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
class WarehouseDistributorModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public string $name;
|
||||
public string $address;
|
||||
public string $plz;
|
||||
public string $city;
|
||||
public int $countryId;
|
||||
public string $email;
|
||||
public string $phone;
|
||||
public string $contactPerson;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseEShop extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
class WarehouseEShopController extends TTCrud {
|
||||
protected string $headerTitle = 'Energie Steiermark Shop';
|
||||
protected bool $createText = false;
|
||||
|
||||
protected array $columns = [
|
||||
['key' => 'title', 'text' => 'Titel'],
|
||||
['key' => 'category', 'text' => 'Kategorie'],
|
||||
['key' => 'amount', 'text' => 'Menge', 'table' => ['filter' => false,'sortable' => false,'class' => 'p-0 width-80']],
|
||||
['key' => 'add', 'text' => 'Hinzufügen', 'table' => ['filter' => false,'sortable' => false, 'class' => 'width-120 text-center']]
|
||||
];
|
||||
|
||||
protected array $infoMessages = [
|
||||
'create' => 'Not possible',
|
||||
'update' => 'Not possible',
|
||||
'delete' => 'Not possible',
|
||||
'noChanges' => 'Keine Änderungen',
|
||||
];
|
||||
|
||||
public function getAction() {
|
||||
$filter = $this->postData['filters'] ?? [];
|
||||
$order = $this->postData['order'] ?? ['key' => null, 'order' => 'ASC'];
|
||||
$page = $this->postData['pagination']['page'] ?? 1;
|
||||
$perPage = $this->postData['pagination']['per_page'] ?? 10;
|
||||
|
||||
$filter['isEShop'] = 1;
|
||||
|
||||
$rows = WarehouseArticleModel::getAll($filter, $perPage, ($page - 1) * $perPage, $order);
|
||||
$filteredAvailable = WarehouseArticleModel::count($filter);
|
||||
$totalRows = WarehouseArticleModel::count(['isEShop' => 1]);
|
||||
|
||||
self::returnJson(["rows" => $rows,
|
||||
"pagination" => ["page" => $page,
|
||||
"total_pages" => ceil($filteredAvailable / $perPage),
|
||||
"per_page" => $perPage,
|
||||
"filtered_available" => intval($filteredAvailable),
|
||||
"total_rows" => intval($totalRows)]]); }
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
class WarehouseEShopModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public string $title;
|
||||
public int $assignedTo;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseEShopOrder extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
class WarehouseEShopOrderController extends TTCrud {
|
||||
protected string $headerTitle = 'Energie Steiermark Bestellungen';
|
||||
protected bool $createText = false;
|
||||
|
||||
protected array $columns = [
|
||||
['key' => 'id', 'text' => 'ID', 'modal' => false],
|
||||
['key' => 'status', 'text' => 'Status', 'required' => true],
|
||||
['key' => 'deliveryMode', 'text' => 'Liefermodus', 'required' => true, 'modal' => ['type' => 'select', 'items' => [
|
||||
['value' => 'singleAddress', 'text' => 'Einzelne Adresse'],
|
||||
['value' => 'multipleAddresses', 'text' => 'Mehrere Adressen'],
|
||||
]]],
|
||||
['key' => 'deliveryAddressName', 'text' => 'Lieferadresse Name', 'required' => true, 'table' => false],
|
||||
['key' => 'deliveryAddressLine', 'text' => 'Lieferadresse', 'required' => true, 'required_length' => 4],
|
||||
['key' => 'deliveryAddressPLZ', 'text' => 'Lieferadresse PLZ', 'required' => true, 'regex' => '/^\d{4}$/', 'table' => false],
|
||||
['key' => 'deliveryAddressCity', 'text' => 'Lieferadresse Stadt', 'required' => true, 'required_length' => 3, 'table' => false],
|
||||
['key' => 'create', 'text' => 'Erstellt', 'required' => true, 'modal' => false, 'filter' => 'datetime'],
|
||||
['key' => 'createBy', 'text' => 'Erstellt von', 'required' => true,'modal' => ['type' => 'select', 'items' => []]],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],
|
||||
];
|
||||
|
||||
protected array $additionalActions = [
|
||||
['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'],
|
||||
];
|
||||
|
||||
protected array $infoMessages = [
|
||||
'create' => 'Bestellung wurde erfolgreich erstellt, sie erhalten in Kürze eine Bestätigungsmail',
|
||||
'update' => 'Lagerort wurde aktualisiert',
|
||||
'delete' => 'Lagerort wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',
|
||||
];
|
||||
|
||||
protected function prepareCrudConfig() {
|
||||
$users = array_map(function($user) {
|
||||
return ['value' => intval($user->id), 'text' => $user->name];
|
||||
}, UserModel::search(['employee' => true]));
|
||||
|
||||
$this->columns[8]['modal']['items'] = $users;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected function createOrderAction() {
|
||||
//TODO: change this to beforeCreate and afterCreate
|
||||
$json = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
$shoppingCart = $json['shoppingCart'];
|
||||
unset($json['shoppingCart']);
|
||||
|
||||
$json['status'] = 'new';
|
||||
$json['create'] = time();
|
||||
$json['createBy'] = $this->user->id;
|
||||
|
||||
Helper::validateArray($json, $this->getCheckArray());
|
||||
|
||||
$id = WarehouseEShopOrderModel::create([
|
||||
'status' => 'new',
|
||||
'deliveryMode' => $json['deliveryMode'],
|
||||
'deliveryAddressName' => $json['deliveryAddressName'],
|
||||
'deliveryAddressLine' => $json['deliveryAddressLine'],
|
||||
'deliveryAddressPLZ' => $json['deliveryAddressPLZ'],
|
||||
'deliveryAddressCity' => $json['deliveryAddressCity'],
|
||||
'create' => $json['create'],
|
||||
'createBy' => $json['createBy'],
|
||||
]);
|
||||
|
||||
// now create WarehouseEShopOrderItems for each item in the shopping cart
|
||||
foreach ($shoppingCart as $item) {
|
||||
WarehouseEShopOrderItemModel::create([
|
||||
'orderId' => $id,
|
||||
'articleId' => $item['itemId'],
|
||||
'quantity' => intval($item['amount']),
|
||||
]);
|
||||
}
|
||||
|
||||
self::returnJson(['success' => true,
|
||||
'message' => $this->infoMessages['create'],
|
||||
'id' => $id]);
|
||||
|
||||
$json['id'] = $id;
|
||||
die(json_encode($json));
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* @property int $id
|
||||
* @property 'new'|'accepted'|'sent'|'done' $status
|
||||
* @property 'singleAddress'|'multipleAddresses' $deliveryMode
|
||||
* @property string $deliveryAddressName
|
||||
* @property string $deliveryAddressLine
|
||||
* @property string $deliveryAddressPLZ
|
||||
* @property string $deliveryAddressCity
|
||||
* @property int $create
|
||||
* @property int $createBy
|
||||
*/
|
||||
|
||||
class WarehouseEShopOrderModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public string $status;
|
||||
public string $deliveryMode;
|
||||
public string $deliveryAddressName;
|
||||
public string $deliveryAddressLine;
|
||||
public string $deliveryAddressPLZ;
|
||||
public string $deliveryAddressCity;
|
||||
public int $create;
|
||||
public int $createBy;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseEShopOrderItem extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $orderId
|
||||
* @property int $articleId
|
||||
* @property int $quantity
|
||||
*/
|
||||
|
||||
class WarehouseEShopOrderItemModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public int $orderId;
|
||||
public int $articleId;
|
||||
public int $quantity;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseHistory extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
class WarehouseHistoryController {
|
||||
|
||||
public function create($postData, $mod) {
|
||||
$modelClass = $mod . 'Model';
|
||||
$modelClass = new $modelClass();
|
||||
$currentData = $modelClass::get($postData['id']);
|
||||
$me = new User();
|
||||
$me->loadMe();
|
||||
|
||||
foreach (array_diff_assoc($postData, (array) $currentData) as $key => $value) {
|
||||
WarehouseHistoryModel::create(['table' => $mod,
|
||||
'row_id' => $postData['id'],
|
||||
'key' => $key,
|
||||
'old_value' => $currentData->$key,
|
||||
'new_value' => $value,
|
||||
'note' => '',
|
||||
'user_id' => $me->id,
|
||||
'create' => date('U')]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getHistory($id, string $mod, $columns): array {
|
||||
$history = WarehouseHistoryModel::getByRowId($id, $mod);
|
||||
|
||||
return array_map(function ($item) use ($columns) {
|
||||
$item = (array) $item;
|
||||
|
||||
if (isset($this->columns[array_search($item['key'], array_column($columns, 'key'))]['modal']['type'])) {
|
||||
|
||||
if($this->columns[array_search($item['key'], array_column($columns, 'key'))]['modal']['type'] === 'checkbox') {
|
||||
$item['old_value'] = $item['old_value'] === '1' ? 'Ja' : 'Nein';
|
||||
$item['new_value'] = $item['new_value'] === '1' ? 'Ja' : 'Nein';
|
||||
}
|
||||
|
||||
if($this->columns[array_search($item['key'], array_column($columns, 'key'))]['modal']['type'] === 'select') {
|
||||
$column = $this->columns[array_search($item['key'], array_column($columns, 'key'))];
|
||||
$item['old_value'] = $column['modal']['items'][array_search($item['old_value'], array_column($column['modal']['items'], 'value'))]['text'];
|
||||
$item['new_value'] = $column['modal']['items'][array_search($item['new_value'], array_column($column['modal']['items'], 'value'))]['text'];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
$item['columnHeader'] = $columns[array_search($item['key'], array_column($columns, 'key'))]['text'];
|
||||
return $item;
|
||||
}, $history);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
//TODO: maybe convert this to use with TTCrudBaseModel
|
||||
class WarehouseHistoryModel {
|
||||
public int $id;
|
||||
public string $table;
|
||||
public int $row_id;
|
||||
public string $key;
|
||||
public string $old_value;
|
||||
public string $new_value;
|
||||
public string $note;
|
||||
public int $user_id;
|
||||
public string $user_name;
|
||||
public int $create;
|
||||
|
||||
public function __construct($data = []) {
|
||||
foreach ($data as $field => $value) {
|
||||
if (property_exists(get_called_class(), $field)) {
|
||||
$this->$field = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function create($data) {
|
||||
$FronkDB = FronkDB::singleton();
|
||||
$db = $FronkDB->link;
|
||||
$sql = /** @lang text */ "INSERT INTO `WarehouseHistory` (`table`, `row_id`, `key`, `old_value`, `new_value`, `note`, `user_id`, `create`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute([
|
||||
$data["table"],
|
||||
$data["row_id"],
|
||||
$data["key"],
|
||||
$data["old_value"],
|
||||
$data["new_value"],
|
||||
$data["note"],
|
||||
$data["user_id"],
|
||||
$data["create"]
|
||||
]);
|
||||
|
||||
return $stmt->insert_id;
|
||||
}
|
||||
/**
|
||||
* Retrieves an array of WarehouseHistoryModel objects by row ID.
|
||||
*
|
||||
* @param int $id The row ID.
|
||||
* @param string $table The table name.
|
||||
* @return WarehouseHistoryModel[] Array of WarehouseHistoryModel objects.
|
||||
*/
|
||||
public static function getByRowId(int $id, string $table): array {
|
||||
$db = FronkDB::singleton();
|
||||
$id = $db->escape($id);
|
||||
$sql = /** @lang text */ "SELECT WH.*, W.name as user_name FROM `WarehouseHistory` WH
|
||||
LEFT JOIN `Worker` W ON WH.user_id = W.id
|
||||
WHERE `row_id` = $id AND `table` = '$table' ORDER BY `create` DESC";
|
||||
$result = $db->query($sql);
|
||||
|
||||
$rows = [];
|
||||
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$rows[] = new WarehouseHistoryModel($row);
|
||||
}
|
||||
|
||||
return $rows;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseItem extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
class WarehouseItemController extends TTCrud {
|
||||
protected string $headerTitle = 'Eintrag';
|
||||
protected string $createText = 'Eintrag erstellen';
|
||||
|
||||
// TODO: change articleId and warehouseLocationId to autocomplete
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'articleId', 'text' => 'Artikel', 'required' => true, 'type' => 'select','table' => ['class' => 'text-nowrap'], 'modal' => ['items' => [], 'type' => 'select']],
|
||||
['key' => 'warehouseLocationId', 'text' => 'Lagerort', 'required' => true, 'type' => 'select', 'modal' => ['items' => [], 'type' => 'select']],
|
||||
['key' => 'quantity', 'text' => 'Menge', 'required' => true, 'type' => 'number'],
|
||||
['key' => 'serialNumber', 'text' => 'Seriennummer', 'required' => false],
|
||||
['key' => 'note', 'text' => 'Notiz', 'required' => false],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'table' => ['filter' => false], 'required' => false, 'modal' => false]
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $additionalActions = [
|
||||
['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'],
|
||||
];
|
||||
|
||||
protected array $infoMessages = [
|
||||
'create' => 'Eintrag wurde erstellt',
|
||||
'update' => 'Eintrag wurde aktualisiert',
|
||||
'delete' => 'Eintrag wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',
|
||||
'alreadyExists' => 'Eintrag existiert bereits an diesem Lagerort.'
|
||||
];
|
||||
|
||||
protected function checkExistingItemOnLocation($postData): bool {
|
||||
$count = WarehouseItemModel::count(['articleId' => $postData['articleId'],
|
||||
'warehouseLocationId' => $postData['warehouseLocationId'],
|
||||
'serialNumber' => null]);
|
||||
|
||||
if ($count > 0) {
|
||||
self::returnJson(['success' => false, 'message' => $this->infoMessages['alreadyExists']]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function beforeCreate($postData): bool {
|
||||
return $this->checkExistingItemOnLocation($postData);
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
$existing = $this->checkExistingItemOnLocation($postData);
|
||||
|
||||
if (!$existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function prepareCrudConfig() {
|
||||
$articles = array_map(function($article) {
|
||||
return ['value' => $article->id, 'text' => $article->title];
|
||||
}, WarehouseArticleModel::getAll());
|
||||
$this->columns[0]['modal']['items'] = $articles;
|
||||
|
||||
$locations = array_map(function($location) {
|
||||
return ['value' => $location->id, 'text' => $location->title];
|
||||
}, WarehouseLocationModel::getAll());
|
||||
$this->columns[1]['modal']['items'] = $locations;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
class WarehouseItemModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public int $articleId;
|
||||
public int $warehouseLocationId;
|
||||
public int $quantity;
|
||||
public ?string $serialNumber;
|
||||
public ?string $note;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseLocation extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
class WarehouseLocationController extends TTCrud {
|
||||
protected string $headerTitle = 'Lagerorte';
|
||||
protected string $createText = 'Lagerort erstellen';
|
||||
|
||||
protected array $columns = [
|
||||
['key' => 'title', 'text' => 'Titel', 'required' => true],
|
||||
['key' => 'assignedTo', 'text' => 'Zugewiesen an', 'required' => true, 'modal' => ['type' => 'select', 'items' => []]],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],
|
||||
];
|
||||
|
||||
protected array $additionalActions = [
|
||||
['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'],
|
||||
];
|
||||
|
||||
protected array $infoMessages = [
|
||||
'create' => 'Lagerort wurde erstellt',
|
||||
'update' => 'Lagerort wurde aktualisiert',
|
||||
'delete' => 'Lagerort wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',
|
||||
];
|
||||
|
||||
public function prepareCrudConfig() {
|
||||
$users = array_map(function($user) {
|
||||
return ['value' => $user->id, 'text' => $user->name];
|
||||
}, UserModel::search(['employee' => true]));
|
||||
|
||||
$this->columns[1]['modal']['items'] = $users;
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
$this->prepareCrudConfig();
|
||||
self::returnJson((new WarehouseHistoryController)->getHistory($this->request->id, $this->mod, $this->columns));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
class WarehouseLocationModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public string $title;
|
||||
public int $assignedTo;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseLocationThresholdOverride extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
class WarehouseLocationThresholdOverrideController extends TTCrud {
|
||||
protected string $headerTitle = 'Lagerort Schwellenwert überschreiben';
|
||||
protected string $createText = 'Lieferanteintrag erstellen';
|
||||
|
||||
// @formatter:off
|
||||
protected array $columns = [
|
||||
['key' => 'locationId', 'text' => 'Lagerort', 'required' => true, 'modal' => ['type' => 'select', 'data' => 'WarehouseLocation']],
|
||||
['key' => 'articleId', 'text' => 'Artikel', 'required' => true, 'modal' => ['type' => 'select', 'data' => 'WarehouseArticle']],
|
||||
['key' => 'warningAmount', 'text' => 'Warnmenge', 'required' => true, 'modal' => ['type' => 'number']],
|
||||
['key' => 'criticalAmount', 'text' => 'Kritische Menge', 'required' => true, 'modal' => ['type' => 'number']],
|
||||
['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']]
|
||||
];
|
||||
// @formatter:on
|
||||
|
||||
protected array $infoMessages = ['create' => 'Lagerort Schwellenwert wurde erstellt',
|
||||
'update' => 'Lagerort Schwellenwert wurde aktualisiert',
|
||||
'delete' => 'Lagerort Schwellenwert wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen'];
|
||||
|
||||
protected function checkExistingDistributorEntry($postData): bool {
|
||||
// if postData id exists check if there is already an entry with the same articleId and locationId if postdata id and WarehouseLocationThresholdOverrideModel id are different return false
|
||||
if (isset($postData['id'])) {
|
||||
$count = WarehouseLocationThresholdOverrideModel::count(['locationId' => $postData['locationId'],
|
||||
'articleId' => $postData['articleId'],
|
||||
'id' => $postData['id']]);
|
||||
if ($count > 0) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$count = WarehouseLocationThresholdOverrideModel::count(['locationId' => $postData['locationId'],
|
||||
'articleId' => $postData['articleId']]);
|
||||
if ($count > 0) {
|
||||
self::returnJson(['success' => false,
|
||||
'message' => 'Es existiert bereits ein Eintrag mit dieser Artikelnummer und diesem Lagerort.']);
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function beforeCreate($postData): bool {
|
||||
return $this->checkExistingDistributorEntry($postData);
|
||||
}
|
||||
|
||||
protected function beforeUpdate($postData): bool {
|
||||
$existing = $this->checkExistingDistributorEntry($postData);
|
||||
|
||||
if (!$existing) {
|
||||
return false;
|
||||
}
|
||||
|
||||
(new WarehouseHistoryController)->create($postData, $this->mod);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getHistoryAction() {
|
||||
$history = WarehouseHistoryModel::getByRowId($this->request->id, 'WarehouseArticleDistributor');
|
||||
|
||||
$history = array_map(function ($item) {
|
||||
$item = (array) $item;
|
||||
|
||||
$item['columnHeader'] = $this->columns[array_search($item['key'], array_column($this->columns, 'key'))]['text'];
|
||||
return $item;
|
||||
}, $history);
|
||||
|
||||
self::returnJson($history);
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class WarehouseLocationThresholdOverrideModel extends TTCrudBaseModel {
|
||||
public int $id;
|
||||
public int $locationId;
|
||||
public int $articleId;
|
||||
public int $warningAmount;
|
||||
public int $criticalAmount;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @property mixed|null $name
|
||||
*/
|
||||
class WarehouseOrderRecommendation extends mfBaseModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
class WarehouseOrderRecommendationController extends TTCrud {
|
||||
protected string $headerTitle = 'Lagerbestellvorschläge';
|
||||
protected bool $createText = false;
|
||||
protected bool $onlyView = true;
|
||||
|
||||
protected array $columns = [
|
||||
['key' => 'articleTitle', 'text' => 'Artikel', 'required' => true],
|
||||
['key' => 'locationTitle', 'text' => 'Lagerort', 'required' => true, 'table' => ['filter' => false, 'sortable' => false]],
|
||||
['key' => 'count', 'text' => 'Anzahl', 'required' => true, 'table' => ['filter' => false, 'sortable' => false]],
|
||||
['key' => 'status', 'text' => 'Status', 'required' => true, 'table' => ['filter' => false, 'sortable' => false]],
|
||||
['key' => 'recommendation', 'text' => 'Empfehlung', 'required' => true, 'table' => ['filter' => false, 'sortable' => false]],
|
||||
// ['key' => 'actions', 'text' => 'Aktionen', 'required' => false, 'modal' => false, 'table' => ['filter' => false, 'sortable' => false, 'class' => 'text-center']],
|
||||
];
|
||||
|
||||
protected array $additionalActions = [
|
||||
['key' => 'openHistory', 'title' => 'Historie', 'class' => 'fas fa-history text-primary'],
|
||||
];
|
||||
|
||||
protected array $infoMessages = [
|
||||
'create' => 'Lagerort wurde erstellt',
|
||||
'update' => 'Lagerort wurde aktualisiert',
|
||||
'delete' => 'Lagerort wurde gelöscht',
|
||||
'noChanges' => 'Keine Änderungen',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WarehouseOrderRecommendationModel
|
||||
*
|
||||
* This class represents a recommendation model for warehouse orders based on the critical and warning amounts of articles in the warehouse.
|
||||
*
|
||||
* @property int $articleId The ID of the article.
|
||||
* @property string $articleTitle The title of the article.
|
||||
* @property int $count The current count of items for the article.
|
||||
* @property string $status The status of the article's inventory ("Kritisch" or "Warnung").
|
||||
* @property string $recommendation The recommendation message for ordering.
|
||||
*/
|
||||
class WarehouseOrderRecommendationModel {
|
||||
public int $articleId;
|
||||
public ?int $locationId;
|
||||
public string $locationTitle;
|
||||
public string $articleTitle;
|
||||
public int $count;
|
||||
public string $status;
|
||||
public string $recommendation;
|
||||
|
||||
/**
|
||||
* WarehouseOrderRecommendationModel constructor.
|
||||
*
|
||||
* Initializes a new instance of the WarehouseOrderRecommendationModel class.
|
||||
*
|
||||
* @param array $data An associative array of property values to initialize the model.
|
||||
*/
|
||||
public function __construct(array $data = []) {
|
||||
foreach ($data as $field => $value) {
|
||||
if (property_exists(get_called_class(), $field)) {
|
||||
$this->$field = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves recommendations based on the provided filter.
|
||||
*
|
||||
* @param array $filter An associative array of filter options.
|
||||
* @return array An array of WarehouseOrderRecommendationModel instances.
|
||||
*/
|
||||
private static function customGet(array $filter = []): array {
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
$filterOptions = [];
|
||||
|
||||
// Convert filter to filterOptions because the filter is not directly usable
|
||||
if (isset($filter['articleTitle'])) {
|
||||
$filterOptions['title'] = $filter['articleTitle'];
|
||||
}
|
||||
|
||||
$articles = [];
|
||||
foreach (WarehouseArticleModel::getAll($filterOptions) as $article) {
|
||||
$articles[$article->id] = $article;
|
||||
}
|
||||
|
||||
$items = WarehouseItemModel::getAll();
|
||||
|
||||
$recommendations = [];
|
||||
// Check if the amount of items is below the critical or warning amount
|
||||
foreach ($articles as $article) {
|
||||
$items = array_filter($items, function ($item) use ($article) {
|
||||
return $item->articleId === $article->id;
|
||||
});
|
||||
|
||||
$count = array_reduce($items, function ($carry, $item) {
|
||||
return $carry + $item->quantity;
|
||||
}, 0);
|
||||
|
||||
if ($count <= $article->criticalAmount) {
|
||||
$minOrderAmount = $article->criticalAmount - $count;
|
||||
$recommendedOrderAmount = $article->warningAmount - $count;
|
||||
$recommendations[] = new WarehouseOrderRecommendationModel(["articleId" => $article->id,
|
||||
"articleTitle" => $article->title,
|
||||
"count" => $count,
|
||||
"status" => "Kritisch",
|
||||
"recommendation" => "Bestellen, min. $minOrderAmount, empfohlen: $recommendedOrderAmount"]);
|
||||
} else if ($count <= $article->warningAmount) {
|
||||
$minOrderAmount = $article->warningAmount - $count;
|
||||
$recommendations[] = new WarehouseOrderRecommendationModel(["articleId" => $article->id,
|
||||
"articleTitle" => $article->title,
|
||||
"count" => $count,
|
||||
"status" => "Warnung",
|
||||
"recommendation" => "Bestellen, min. $minOrderAmount"]);
|
||||
}
|
||||
}
|
||||
|
||||
$locations = [];
|
||||
foreach (WarehouseLocationModel::getAll() as $location) {
|
||||
$locations[$location->id] = $location;
|
||||
}
|
||||
|
||||
$locationThresholdOverrides = WarehouseLocationThresholdOverrideModel::getAll();
|
||||
|
||||
foreach ($locationThresholdOverrides as $locationThresholdOverride) {
|
||||
if (!isset($articles[$locationThresholdOverride->articleId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$items = array_filter($items, function ($item) use ($locationThresholdOverride) {
|
||||
return $item->articleId === $locationThresholdOverride->articleId;
|
||||
});
|
||||
|
||||
$count = array_reduce($items, function ($carry, $item) {
|
||||
return $carry + $item->quantity;
|
||||
}, 0);
|
||||
|
||||
if ($count <= $locationThresholdOverride->criticalAmount) {
|
||||
$minOrderAmount = $locationThresholdOverride->criticalAmount - $count;
|
||||
$recommendedOrderAmount = $locationThresholdOverride->warningAmount - $count;
|
||||
$recommendations[] = new WarehouseOrderRecommendationModel(["articleId" => $locationThresholdOverride->articleId,
|
||||
"articleTitle" => $articles[$locationThresholdOverride->articleId]->title,
|
||||
"locationId" => $locationThresholdOverride->locationId,
|
||||
"locationTitle" => $locations[$locationThresholdOverride->locationId]->title,
|
||||
"count" => $count,
|
||||
"status" => "Kritisch",
|
||||
"recommendation" => "Bestellen, min. $minOrderAmount, empfohlen: $recommendedOrderAmount"]);
|
||||
} else if ($count <= $locationThresholdOverride->warningAmount) {
|
||||
$minOrderAmount = $locationThresholdOverride->warningAmount - $count;
|
||||
$recommendations[] = new WarehouseOrderRecommendationModel(["articleId" => $locationThresholdOverride->articleId,
|
||||
"articleTitle" => $articles[$locationThresholdOverride->articleId]->title,
|
||||
"locationId" => $locationThresholdOverride->locationId,
|
||||
"locationTitle" => $locations[$locationThresholdOverride->locationId]->title,
|
||||
"count" => $count,
|
||||
"status" => "Warnung",
|
||||
"recommendation" => "Bestellen, min. $minOrderAmount"]);
|
||||
}
|
||||
}
|
||||
|
||||
return $recommendations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of recommendations based on the provided filter.
|
||||
*
|
||||
* @param array $filter An associative array of filter options.
|
||||
* @return int The number of recommendations.
|
||||
*/
|
||||
public static function count(array $filter = []): int {
|
||||
return count(self::customGet($filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all recommendations based on the provided filter, limit, offset, and order.
|
||||
*
|
||||
* @param array $filter An associative array of filter options.
|
||||
* @param int|null $limit The maximum number of recommendations to return.
|
||||
* @param int $offset The number of recommendations to skip.
|
||||
* @param array $order An associative array containing the key to sort by and the order direction ('ASC' or 'DESC').
|
||||
* @return array An array of WarehouseOrderRecommendationModel instances.
|
||||
*/
|
||||
public static function getAll(array $filter = [], int $limit = null, int $offset = 0, array $order = ["key" => null]): array {
|
||||
$recommendations = self::customGet($filter);
|
||||
|
||||
// apply limit,offset and order
|
||||
if ($order['key'] !== null) {
|
||||
usort($recommendations, function ($a, $b) use ($order) {
|
||||
return $order['order'] === 'ASC' ? $a->{$order['key']} <=> $b->{$order['key']} : $b->{$order['key']} <=> $a->{$order['key']};
|
||||
});
|
||||
}
|
||||
|
||||
if ($limit !== null) {
|
||||
return array_slice($recommendations, $offset, $limit);
|
||||
}
|
||||
return $recommendations;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user