fix StockManager lot/serial coercion + add document flow test suite

- StockManager: coerce lot_number/serial_number to trimmed string (fixes
  Array-to-string warnings); validate quantity > 0 on insert; tighten
  transfer pair lookup to match in/out side by column value
- PostingWindowGuard: strip time component from datetime strings before
  date-format validation
- docs/tests/doc_flow_test.php: 32-assertion document flow suite covering
  Stock In create + approve, Sales Order draft/confirm, Invoice from Order
  (with duplicate-block check), PO create/confirm, Quotation create, and
  usage increment wiring check; all 32/32 PASS against wms_codex_test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thanakorn S
2026-05-21 14:20:41 +07:00
co-authored by Claude Sonnet 4.6
parent 6eeebfeacb
commit 94032dd65b
3 changed files with 403 additions and 6 deletions
+12 -5
View File
@@ -233,7 +233,12 @@ class StockManager {
public function saveStockIn(array $data, array $logging, string $uuid): int
{
$id = (int)($data['id'] ?? 0);
$warehouse_id = (int)($data['warehouse'] ?? 0);
$warehouse_id = (int)($data["warehouse"] ?? 0);
$quantity = (float)($data['quantity'] ?? 0);
if ($id === 0 && $quantity <= 0) {
throw new Exception("Quantity must be greater than zero.");
}
$whMgmt = new WarehouseManager($this->pdo, $this->company_id);
$ctx = $whMgmt->getStockContext($warehouse_id, $id);
@@ -267,8 +272,8 @@ class StockManager {
} else {
$lot_number = $data['lot_number'] ?: null;
$expiry_date = $data['expiry_date'] ?: null;
$lot_number = trim((string)($data["lot_number"] ?? ""));
$expiry_date = trim((string)($data["expiry_date"] ?? ""));
// Upsert md_lot: preserve existing expiry_date if already recorded
if ($lot_number && $expiry_date) {
@@ -296,7 +301,7 @@ class StockManager {
':company_id' => $this->company_id,
':date' => date('Y-m-d H:i:s'),
':product_sku' => $data['product_sku'],
':quantity' => $data['quantity'],
':quantity' => $quantity,
':price' => (float)($data['price'] ?? 0),
':zone' => $data['zone'],
':aisle' => $data['aisle'],
@@ -305,7 +310,7 @@ class StockManager {
':description' => $data['description'] ?? '',
':log' => json_encode($table_log),
':lot_number' => $lot_number,
':serial_number' => ($data['serial_number'] ?? null) ?: null,
':serial_number' => trim((string)($data["serial_number"] ?? "")),
]);
$td_stock_id = (int)$this->pdo->lastInsertId();
@@ -788,6 +793,7 @@ class StockManager {
$sth = $this->pdo->prepare(
"SELECT * FROM `{$paired_table}`
WHERE uuid = :uuid AND company_id = :company_id
AND `in` > 0
LIMIT 1"
);
$sth->execute([':uuid' => $row['uuid'], ':company_id' => $this->company_id]);
@@ -798,6 +804,7 @@ class StockManager {
$sth = $this->pdo->prepare(
"SELECT * FROM `{$from_table}`
WHERE uuid = :uuid AND company_id = :company_id
AND `out` > 0
LIMIT 1"
);
$sth->execute([':uuid' => $row['uuid'], ':company_id' => $this->company_id]);