auto fixes + some impl.

This commit is contained in:
Dennis Eichhorn 2024-01-26 22:54:00 +00:00
parent 17fb0226d4
commit cd18f753ca
28 changed files with 444 additions and 296 deletions

View File

@ -0,0 +1,43 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\WarehouseManagement\Admin\Install
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\WarehouseManagement\Admin\Install;
use phpOMS\Application\ApplicationAbstract;
/**
* ClientManagement class.
*
* @package Modules\WarehouseManagement\Admin\Install
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class ClientManagement
{
/**
* Install navigation providing
*
* @param ApplicationAbstract $app Application
* @param string $path Module path
*
* @return void
*
* @since 1.0.0
*/
public static function install(ApplicationAbstract $app, string $path) : void
{
\Modules\WarehouseManagement\Admin\Installer::personalStock($app, 'client');
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\WarehouseManagement\Admin\Install
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1);
namespace Modules\WarehouseManagement\Admin\Install;
use phpOMS\Application\ApplicationAbstract;
/**
* SupplierManagement class.
*
* @package Modules\WarehouseManagement\Admin\Install
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
*/
class SupplierManagement
{
/**
* Install navigation providing
*
* @param ApplicationAbstract $app Application
* @param string $path Module path
*
* @return void
*
* @since 1.0.0
*/
public static function install(ApplicationAbstract $app, string $path) : void
{
\Modules\WarehouseManagement\Admin\Installer::personalStock($app, 'supplier');
}
}

View File

@ -14,6 +14,11 @@
"type": "VARCHAR(255)", "type": "VARCHAR(255)",
"null": false "null": false
}, },
"warehousemgmt_stock_inventory": {
"name": "warehousemgmt_stock_inventory",
"type": "TINYINT(1)",
"null": false
},
"warehousemgmt_stock_unit": { "warehousemgmt_stock_unit": {
"name": "warehousemgmt_stock_unit", "name": "warehousemgmt_stock_unit",
"type": "INT", "type": "INT",
@ -21,6 +26,20 @@
"foreignTable": "itemmgmt_item", "foreignTable": "itemmgmt_item",
"foreignKey": "itemmgmt_item_id" "foreignKey": "itemmgmt_item_id"
}, },
"warehousemgmt_stock_client": {
"name": "warehousemgmt_stock_client",
"type": "INT",
"null": false,
"foreignTable": "clientmgmt_client",
"foreignKey": "clientmgmt_client_id"
},
"warehousemgmt_stock_supplier": {
"name": "warehousemgmt_stock_supplier",
"type": "INT",
"null": false,
"foreignTable": "suppliermgmt_supplier",
"foreignKey": "suppliermgmt_supplier_id"
},
"warehousemgmt_stock_address": { "warehousemgmt_stock_address": {
"name": "warehousemgmt_stock_address", "name": "warehousemgmt_stock_address",
"type": "INT", "type": "INT",
@ -273,6 +292,11 @@
"type": "TINYINT(1)", "type": "TINYINT(1)",
"null": false "null": false
}, },
"warehousemgmt_attr_type_internal": {
"name": "warehousemgmt_attr_type_internal",
"type": "TINYINT(1)",
"null": false
},
"warehousemgmt_attr_type_required": { "warehousemgmt_attr_type_required": {
"description": "Every item must have this attribute type if set to true.", "description": "Every item must have this attribute type if set to true.",
"name": "warehousemgmt_attr_type_required", "name": "warehousemgmt_attr_type_required",
@ -635,42 +659,48 @@
"warehousemgmt_stock_transaction_from_lot": { "warehousemgmt_stock_transaction_from_lot": {
"name": "warehousemgmt_stock_transaction_from_lot", "name": "warehousemgmt_stock_transaction_from_lot",
"type": "INT", "type": "INT",
"null": false, "null": true,
"default": null,
"foreignTable": "warehousemgmt_lot", "foreignTable": "warehousemgmt_lot",
"foreignKey": "warehousemgmt_lot_id" "foreignKey": "warehousemgmt_lot_id"
}, },
"warehousemgmt_stock_transaction_from_stock": { "warehousemgmt_stock_transaction_from_stock": {
"name": "warehousemgmt_stock_transaction_from_stock", "name": "warehousemgmt_stock_transaction_from_stock",
"type": "INT", "type": "INT",
"null": false, "null": true,
"default": null,
"foreignTable": "warehousemgmt_stock", "foreignTable": "warehousemgmt_stock",
"foreignKey": "warehousemgmt_stock_id" "foreignKey": "warehousemgmt_stock_id"
}, },
"warehousemgmt_stock_transaction_from_stocktype": { "warehousemgmt_stock_transaction_from_stocktype": {
"name": "warehousemgmt_stock_transaction_from_stocktype", "name": "warehousemgmt_stock_transaction_from_stocktype",
"type": "INT", "type": "INT",
"null": false, "null": true,
"default": null,
"foreignTable": "warehousemgmt_stock_type", "foreignTable": "warehousemgmt_stock_type",
"foreignKey": "warehousemgmt_stock_type_id" "foreignKey": "warehousemgmt_stock_type_id"
}, },
"warehousemgmt_stock_transaction_to_lot": { "warehousemgmt_stock_transaction_to_lot": {
"name": "warehousemgmt_stock_transaction_to_lot", "name": "warehousemgmt_stock_transaction_to_lot",
"type": "INT", "type": "INT",
"null": false, "null": true,
"default": null,
"foreignTable": "warehousemgmt_lot", "foreignTable": "warehousemgmt_lot",
"foreignKey": "warehousemgmt_lot_id" "foreignKey": "warehousemgmt_lot_id"
}, },
"warehousemgmt_stock_transaction_to_stock": { "warehousemgmt_stock_transaction_to_stock": {
"name": "warehousemgmt_stock_transaction_to_stock", "name": "warehousemgmt_stock_transaction_to_stock",
"type": "INT", "type": "INT",
"null": false, "null": true,
"default": null,
"foreignTable": "warehousemgmt_stock", "foreignTable": "warehousemgmt_stock",
"foreignKey": "warehousemgmt_stock_id" "foreignKey": "warehousemgmt_stock_id"
}, },
"warehousemgmt_stock_transaction_to_stocktype": { "warehousemgmt_stock_transaction_to_stocktype": {
"name": "warehousemgmt_stock_transaction_to_stocktype", "name": "warehousemgmt_stock_transaction_to_stocktype",
"type": "INT", "type": "INT",
"null": false, "null": true,
"default": null,
"foreignTable": "warehousemgmt_stock_type", "foreignTable": "warehousemgmt_stock_type",
"foreignKey": "warehousemgmt_stock_type_id" "foreignKey": "warehousemgmt_stock_type_id"
}, },

View File

@ -14,17 +14,12 @@ declare(strict_types=1);
namespace Modules\WarehouseManagement\Admin; namespace Modules\WarehouseManagement\Admin;
use Modules\WarehouseManagement\Models\Stock;
use Modules\WarehouseManagement\Models\StockLocation;
use Modules\WarehouseManagement\Models\StockLocationMapper;
use Modules\WarehouseManagement\Models\StockMapper;
use phpOMS\Application\ApplicationAbstract; use phpOMS\Application\ApplicationAbstract;
use phpOMS\Config\SettingsInterface; use phpOMS\Config\SettingsInterface;
use phpOMS\Message\Http\HttpRequest; use phpOMS\Message\Http\HttpRequest;
use phpOMS\Message\Http\HttpResponse; use phpOMS\Message\Http\HttpResponse;
use phpOMS\Module\InstallerAbstract; use phpOMS\Module\InstallerAbstract;
use phpOMS\Module\ModuleInfo; use phpOMS\Module\ModuleInfo;
use phpOMS\Uri\HttpUri;
/** /**
* Installer class. * Installer class.
@ -81,32 +76,13 @@ final class Installer extends InstallerAbstract
$module = $app->moduleManager->getModuleInstance('WarehouseManagement', 'Api'); $module = $app->moduleManager->getModuleInstance('WarehouseManagement', 'Api');
$response = new HttpResponse(); $response = new HttpResponse();
$request = new HttpRequest(new HttpUri('')); $request = new HttpRequest();
$request->header->account = 1; $request->header->account = 1;
$request->setData('name', 'Default'); $request->setData('name', 'Default');
$request->setData('unit', 1); $request->setData('unit', 1);
$request->setData('inventory', true);
$module->apiStockCreate($request, $response); $module->apiStockCreate($request, $response);
$responseData = $response->getData('');
if (!\is_array($responseData)) {
return;
}
$id = $responseData['response']->id;
$response = new HttpResponse();
$request = new HttpRequest(new HttpUri(''));
$request->header->account = 1;
$request->setData('name', $id . '-1');
$request->setData('stock', $id);
$module->apiStockLocationCreate($request, $response);
$responseData = $response->getData('');
if (!\is_array($responseData)) {
return;
}
} }
/** /**
@ -131,7 +107,7 @@ final class Installer extends InstallerAbstract
foreach ($types as $type) { foreach ($types as $type) {
$response = new HttpResponse(); $response = new HttpResponse();
$request = new HttpRequest(new HttpUri('')); $request = new HttpRequest();
$request->header->account = 1; $request->header->account = 1;
$request->setData('name', $type['name'] ?? ''); $request->setData('name', $type['name'] ?? '');
@ -159,7 +135,7 @@ final class Installer extends InstallerAbstract
} }
$response = new HttpResponse(); $response = new HttpResponse();
$request = new HttpRequest(new HttpUri('')); $request = new HttpRequest();
$request->header->account = 1; $request->header->account = 1;
$request->setData('title', $l11n); $request->setData('title', $l11n);
@ -172,4 +148,34 @@ final class Installer extends InstallerAbstract
return $stockTypes; return $stockTypes;
} }
/**
* Import accounts
*
* @param ApplicationAbstract $app Application
* @param string $type Personal account type
*
* @return void
*
* @since 1.0.0
*/
public static function personalStock(ApplicationAbstract $app, string $type) : void
{
/** @var \Modules\WarehouseManagement\Controller\ApiController $module */
$module = $app->moduleManager->getModuleInstance('WarehouseManagement', 'Api');
$mapper = $type === 'client'
? \Modules\ClientManagement\Models\ClientMapper::class
: \Modules\SupplierManagement\Models\SupplierMapper::class;
foreach ($mapper::yield()->execute() as $person) {
$response = new HttpResponse();
$request = new HttpRequest();
$request->header->account = 1;
$request->setData('name', $person->number);
$request->setData($type, $person->id);
$module->apiStockCreate($request, $response);
}
}
} }

View File

@ -18,7 +18,7 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb; use phpOMS\Router\RouteVerb;
return [ return [
'^.*/warehouse/stock/list.*$' => [ '^.*/warehouse/stock/list(\?.*$|$)' => [
[ [
'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockList', 'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockList',
'verb' => RouteVerb::GET, 'verb' => RouteVerb::GET,
@ -40,7 +40,7 @@ return [
], ],
], ],
], ],
'^.*/warehouse/stock/type/list.*$' => [ '^.*/warehouse/stock/type/list(\?.*$|$)' => [
[ [
'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockTypeList', 'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockTypeList',
'verb' => RouteVerb::GET, 'verb' => RouteVerb::GET,
@ -62,7 +62,7 @@ return [
], ],
], ],
], ],
'^.*/warehouse/stock/location/list.*$' => [ '^.*/warehouse/stock/location/list(\?.*$|$)' => [
[ [
'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockLocationList', 'dest' => '\Modules\WarehouseManagement\Controller\BackendController:viewStockLocationList',
'verb' => RouteVerb::GET, 'verb' => RouteVerb::GET,

View File

@ -17,6 +17,7 @@ namespace Modules\WarehouseManagement\Controller;
use Modules\Attribute\Models\Attribute; use Modules\Attribute\Models\Attribute;
use Modules\Attribute\Models\AttributeType; use Modules\Attribute\Models\AttributeType;
use Modules\Attribute\Models\AttributeValue; use Modules\Attribute\Models\AttributeValue;
use Modules\Attribute\Models\AttributeValueType;
use Modules\Attribute\Models\NullAttributeType; use Modules\Attribute\Models\NullAttributeType;
use Modules\Attribute\Models\NullAttributeValue; use Modules\Attribute\Models\NullAttributeValue;
use Modules\WarehouseManagement\Models\Attribute\LotAttributeMapper; use Modules\WarehouseManagement\Models\Attribute\LotAttributeMapper;
@ -158,9 +159,7 @@ final class ApiAttributeController extends Controller
{ {
$attrL11n = new BaseStringL11n(); $attrL11n = new BaseStringL11n();
$attrL11n->ref = $request->getDataInt('type') ?? 0; $attrL11n->ref = $request->getDataInt('type') ?? 0;
$attrL11n->setLanguage( $attrL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$request->getDataString('language') ?? $request->header->l11n->language
);
$attrL11n->content = $request->getDataString('title') ?? ''; $attrL11n->content = $request->getDataString('title') ?? '';
return $attrL11n; return $attrL11n;
@ -226,11 +225,14 @@ final class ApiAttributeController extends Controller
private function createLotAttributeTypeFromRequest(RequestAbstract $request) : AttributeType private function createLotAttributeTypeFromRequest(RequestAbstract $request) : AttributeType
{ {
$attrType = new AttributeType($request->getDataString('name') ?? ''); $attrType = new AttributeType($request->getDataString('name') ?? '');
$attrType->datatype = $request->getDataInt('datatype') ?? 0; $attrType->datatype = AttributeValueType::tryFromValue($request->getDataInt('datatype')) ?? AttributeValueType::_STRING;
$attrType->custom = $request->getDataBool('custom') ?? false; $attrType->custom = $request->getDataBool('custom') ?? false;
$attrType->isRequired = $request->getDataBool('is_required') ?? false; $attrType->isRequired = $request->getDataBool('is_required') ?? false;
$attrType->validationPattern = $request->getDataString('validation_pattern') ?? ''; $attrType->validationPattern = $request->getDataString('validation_pattern') ?? '';
$attrType->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); $attrType->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
$attrType->setFields($request->getDataInt('fields') ?? 0); $attrType->setFields($request->getDataInt('fields') ?? 0);
return $attrType; return $attrType;
@ -315,7 +317,10 @@ final class ApiAttributeController extends Controller
$attrValue->setValue($request->getDataString('value'), $type->datatype); $attrValue->setValue($request->getDataString('value'), $type->datatype);
if ($request->hasData('title')) { if ($request->hasData('title')) {
$attrValue->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); $attrValue->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
} }
return $attrValue; return $attrValue;
@ -382,9 +387,7 @@ final class ApiAttributeController extends Controller
{ {
$attrL11n = new BaseStringL11n(); $attrL11n = new BaseStringL11n();
$attrL11n->ref = $request->getDataInt('value') ?? 0; $attrL11n->ref = $request->getDataInt('value') ?? 0;
$attrL11n->setLanguage( $attrL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$request->getDataString('language') ?? $request->header->l11n->language
);
$attrL11n->content = $request->getDataString('title') ?? ''; $attrL11n->content = $request->getDataString('title') ?? '';
return $attrL11n; return $attrL11n;

View File

@ -18,19 +18,21 @@ use Modules\Billing\Models\BillElement;
use Modules\Billing\Models\BillMapper; use Modules\Billing\Models\BillMapper;
use Modules\Billing\Models\BillStatus; use Modules\Billing\Models\BillStatus;
use Modules\Billing\Models\BillTransferType; use Modules\Billing\Models\BillTransferType;
use Modules\ClientManagement\Models\NullClient;
use Modules\ItemManagement\Models\StockIdentifierType; use Modules\ItemManagement\Models\StockIdentifierType;
use Modules\SupplierManagement\Models\NullSupplier;
use Modules\WarehouseManagement\Models\Stock; use Modules\WarehouseManagement\Models\Stock;
use Modules\WarehouseManagement\Models\StockDistribution; use Modules\WarehouseManagement\Models\StockDistribution;
use Modules\WarehouseManagement\Models\StockDistributionMapper; use Modules\WarehouseManagement\Models\StockDistributionMapper;
use Modules\WarehouseManagement\Models\StockLocation; use Modules\WarehouseManagement\Models\StockLocation;
use Modules\WarehouseManagement\Models\StockLocationMapper; use Modules\WarehouseManagement\Models\StockLocationMapper;
use Modules\WarehouseManagement\Models\StockMapper; use Modules\WarehouseManagement\Models\StockMapper;
use Modules\WarehouseManagement\Models\StockShelf;
use Modules\WarehouseManagement\Models\StockShelfMapper;
use Modules\WarehouseManagement\Models\StockTransaction; use Modules\WarehouseManagement\Models\StockTransaction;
use Modules\WarehouseManagement\Models\StockTransactionMapper; use Modules\WarehouseManagement\Models\StockTransactionMapper;
use Modules\WarehouseManagement\Models\StockTransactionState; use Modules\WarehouseManagement\Models\StockTransactionState;
use Modules\WarehouseManagement\Models\StockTransactionType; use Modules\WarehouseManagement\Models\StockTransactionType;
use Modules\WarehouseManagement\Models\StockShelf;
use Modules\WarehouseManagement\Models\StockShelfMapper;
use phpOMS\Message\Http\RequestStatusCode; use phpOMS\Message\Http\RequestStatusCode;
use phpOMS\Message\RequestAbstract; use phpOMS\Message\RequestAbstract;
use phpOMS\Message\ResponseAbstract; use phpOMS\Message\ResponseAbstract;
@ -69,6 +71,13 @@ final class ApiController extends Controller
$stock = $this->createStockFromRequest($request); $stock = $this->createStockFromRequest($request);
$this->createModel($request->header->account, $stock, StockMapper::class, 'stock', $request->getOrigin()); $this->createModel($request->header->account, $stock, StockMapper::class, 'stock', $request->getOrigin());
$request->setData('name', $request->getDataString('name') . '-1', true);
$request->setData('stock', $stock->id, true);
$stock = $this->createStockLocationFromRequest($request);
$this->createModel($request->header->account, $stock, StockLocationMapper::class, 'stocklocation', $request->getOrigin());
$this->createStandardCreateResponse($request, $response, $stock); $this->createStandardCreateResponse($request, $response, $stock);
} }
@ -106,6 +115,10 @@ final class ApiController extends Controller
$stock = new Stock(); $stock = new Stock();
$stock->name = $request->getDataString('name') ?? ''; $stock->name = $request->getDataString('name') ?? '';
$stock->unit = $request->getDataInt('unit') ?? 1; $stock->unit = $request->getDataInt('unit') ?? 1;
$stock->inventory = $request->getDataBool('inventory') ?? false;
$stock->client = $request->hasData('client') ? new NullClient($request->getDataInt('client')) : null;
$stock->supplier = $request->hasData('supplier') ? new NullSupplier($request->getDataInt('supplier')) : null;
return $stock; return $stock;
} }
@ -197,12 +210,12 @@ final class ApiController extends Controller
int $account, int $account,
mixed $old, mixed $old,
mixed $new, mixed $new,
int $type = null, ?int $type = null,
string $trigger = '', string $trigger = '',
string $module = null, ?string $module = null,
string $ref = null, ?string $ref = null,
string $content = null, ?string $content = null,
string $ip = null ?string $ip = null
) : void ) : void
{ {
/** @var \Modules\ClientManagement\Models\Client|\Modules\SupplierManagement\Models\Supplier $new */ /** @var \Modules\ClientManagement\Models\Client|\Modules\SupplierManagement\Models\Supplier $new */
@ -234,17 +247,20 @@ final class ApiController extends Controller
* @return void * @return void
* *
* @since 1.0.0 * @since 1.0.0
*
* @todo Cleanup/restructure so this function works with database transactions and exceptions. This function is very critical!
* Maybe do the transaction outside wherever the updateModel/createModel/... functions are called.
*/ */
public function eventBillUpdateInternal( public function eventBillUpdateInternal(
int $account, int $account,
mixed $old, mixed $old,
mixed $new, mixed $new,
int $type = null, ?int $type = null,
string $trigger = '', string $trigger = '',
string $module = null, ?string $module = null,
string $ref = null, ?string $ref = null,
string $content = null, ?string $content = null,
string $ip = null ?string $ip = null
) : void ) : void
{ {
// Directly/manually creating a transaction is handled in the API Create/Update functions. // Directly/manually creating a transaction is handled in the API Create/Update functions.
@ -255,18 +271,34 @@ final class ApiController extends Controller
$bill = BillMapper::get() $bill = BillMapper::get()
->with('type') ->with('type')
->with('elements') ->with('elements')
->with('elements/container')
->with('elements/item') ->with('elements/item')
->with('supplier') ->with('supplier')
->with('client') ->with('client')
->where('id', $isBillElement ? $new->bill->id : $new->id) ->where('id', $isBillElement ? $new->bill->id : $new->id)
->where('type/transferStock', true)
->execute(); ->execute();
// Has stock movement? // Has stock movement?
if (!$bill->type->transferStock) { if ($bill->id === 0 || !$bill->type->transferStock) {
return; return;
} }
$billElements = $isBillElement ? [$new] : $bill->elements; /*
Only necessary if actual client/supplier stock
$externalStock = 1;
if ($bill->client !== null) {
$externalStock = StockMapper::get()
->where('client', $bill->client->id)
->limit(1)
->execute();
} elseif ($bill->supplier !== null) {
$externalStock = StockMapper::get()
->where('supplier', $bill->supplier->id)
->limit(1)
->execute();
}
*/
// @todo check if old element existed -> removed/changed item // @todo check if old element existed -> removed/changed item
// @todo we cannot have transaction->to and transaction->from be the id of client/supplier because the IDs can overlap // @todo we cannot have transaction->to and transaction->from be the id of client/supplier because the IDs can overlap
@ -276,7 +308,7 @@ final class ApiController extends Controller
// invoice with partly delivery note(s), // invoice with partly delivery note(s),
// invoice with no delivery note // invoice with no delivery note
// @todo Handle bill drafts (now only finalization moves stock, how do we reserve stock?) // @todo Handle bill drafts (now only finalization moves stock, how do we reserve stock?)
foreach ($billElements as $element) { foreach ($bill->elements as $element) {
if ($element->item === 0 || $element->item === null if ($element->item === 0 || $element->item === null
|| $element->item->stockIdentifier === StockIdentifierType::NONE || $element->item->stockIdentifier === StockIdentifierType::NONE
) { ) {
@ -288,15 +320,14 @@ final class ApiController extends Controller
->where('stock', 1) // @todo fix ->where('stock', 1) // @todo fix
->where('stockType', 1) // @todo fix ->where('stockType', 1) // @todo fix
->where('lot', $element->item->stockIdentifier === StockIdentifierType::NUMBER ? null : '') ->where('lot', $element->item->stockIdentifier === StockIdentifierType::NUMBER ? null : '')
->limit(1)
->execute(); ->execute();
$transaction = new StockTransaction();
// @todo how to handle only reserving items for drafted bills (not yet shipped) // @todo how to handle only reserving items for drafted bills (not yet shipped)
if ($trigger === 'POST:Module:Billing-bill_element-create') { if ($trigger === 'Billing-bill_element-create') {
// Check stock availability // Check stock availability
if ($bill->type->sign < 0 && $dist->quantity < $element->quantity) { if ($bill->type->sign > 0 && $dist->quantity < $element->quantity->getInt()) {
continue; continue;
} }
@ -306,15 +337,14 @@ final class ApiController extends Controller
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// @todo handle stock returns!!! // @todo handle stock returns!!!
if ($bill->type->sign < 0) { if ($bill->type->sign > 0) {
$dist->quantity -= $element->quantity; $dist->quantity -= $element->quantity->getInt();
StockDistributionMapper::update()->execute($dist); StockDistributionMapper::update()->execute($dist);
} else { } elseif ($dist->id === 0) {
if ($dist->id === 0) {
$dist = new StockDistribution(); $dist = new StockDistribution();
$dist->item = $element->item->id; $dist->item = $element->item->id;
$dist->quantity = $element->quantity; $dist->quantity = $element->quantity->getInt();
$dist->lot = null; // @todo handle correct $dist->lot = null; // @todo handle correct
$dist->stock = 1; // @todo handle correct $dist->stock = 1; // @todo handle correct
@ -322,15 +352,15 @@ final class ApiController extends Controller
StockDistributionMapper::create()->execute($dist); StockDistributionMapper::create()->execute($dist);
} else { } else {
$dist->quantity += $element->quantity; $dist->quantity += $element->quantity->getInt();
StockDistributionMapper::update()->execute($dist); StockDistributionMapper::update()->execute($dist);
} }
}
// Handle transfer protocol // Handle transfer protocol
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
$transaction = new StockTransaction();
$transaction->billElement = $new->id; $transaction->billElement = $new->id;
$transaction->state = StockTransactionState::DRAFT; $transaction->state = StockTransactionState::DRAFT;
@ -338,7 +368,8 @@ final class ApiController extends Controller
// @todo find stock candidates // @todo find stock candidates
$transaction->type = StockTransactionType::TRANSFER; // @todo depends on bill type $transaction->type = StockTransactionType::TRANSFER; // @todo depends on bill type
$transaction->quantity = $new->getQuantity(); // @todo may require split quantity if not sufficient available from one lost $transaction->quantity = $new->quantity->getInt(); // @todo may require split quantity if not sufficient available from one lost
$transaction->item = $element->item->id;
// @todo allow consignment bills // @todo allow consignment bills
// @todo allow to pass stocklocation for entire bill to avoid re-defining it // @todo allow to pass stocklocation for entire bill to avoid re-defining it
@ -347,8 +378,13 @@ final class ApiController extends Controller
if ($bill->type->sign > 0) { if ($bill->type->sign > 0) {
// Handle from // Handle from
// @todo find possible candidate based on defined default stock for bill type/org/location // @todo find possible candidate based on defined default stock for bill type/org/location
$transaction->fromStock = 1; // @todo requires update
$transaction->fromStockType = 1; // @todo requires update
// Handle to // Handle to
$transaction->toStock = null; // @todo requires update
$transaction->toStockType = null; // @todo requires update
if (($bill->client?->id ?? 0) !== 0) { if (($bill->client?->id ?? 0) !== 0) {
// @todo remove phpstan this is just a bug fix until phpstan fixes this bug // @todo remove phpstan this is just a bug fix until phpstan fixes this bug
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
@ -362,10 +398,13 @@ final class ApiController extends Controller
if ($bill->type->transferType === BillTransferType::SALES) { if ($bill->type->transferType === BillTransferType::SALES) {
$transaction->subtype = StockTransactionType::SALE; $transaction->subtype = StockTransactionType::SALE;
} elseif ($bill->type->transferType === BillTransferType::PURCHASE) { } elseif ($bill->type->transferType === BillTransferType::PURCHASE) {
$transaction->subtype = StockTransactionType::PURCHASE; $transaction->subtype = StockTransactionType::RETURN;
} }
} else { } else {
// Handle from // Handle from
$transaction->fromStock = null; // @todo requires update
$transaction->fromStockType = null; // @todo requires update
if (($bill->client?->id ?? 0) !== 0) { if (($bill->client?->id ?? 0) !== 0) {
// @todo remove phpstan this is just a bug fix until phpstan fixes this bug // @todo remove phpstan this is just a bug fix until phpstan fixes this bug
/** @phpstan-ignore-next-line */ /** @phpstan-ignore-next-line */
@ -378,16 +417,18 @@ final class ApiController extends Controller
// Handle to // Handle to
// @todo find possible candidate based on defined default stock for bill type/org/location // @todo find possible candidate based on defined default stock for bill type/org/location
$transaction->toStock = 1; // @todo requires update
$transaction->toStockType = 1; // @todo requires update
if ($bill->type->transferType === BillTransferType::SALES if ($bill->type->transferType === BillTransferType::SALES) {
|| $bill->type->transferType === BillTransferType::PURCHASE
) {
$transaction->subtype = StockTransactionType::RETURN; $transaction->subtype = StockTransactionType::RETURN;
} elseif ($bill->type->transferType === BillTransferType::PURCHASE) {
$transaction->subtype = StockTransactionType::PURCHASE;
} }
} }
StockTransactionMapper::create()->execute($transaction); StockTransactionMapper::create()->execute($transaction);
} elseif ($trigger === 'POST:Module:Billing-bill_element-update') { } elseif ($trigger === 'Billing-bill_element-update') {
/** @var \Modules\Billing\Models\BillElement $new */ /** @var \Modules\Billing\Models\BillElement $new */
/** @var \Modules\Billing\Models\BillElement $old */ /** @var \Modules\Billing\Models\BillElement $old */
/** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */ /** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */
@ -406,15 +447,18 @@ final class ApiController extends Controller
// and then do normal algorithm like for a new element // and then do normal algorithm like for a new element
} }
*/ */
if ($new->item !== $old->item) { if ($new->item->id !== $old->item->id) {
// @todo: also undo stock amount in stock distribution
StockTransactionMapper::delete()->execute($transactions); StockTransactionMapper::delete()->execute($transactions);
$this->eventBillUpdateInternal( $this->eventBillUpdateInternal(
$account, $old, $new, $account, $old, $new,
$type, 'POST:Module:Billing-bill_element-create', $module, $ref, $content, $ip $type, 'Billing-bill_element-create', $module, $ref, $content, $ip
); );
} }
} elseif ($trigger === 'POST:Module:Billing-bill_element-delete') {
// @todo handle same item but quantity update
} elseif ($trigger === 'Billing-bill_element-delete') {
/** @var \Modules\Billing\Models\BillElement $new */ /** @var \Modules\Billing\Models\BillElement $new */
/** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */ /** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */
$transactions = StockTransactionMapper::getAll() $transactions = StockTransactionMapper::getAll()
@ -422,17 +466,7 @@ final class ApiController extends Controller
->execute(); ->execute();
StockTransactionMapper::delete()->execute($transactions); StockTransactionMapper::delete()->execute($transactions);
} elseif ($trigger === 'POST:Module:Billing-bill-delete') { } elseif ($trigger === 'Billing-bill-delete') {
/** @var \Modules\Billing\Models\Bill $new */
/** @var \Modules\Billing\Models\Bill $bill */
$bill = BillMapper::get()
->with('type')
->with('elements')
->with('supplier')
->with('client')
->where('id', $new->id)
->execute();
foreach ($bill->elements as $element) { foreach ($bill->elements as $element) {
/** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */ /** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */
$transactions = StockTransactionMapper::getAll() $transactions = StockTransactionMapper::getAll()
@ -442,7 +476,7 @@ final class ApiController extends Controller
StockTransactionMapper::delete()->execute($transactions); StockTransactionMapper::delete()->execute($transactions);
// @todo consider not to delete but mark as deleted? // @todo consider not to delete but mark as deleted?
} }
} elseif ($trigger === 'POST:Module:Billing-bill-update') { } elseif ($trigger === 'Billing-bill-update') {
// is receiver update -> change all movements // is receiver update -> change all movements
// is status update -> change all movements (delete = delete) // is status update -> change all movements (delete = delete)
@ -450,18 +484,9 @@ final class ApiController extends Controller
if ($new->status === BillStatus::DELETED) { if ($new->status === BillStatus::DELETED) {
$this->eventBillUpdateInternal( $this->eventBillUpdateInternal(
$account, $old, $new, $account, $old, $new,
$type, 'POST:Module:Billing-bill-delete', $module, $ref, $content, $ip $type, 'Billing-bill-delete', $module, $ref, $content, $ip
); );
} elseif ($new->status === BillStatus::ARCHIVED) { } elseif ($new->status === BillStatus::ARCHIVED) {
/** @var \Modules\Billing\Models\Bill $bill */
$bill = BillMapper::get()
->with('type')
->with('elements')
->with('supplier')
->with('client')
->where('id', $new->id)
->execute();
foreach ($bill->elements as $element) { foreach ($bill->elements as $element) {
/** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */ /** @var \Modules\WarehouseManagement\Models\StockTransaction[] $transactions */
$transactions = StockTransactionMapper::getAll() $transactions = StockTransactionMapper::getAll()

View File

@ -74,7 +74,10 @@ final class ApiStockTypeController extends Controller
{ {
$stockType = new StockType(); $stockType = new StockType();
$stockType->name = $request->getDataString('name') ?? ''; $stockType->name = $request->getDataString('name') ?? '';
$stockType->setL11n($request->getDataString('title') ?? '', $request->getDataString('language') ?? ISO639x1Enum::_EN); $stockType->setL11n(
$request->getDataString('title') ?? '',
ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? ISO639x1Enum::_EN
);
return $stockType; return $stockType;
} }
@ -140,9 +143,7 @@ final class ApiStockTypeController extends Controller
{ {
$stockTypeL11n = new BaseStringL11n(); $stockTypeL11n = new BaseStringL11n();
$stockTypeL11n->ref = $request->getDataInt('type') ?? 0; $stockTypeL11n->ref = $request->getDataInt('type') ?? 0;
$stockTypeL11n->setLanguage( $stockTypeL11n->language = ISO639x1Enum::tryFromValue($request->getDataString('language')) ?? $request->header->l11n->language;
$request->getDataString('language') ?? $request->header->l11n->language
);
$stockTypeL11n->content = $request->getDataString('title') ?? ''; $stockTypeL11n->content = $request->getDataString('title') ?? '';
return $stockTypeL11n; return $stockTypeL11n;

View File

@ -152,7 +152,7 @@ final class BackendController extends Controller
{ {
$view = new View($this->app->l11nManager, $request, $response); $view = new View($this->app->l11nManager, $request, $response);
$view->setTemplate('/Modules/WarehouseManagement/Theme/Backend/stock-type-profile'); $view->setTemplate('/Modules/WarehouseManagement/Theme/Backend/stock-type-view');
$view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1001302001, $request, $response); $view->data['nav'] = $this->app->moduleManager->get('Navigation')->createNavigationMid(1001302001, $request, $response);
$view->data['type'] = StockMapper::get()->where('id', (int) $request->getData('id'))->execute(); $view->data['type'] = StockMapper::get()->where('id', (int) $request->getData('id'))->execute();

View File

@ -14,6 +14,8 @@ declare(strict_types=1);
namespace Modules\WarehouseManagement\Models; namespace Modules\WarehouseManagement\Models;
use Modules\ClientManagement\Models\Client;
use Modules\SupplierManagement\Models\Supplier;
use phpOMS\Stdlib\Base\Address; use phpOMS\Stdlib\Base\Address;
/** /**
@ -44,8 +46,14 @@ class Stock
public int $unit = 0; public int $unit = 0;
public ?Client $client = null;
public ?Supplier $supplier = null;
public ?Address $address = null; public ?Address $address = null;
public bool $inventory = false;
/** /**
* Constructor. * Constructor.
* *
@ -57,16 +65,4 @@ class Stock
{ {
$this->name = $name; $this->name = $name;
} }
/**
* Get id.
*
* @return int
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
} }

View File

@ -34,7 +34,7 @@ class StockDistribution
public int $quantity = 0; public int $quantity = 0;
public int $lot = 0; public ?int $lot = null;
public int $item = 0; public int $item = 0;

View File

@ -55,16 +55,4 @@ class StockLocation
{ {
$this->name = $name; $this->name = $name;
} }
/**
* Get id.
*
* @return int
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
} }

View File

@ -15,6 +15,8 @@ declare(strict_types=1);
namespace Modules\WarehouseManagement\Models; namespace Modules\WarehouseManagement\Models;
use Modules\Admin\Models\AddressMapper; use Modules\Admin\Models\AddressMapper;
use Modules\ClientManagement\Models\ClientMapper;
use Modules\SupplierManagement\Models\SupplierMapper;
use phpOMS\DataStorage\Database\Mapper\DataMapperFactory; use phpOMS\DataStorage\Database\Mapper\DataMapperFactory;
/** /**
@ -40,6 +42,9 @@ final class StockMapper extends DataMapperFactory
'warehousemgmt_stock_id' => ['name' => 'warehousemgmt_stock_id', 'type' => 'int', 'internal' => 'id'], 'warehousemgmt_stock_id' => ['name' => 'warehousemgmt_stock_id', 'type' => 'int', 'internal' => 'id'],
'warehousemgmt_stock_name' => ['name' => 'warehousemgmt_stock_name', 'type' => 'string', 'internal' => 'name'], 'warehousemgmt_stock_name' => ['name' => 'warehousemgmt_stock_name', 'type' => 'string', 'internal' => 'name'],
'warehousemgmt_stock_unit' => ['name' => 'warehousemgmt_stock_unit', 'type' => 'int', 'internal' => 'unit'], 'warehousemgmt_stock_unit' => ['name' => 'warehousemgmt_stock_unit', 'type' => 'int', 'internal' => 'unit'],
'warehousemgmt_stock_client' => ['name' => 'warehousemgmt_stock_client', 'type' => 'int', 'internal' => 'client'],
'warehousemgmt_stock_supplier' => ['name' => 'warehousemgmt_stock_supplier', 'type' => 'int', 'internal' => 'supplier'],
'warehousemgmt_stock_inventory' => ['name' => 'warehousemgmt_stock_inventory', 'type' => 'bool', 'internal' => 'inventory'],
'warehousemgmt_stock_address' => ['name' => 'warehousemgmt_stock_address', 'type' => 'int', 'internal' => 'address'], 'warehousemgmt_stock_address' => ['name' => 'warehousemgmt_stock_address', 'type' => 'int', 'internal' => 'address'],
]; ];
@ -56,6 +61,23 @@ final class StockMapper extends DataMapperFactory
], ],
]; ];
/**
* Belongs to.
*
* @var array<string, array{mapper:class-string, external:string, column?:string, by?:string}>
* @since 1.0.0
*/
public const BELONGS_TO = [
'client' => [
'mapper' => ClientMapper::class,
'external' => 'warehousemgmt_stock_client',
],
'supplier' => [
'mapper' => SupplierMapper::class,
'external' => 'warehousemgmt_stock_supplier',
],
];
/** /**
* Primary table. * Primary table.
* *

View File

@ -55,16 +55,4 @@ class StockShelf
{ {
$this->name = $name; $this->name = $name;
} }
/**
* Get id.
*
* @return int
*
* @since 1.0.0
*/
public function getId() : int
{
return $this->id;
}
} }

View File

@ -55,13 +55,17 @@ class StockTransaction
public int $item = 0; public int $item = 0;
public int $fromLot = 0; public ?int $fromLot = null;
public int $fromStock = 0;
public int $fromStockType = 0;
public int $toLot = 0; public ?int $fromStock = null;
public int $toStock = 0;
public int $toStockType = 0; public ?int $fromStockType = null;
public ?int $toLot = null;
public ?int $toStock = null;
public ?int $toStockType = null;
/** /**
* Creator. * Creator.
@ -89,16 +93,4 @@ class StockTransaction
$this->createdBy = new NullAccount(); $this->createdBy = new NullAccount();
$this->createdAt = new \DateTimeImmutable('now'); $this->createdAt = new \DateTimeImmutable('now');
} }
/**
* Get ID.
*
* @return int
*
* @since 1.0.0
*/
public function getId()
{
return $this->id;
}
} }

View File

@ -66,12 +66,12 @@ class StockType
$this->l11n = $l11n; $this->l11n = $l11n;
} elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) { } elseif (isset($this->l11n) && $this->l11n instanceof BaseStringL11n) {
$this->l11n->content = $l11n; $this->l11n->content = $l11n;
$this->l11n->setLanguage($lang); $this->l11n->language = $lang;
} else { } else {
$this->l11n = new BaseStringL11n(); $this->l11n = new BaseStringL11n();
$this->l11n->content = $l11n; $this->l11n->content = $l11n;
$this->l11n->ref = $this->id; $this->l11n->ref = $this->id;
$this->l11n->setLanguage($lang); $this->l11n->language = $lang;
} }
} }

View File

@ -79,7 +79,7 @@ echo $this->data['nav']->render();
<?php endif; ?> <?php endif; ?>
<td data-tpl-text="/id" data-tpl-value="/id"><?= $value->id; ?> <td data-tpl-text="/id" data-tpl-value="/id"><?= $value->id; ?>
<td data-tpl-text="/type" data-tpl-value="/type" data-value="<?= $value->type->id; ?>"><?= $this->printHtml($value->type->title); ?> <td data-tpl-text="/type" data-tpl-value="/type" data-value="<?= $value->type->id; ?>"><?= $this->printHtml($value->type->title); ?>
<td data-tpl-text="/language" data-tpl-value="/language"><?= $this->printHtml($value->getLanguage()); ?> <td data-tpl-text="/language" data-tpl-value="/language"><?= $this->printHtml($value->language); ?>
<td data-tpl-text="/l11n" data-tpl-value="/l11n" data-value="<?= \nl2br($this->printHtml($value->content)); ?>"><?= \nl2br($this->printHtml(\substr($value->content, 0, 100))); ?> <td data-tpl-text="/l11n" data-tpl-value="/l11n" data-value="<?= \nl2br($this->printHtml($value->content)); ?>"><?= \nl2br($this->printHtml(\substr($value->content, 0, 100))); ?>
<?php endforeach; ?> <?php endforeach; ?>
<?php if ($c === 0) : ?> <?php if ($c === 0) : ?>

View File

@ -1,4 +1,15 @@
<?php <?php
/**
* Jingga
*
* PHP Version 8.1
*
* @package Modules\WarehouseManagement\tests
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
declare(strict_types=1); declare(strict_types=1);
\ini_set('memory_limit', '2048M'); \ini_set('memory_limit', '2048M');