diff --git a/Admin/Hooks/Manual.php b/Admin/Hooks/Manual.php new file mode 100644 index 0000000..1b4ede3 --- /dev/null +++ b/Admin/Hooks/Manual.php @@ -0,0 +1,22 @@ + [ + 'callback' => ['\Modules\WarehouseManagement\Controller\ApiController:eventBillUpdateInternal'], + ], + '/POST:Module:Billing\-bill\-(update|delete)/' => [ + 'callback' => ['\Modules\WarehouseManagement\Controller\ApiController:eventBillUpdateInternal'], + ], +]; diff --git a/Admin/Install/db.json b/Admin/Install/db.json index 128e43d..5094d97 100755 --- a/Admin/Install/db.json +++ b/Admin/Install/db.json @@ -586,6 +586,12 @@ "primary": true, "autoincrement": true }, + "warehousemgmt_stock_distribution_history_name": { + "descritpion": "Name of the stock distribution snapshot, given by a user/admin.", + "name": "warehousemgmt_stock_distribution_history_name", + "type": "VARCHAR(255)", + "null": false + }, "warehousemgmt_stock_distribution_history_item": { "name": "warehousemgmt_stock_distribution_history_item", "type": "INT", diff --git a/Admin/Hooks/Web/Api.php b/Admin/Routes/Web/Api.php old mode 100755 new mode 100644 similarity index 100% rename from Admin/Hooks/Web/Api.php rename to Admin/Routes/Web/Api.php diff --git a/Controller/ApiController.php b/Controller/ApiController.php index ed85db7..bcff5ea 100755 --- a/Controller/ApiController.php +++ b/Controller/ApiController.php @@ -14,11 +14,18 @@ declare(strict_types=1); namespace Modules\WarehouseManagement\Controller; -use Modules\Billing\Models\Bill; +use Modules\Billing\Models\BillElement; +use Modules\Billing\Models\BillMapper; +use Modules\Billing\Models\BillStatus; +use Modules\Billing\Models\BillTransferType; use Modules\WarehouseManagement\Models\Stock; use Modules\WarehouseManagement\Models\StockLocation; use Modules\WarehouseManagement\Models\StockLocationMapper; use Modules\WarehouseManagement\Models\StockMapper; +use Modules\WarehouseManagement\Models\StockMovement; +use Modules\WarehouseManagement\Models\StockMovementMapper; +use Modules\WarehouseManagement\Models\StockMovementState; +use Modules\WarehouseManagement\Models\StockMovementType; use Modules\WarehouseManagement\Models\StockShelf; use Modules\WarehouseManagement\Models\StockShelfMapper; @@ -62,7 +69,7 @@ final class ApiController extends Controller ) : void { /** @var \Modules\ClientManagement\Models\Client|\Modules\SupplierManagement\Models\Supplier $new */ - $stock = new Stock($new->number); + $stock = new Stock($new->number); StockMapper::create()->execute($stock); $stockLocation = new StockLocation($stock->name . '-1'); @@ -103,25 +110,157 @@ final class ApiController extends Controller string $ip = null ) : void { + // Directly/manually creating a transaction is handled in the API Create/Update functions. + + /** @var \Modules\Billing\Models\Bill $bill */ + $bill = BillMapper::get() + ->with('type') + ->with('supplier') + ->with('client') + ->where('id', $new instanceof BillElement ? $new->bill->id : $new->id) + ->execute(); + + // Has stock movement? + if ($bill->id !== 0 && !$bill->type->transferStock) { + return; + } + + // @todo: check if old element existex -> removed/changed item + + $transaction = new StockMovement(); + if ($trigger === 'POST:Module:Billing-bill_element-create') { - // @todo: if is bill element create, create stock movement + /** @var \Modules\Billing\Models\BillElement $new */ + + $transaction->billElement = $new->id; + $transaction->state = StockMovementState::DRAFT; + + // @todo: load default stock movement for bill type/organization settings (default stock location, default lot order e.g. FIFO/LIFO) + // @todo: find stock candidates + + $transaction->type = StockMovementType::TRANSFER; // @todo: depends on bill type + $transaction->quantity = $new->getQuantity(); // @todo may require split quantity if not sufficient available from one lost + + // @todo: allow consignment bills + // @todo: allow to pass stocklocation for entire bill to avoid re-defining it + + // @todo: allow custom stock location + if ($bill->type->sign > 0) { + // Handle from + // @todo: find possible candidate based on defined default stock for bill type/org/location + + // Handle to + if ($bill->client->id !== 0) { + $transaction->to = $bill->client->number; + } elseif ($bill->supplier->id !== 0) { + $transaction->to = $bill->supplier->number; + } + + if ($bill->type->transferType === BillTransferType::SALES) { + $transaction->subtype = StockMovementType::SALE; + } elseif ($bill->type->transferType === BillTransferType::PURCHASE) { + $transaction->subtype = StockMovementType::PURCHASE; + } + } else { + // Handle from + if ($bill->client->id !== 0) { + $transaction->from = $bill->client->number; + } elseif ($bill->supplier->id !== 0) { + $transaction->from = $bill->supplier->number; + } + + // Handle to + // @todo: find possible candidate based on defined default stock for bill type/org/location + + if ($bill->type->transferType === BillTransferType::SALES + || $bill->type->transferType === BillTransferType::PURCHASE + ) { + $transaction->subtype = StockMovementType::RETURN; + } + } + return; } elseif ($trigger === 'POST:Module:Billing-bill_element-update') { - // quantity change - // lot changes - // stock changes - // all other changes ignore! - // check availability again, if not available abort bill + $transactions = StockMovementMapper::getAll() + ->where('billElement', $new->billElement) + ->execute(); + + if ($new->item === $old->item) { + // quantity change + // lot changes + // stock changes + // all other changes ignore! + // check availability again, if not available abort bill + } else { + StockMovementMapper::delete()->execute($transactions); + + $this->eventBillUpdateInternal( + $account, $old, $new, + $type, 'POST:Module:Billing-bill_element-create', $module, $ref, $content, $ip + ); + } + return; } elseif ($trigger === 'POST:Module:Billing-bill_element-delete') { - // @todo: delete stock movement + $transactions = StockMovementMapper::getAll() + ->where('billElement', $new->billElement) + ->execute(); + + StockMovementMapper::delete()->execute($transactions); + return; } elseif ($trigger === 'POST:Module:Billing-bill-delete') { - // @todo: delete stock movements + /** @var \Modules\Billing\Models\Bill $bill */ + $bill = BillMapper::get() + ->with('type') + ->with('elements') + ->with('supplier') + ->with('client') + ->where('id', $new->bill->id) + ->execute(); + + foreach ($bill->elements as $element) { + $transactions = StockMovementMapper::getAll() + ->where('billElement', $element->id) + ->execute(); + + StockMovementMapper::delete()->execute($transactions); + // @todo: consider not to delete but mark as deleted? + } + return; } elseif ($trigger === 'POST:Module:Billing-bill-update') { // is receiver update -> change all movements // is status update -> change all movements (delete = delete) + + if ($new->status === BillStatus::DELETED) { + $this->eventBillUpdateInternal( + $account, $old, $new, + $type, 'POST:Module:Billing-bill-delete', $module, $ref, $content, $ip + ); + } 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) { + $transactions = StockMovementMapper::getAll() + ->where('billElement', $element->id) + ->execute(); + + foreach ($transactions as $transaction) { + $transaction->state = StockMovementState::TRANSIT; // @todo: change to more specific + + StockMovementMapper::update()->execute($transaction); + } + } + } + return; } } diff --git a/Models/StockEvaluation.php b/Models/StockEvaluation.php index 57358b9..44cd3e7 100644 --- a/Models/StockEvaluation.php +++ b/Models/StockEvaluation.php @@ -30,7 +30,7 @@ abstract class StockEvaluation extends Enum public int $type = 0; // lifo, fifo, ... - public int $method = StockEValuationMethod::SPECIFIC_IDENTIFICATION; + public int $method = StockEvaluationMethod::SPECIFIC_IDENTIFICATION; public int $altmethod = StockEvaluationMethod::WEIGHTED_AVERAGE; diff --git a/Models/StockMovement.php b/Models/StockMovement.php index 22e880d..dfb3c9c 100755 --- a/Models/StockMovement.php +++ b/Models/StockMovement.php @@ -51,6 +51,8 @@ class StockMovement public int $billElement = 0; + public int $state = StockMovementState::DRAFT; + /** * Creator. * diff --git a/Models/StockMovementState.php b/Models/StockMovementState.php new file mode 100644 index 0000000..140f78b --- /dev/null +++ b/Models/StockMovementState.php @@ -0,0 +1,40 @@ +