From a0677d6d8d46cc5334745ee1b086b581c25b8b5f Mon Sep 17 00:00:00 2001 From: Thanakorn S Date: Fri, 29 May 2026 08:30:40 +0700 Subject: [PATCH] Classe methods: remove reducdancy --- app/assets/utils/classes/BarcodeManager.php | 4 +- app/assets/utils/classes/ContactManager.php | 11 ++--- app/assets/utils/classes/OrderManager.php | 43 +++++++++-------- app/assets/utils/classes/ProductManager.php | 11 ++--- .../utils/classes/PurchaseOrderManager.php | 47 ++++++++++--------- app/assets/utils/classes/ReturnManager.php | 23 +++------ app/assets/utils/classes/StockTablesTrait.php | 26 ++++++++++ .../utils/classes/SupplierReturnManager.php | 26 +++------- app/assets/utils/classes/WarehouseManager.php | 14 ++++++ 9 files changed, 112 insertions(+), 93 deletions(-) create mode 100644 app/assets/utils/classes/StockTablesTrait.php diff --git a/app/assets/utils/classes/BarcodeManager.php b/app/assets/utils/classes/BarcodeManager.php index eee6bd9..7b011af 100644 --- a/app/assets/utils/classes/BarcodeManager.php +++ b/app/assets/utils/classes/BarcodeManager.php @@ -84,7 +84,7 @@ class BarcodeManager { $warehouses->execute([':company_id' => $this->company_id]); foreach ($warehouses->fetchAll(PDO::FETCH_COLUMN) as $warehouse_id) { - $table = $this->stockTableName((int)$warehouse_id); + $table = 'td_stock_' . (int)$warehouse_id; $sth = $this->pdo->prepare( "SELECT lot_number FROM `{$table}` @@ -169,7 +169,7 @@ class BarcodeManager { $warehouses->execute([':company_id' => $this->company_id]); foreach ($warehouses->fetchAll(PDO::FETCH_COLUMN) as $warehouse_id) { - $table = $this->stockTableName((int)$warehouse_id); + $table = 'td_stock_' . (int)$warehouse_id; $sth = $this->pdo->prepare( "SELECT ROUND(SUM(COALESCE(`in`, 0)) - SUM(COALESCE(`out`, 0)), 2) AS balance FROM `{$table}` diff --git a/app/assets/utils/classes/ContactManager.php b/app/assets/utils/classes/ContactManager.php index f06cd95..41b1d5d 100644 --- a/app/assets/utils/classes/ContactManager.php +++ b/app/assets/utils/classes/ContactManager.php @@ -44,14 +44,11 @@ class ContactManager { private function hasActiveStock(int $contact_id): bool { $sth = $this->pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" + "SELECT table_name FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name LIKE 'td_stock_%'" ); - $sth->execute([':company_id' => $this->company_id]); + $sth->execute(); $tables = $sth->fetchAll(PDO::FETCH_COLUMN); foreach ($tables as $table) { diff --git a/app/assets/utils/classes/OrderManager.php b/app/assets/utils/classes/OrderManager.php index 56c8dba..37df2ec 100644 --- a/app/assets/utils/classes/OrderManager.php +++ b/app/assets/utils/classes/OrderManager.php @@ -86,20 +86,6 @@ class OrderManager { return 'td_stock_' . $warehouse_id; } - private function getStockTables(): array - { - $sth = $this->pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" - ); - $sth->execute([':company_id' => $this->company_id]); - return $sth->fetchAll(PDO::FETCH_COLUMN); - } - /** * FIFO bin pick — find the oldest approved stock-in row for a SKU * in a given warehouse that is still bin-occupied. @@ -198,7 +184,7 @@ class OrderManager { $stock_out_id = (int)($item['stock_out_id'] ?? 0); if ($warehouse_id <= 0 || $stock_out_id <= 0) continue; - $table = $this->stockTableNameFromWarehouseId($warehouse_id); + $table = 'td_stock_' . $warehouse_id; $sth = $this->pdo->prepare( "SELECT status FROM `{$table}` WHERE company_id = :company_id @@ -379,7 +365,7 @@ class OrderManager { $stock_out_id = (int)($item['stock_out_id'] ?? 0); if ($stock_out_warehouse_id > 0 && $stock_out_id > 0) { - $table = $this->stockTableNameFromWarehouseId($stock_out_warehouse_id); + $table = 'td_stock_' . $stock_out_warehouse_id; $sth = $this->pdo->prepare( "SELECT id, status, zone, aisle, bin, lot_number, serial_number FROM `{$table}` @@ -716,6 +702,22 @@ class OrderManager { throw new Exception(implode("\n", $preflight_errors)); } + // Validate all warehouse IDs in one query before entering the item loop. + $itemWarehouseIds = array_values(array_unique(array_filter( + array_map(fn($item) => (int)($item['warehouse_id'] ?? 0), $items), + fn($id) => $id > 0 + ))); + if (!empty($itemWarehouseIds)) { + $placeholders = implode(',', array_fill(0, count($itemWarehouseIds), '?')); + $sth = $this->pdo->prepare( + "SELECT id FROM md_warehouse WHERE company_id = ? AND id IN ($placeholders)" + ); + $sth->execute([$this->company_id, ...$itemWarehouseIds]); + $validWarehouseIds = array_flip($sth->fetchAll(PDO::FETCH_COLUMN)); + } else { + $validWarehouseIds = []; + } + foreach ($items as $i => &$item) { $warehouse_id = (int)($item['warehouse_id'] ?? 0); @@ -725,7 +727,10 @@ class OrderManager { $bin_stock = $this->pickFifoRack($warehouse_id, $product_sku); $available_qty = (float)($bin_stock['available_qty'] ?? $bin_stock['in'] ?? 0); - $table = $this->stockTableNameFromWarehouseId($warehouse_id); + if (!isset($validWarehouseIds[$warehouse_id])) { + throw new Exception("Warehouse ID {$warehouse_id} not found."); + } + $table = 'td_stock_' . $warehouse_id; $item_uuid = $uuid . '_' . $i; $item_log = [array_merge($logging, ['action' => 'confirm_item'])]; @@ -888,8 +893,8 @@ class OrderManager { } // ── Reverse approved stock-out side effects, then soft-delete rows ─ - $tables = $this->getStockTables(); $whMgmt = new WarehouseManager($this->pdo, $this->company_id); + $tables = $whMgmt->getStockTables(); foreach ($tables as $table) { if (!preg_match('/^td_stock_(\d+)$/', (string)$table, $matches)) { @@ -1034,7 +1039,7 @@ class OrderManager { } // Block if any approved stock-out rows exist; user must reverse via ICS first - $tables = $this->getStockTables(); + $tables = (new WarehouseManager($this->pdo, $this->company_id))->getStockTables(); foreach ($tables as $table) { $chk = $this->pdo->prepare( diff --git a/app/assets/utils/classes/ProductManager.php b/app/assets/utils/classes/ProductManager.php index 46291e3..30150dc 100644 --- a/app/assets/utils/classes/ProductManager.php +++ b/app/assets/utils/classes/ProductManager.php @@ -45,14 +45,11 @@ class ProductManager { private function findActiveStock(string $sku): ?string { $sth = $this->pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" + "SELECT table_name FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name LIKE 'td_stock_%'" ); - $sth->execute([':company_id' => $this->company_id]); + $sth->execute(); $tables = $sth->fetchAll(PDO::FETCH_COLUMN); foreach ($tables as $table) { diff --git a/app/assets/utils/classes/PurchaseOrderManager.php b/app/assets/utils/classes/PurchaseOrderManager.php index b890b49..f4d4918 100644 --- a/app/assets/utils/classes/PurchaseOrderManager.php +++ b/app/assets/utils/classes/PurchaseOrderManager.php @@ -1,5 +1,6 @@ getStockTables(); + $tables = (new WarehouseManager($this->pdo, $this->company_id))->getStockTables(); $total = 0; $pending = 0; @@ -149,20 +150,6 @@ class PurchaseOrderManager { return 'td_stock_' . $warehouse_id; } - private function getStockTables(): array - { - $sth = $this->pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" - ); - $sth->execute([':company_id' => $this->company_id]); - return $sth->fetchAll(PDO::FETCH_COLUMN); - } - private function syncPoItems(int $po_id, array $items): void { $this->pdo->prepare( @@ -563,6 +550,22 @@ class PurchaseOrderManager { $stock = new StockManager($this->pdo, $this->company_id); $whMgmt = new WarehouseManager($this->pdo, $this->company_id); + // Validate all warehouse IDs in one query before entering the item loop. + $recvWarehouseIds = array_values(array_unique(array_filter( + array_map(fn($recv) => (int)($recv['warehouse_id'] ?? $po['warehouse_id']), $receive_items), + fn($id) => $id > 0 + ))); + if (!empty($recvWarehouseIds)) { + $placeholders = implode(',', array_fill(0, count($recvWarehouseIds), '?')); + $sth = $this->pdo->prepare( + "SELECT id FROM md_warehouse WHERE company_id = ? AND id IN ($placeholders)" + ); + $sth->execute([$this->company_id, ...$recvWarehouseIds]); + $validWarehouseIds = array_flip($sth->fetchAll(PDO::FETCH_COLUMN)); + } else { + $validWarehouseIds = []; + } + foreach ($receive_items as $j => $recv) { $item_id = (int)($recv['item_id'] ?? -1); $product_sku = $recv['product_sku'] ?? ''; @@ -632,7 +635,10 @@ class PurchaseOrderManager { // saveStockIn() does not write source/source_id — stamp them here. // This links the stock-in row back to this PO for cancellation guards // and makes it appear under the "PO" source tab on the Stock In list. - $table = $this->stockTableNameFromWarehouseId($warehouse_id); + if (!isset($validWarehouseIds[$warehouse_id])) { + throw new Exception("Warehouse ID {$warehouse_id} not found."); + } + $table = 'td_stock_' . $warehouse_id; $this->pdo->prepare( "UPDATE `{$table}` SET source = 'po', source_id = :po_id WHERE id = :id AND company_id = :company_id" @@ -746,7 +752,8 @@ class PurchaseOrderManager { if ($status === -1) throw new Exception("PO is already cancelled."); // Guard: block if any approved stock-in rows exist for this PO - $tables = $this->getStockTables(); + $whMgmt = new WarehouseManager($this->pdo, $this->company_id); + $tables = $whMgmt->getStockTables(); foreach ($tables as $table) { $sth = $this->pdo->prepare( @@ -765,8 +772,6 @@ class PurchaseOrderManager { } } - $whMgmt = new WarehouseManager($this->pdo, $this->company_id); - // Soft-delete draft stock-in rows and release their bin reservations. foreach ($tables as $table) { if (!preg_match('/^td_stock_(\d+)$/', $table, $m)) { @@ -887,7 +892,8 @@ class PurchaseOrderManager { throw new Exception('Cannot delete — this PO has linked supplier returns. Delete or cancel the returns first.'); } - $tables = $this->getStockTables(); + $whMgmt = new WarehouseManager($this->pdo, $this->company_id); + $tables = $whMgmt->getStockTables(); foreach ($tables as $table) { $sth5 = $this->pdo->prepare( @@ -901,7 +907,6 @@ class PurchaseOrderManager { } // Release bins from draft stock-in rows and negate them - $whMgmt = new WarehouseManager($this->pdo, $this->company_id); foreach ($tables as $table) { if (!preg_match('/^td_stock_(\d+)$/', (string)$table, $matches)) continue; $warehouse_id = (int)$matches[1]; diff --git a/app/assets/utils/classes/ReturnManager.php b/app/assets/utils/classes/ReturnManager.php index 87218fc..e68b98a 100644 --- a/app/assets/utils/classes/ReturnManager.php +++ b/app/assets/utils/classes/ReturnManager.php @@ -1,6 +1,7 @@ pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" + "SELECT table_name FROM information_schema.tables + WHERE table_schema = DATABASE() + AND table_name LIKE 'td_stock_%'" ); - $sth->execute([':company_id' => $this->company_id]); + $sth->execute(); $tables = $sth->fetchAll(PDO::FETCH_COLUMN); foreach ($tables as $table) { @@ -749,16 +747,7 @@ class ReturnManager { } // Block if any approved stock-in rows exist; user must reverse via ICS first - $sth = $this->pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" - ); - $sth->execute([':company_id' => $this->company_id]); - $tables = $sth->fetchAll(PDO::FETCH_COLUMN); + $tables = (new WarehouseManager($this->pdo, $this->company_id))->getStockTables(); foreach ($tables as $table) { $chk = $this->pdo->prepare( diff --git a/app/assets/utils/classes/StockTablesTrait.php b/app/assets/utils/classes/StockTablesTrait.php new file mode 100644 index 0000000..feeb65b --- /dev/null +++ b/app/assets/utils/classes/StockTablesTrait.php @@ -0,0 +1,26 @@ +pdo PDO + * $this->company_id int + */ +trait StockTablesTrait +{ + private function getStockTables(): array + { + $sth = $this->pdo->prepare( + "SELECT t.table_name + FROM md_warehouse w + JOIN information_schema.tables t + ON t.table_schema = DATABASE() + AND t.table_name = CONCAT('td_stock_', w.id) + WHERE w.company_id = :company_id" + ); + $sth->execute([':company_id' => $this->company_id]); + return $sth->fetchAll(PDO::FETCH_COLUMN); + } +} diff --git a/app/assets/utils/classes/SupplierReturnManager.php b/app/assets/utils/classes/SupplierReturnManager.php index 80f72ac..5538fcc 100644 --- a/app/assets/utils/classes/SupplierReturnManager.php +++ b/app/assets/utils/classes/SupplierReturnManager.php @@ -1,6 +1,8 @@ pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" - ); - $sth->execute([':company_id' => $this->company_id]); - $tables = $sth->fetchAll(PDO::FETCH_COLUMN); + $tables = $this->getStockTables(); $has_stock_out = false; $has_draft = false; @@ -650,16 +645,7 @@ class SupplierReturnManager { } // Block if any approved stock-out rows exist; user must reverse via ICS first - $sth = $this->pdo->prepare( - "SELECT t.table_name - FROM md_warehouse w - JOIN information_schema.tables t - ON t.table_schema = DATABASE() - AND t.table_name = CONCAT('td_stock_', w.id) - WHERE w.company_id = :company_id" - ); - $sth->execute([':company_id' => $this->company_id]); - $tables = $sth->fetchAll(PDO::FETCH_COLUMN); + $tables = $this->getStockTables(); foreach ($tables as $table) { $chk = $this->pdo->prepare( diff --git a/app/assets/utils/classes/WarehouseManager.php b/app/assets/utils/classes/WarehouseManager.php index cb5dd67..b775199 100644 --- a/app/assets/utils/classes/WarehouseManager.php +++ b/app/assets/utils/classes/WarehouseManager.php @@ -52,6 +52,20 @@ class WarehouseManager { return 'td_stock_' . $warehouse_id; } + public function getStockTables(): array + { + $sth = $this->pdo->prepare( + "SELECT t.table_name + FROM md_warehouse w + JOIN information_schema.tables t + ON t.table_schema = DATABASE() + AND t.table_name = CONCAT('td_stock_', w.id) + WHERE w.company_id = :company_id" + ); + $sth->execute([':company_id' => $this->company_id]); + return $sth->fetchAll(PDO::FETCH_COLUMN); + } + public function assertStockMovementWindow(?string $date, string $context = 'Stock movement'): void { global $pdo1;