Change 'Rack' to 'Bin'
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
* Dashboard reports → stats, movement charts, most moved, recent activity
|
||||
* Warehouse detail → capacity, space used, balance, movement, trend, activity
|
||||
* Expiry reports → expired / near-expiry stock
|
||||
* Lot / Rack reports → lot stock log, product lots, rack log, rack occupancy
|
||||
* Lot / Bin reports → lot stock log, product lots, bin log, bin occupancy
|
||||
* Balance summary → getWarehouseBalanceSummary
|
||||
*
|
||||
* Security: All SQL uses PDO prepared statements with bound parameters.
|
||||
@@ -159,25 +159,25 @@ class ReportManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Total rack capacity (all racks across all warehouses) for this company.
|
||||
* Total bin capacity (all bins across all warehouses) for this company.
|
||||
* Used by the reports_stats dashboard tile.
|
||||
*/
|
||||
public function getTotalCapacity(): int
|
||||
{
|
||||
$sql = "SELECT COUNT(*)
|
||||
FROM md_rack
|
||||
FROM md_bin
|
||||
WHERE company_id = :company_id";
|
||||
return (int) $this->fetchScalar($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of occupied racks (product_sku IS NOT NULL) for this company.
|
||||
* Number of occupied bins (product_sku IS NOT NULL) for this company.
|
||||
* Used by the reports_stats dashboard tile.
|
||||
*/
|
||||
public function getSpaceUsed(): int
|
||||
{
|
||||
$sql = "SELECT COUNT(*)
|
||||
FROM md_rack
|
||||
FROM md_bin
|
||||
WHERE company_id = :company_id
|
||||
AND product_sku IS NOT NULL";
|
||||
return (int) $this->fetchScalar($sql);
|
||||
@@ -710,15 +710,15 @@ class ReportManager
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Total rack capacity for a specific warehouse (all racks regardless of occupancy).
|
||||
* Total bin capacity for a specific warehouse (all bins regardless of occupancy).
|
||||
*
|
||||
* @param int $warehouse_id The warehouse to query.
|
||||
* @return int Total rack count.
|
||||
* @return int Total bin count.
|
||||
*/
|
||||
public function getWarehouseCapacity(int $warehouse_id): int
|
||||
{
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT COUNT(*) FROM md_rack
|
||||
"SELECT COUNT(*) FROM md_bin
|
||||
WHERE company_id = :company_id AND warehouse = :warehouse_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':warehouse_id' => $warehouse_id]);
|
||||
@@ -726,15 +726,15 @@ class ReportManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of occupied racks (product_sku IS NOT NULL) for a specific warehouse.
|
||||
* Number of occupied bins (product_sku IS NOT NULL) for a specific warehouse.
|
||||
*
|
||||
* @param int $warehouse_id The warehouse to query.
|
||||
* @return int Occupied rack count.
|
||||
* @return int Occupied bin count.
|
||||
*/
|
||||
public function getWarehouseSpaceUsed(int $warehouse_id): int
|
||||
{
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT COUNT(*) FROM md_rack
|
||||
"SELECT COUNT(*) FROM md_bin
|
||||
WHERE company_id = :company_id AND warehouse = :warehouse_id
|
||||
AND product_sku IS NOT NULL"
|
||||
);
|
||||
@@ -1008,14 +1008,14 @@ class ReportManager
|
||||
s.lot_number,
|
||||
s.zone,
|
||||
s.aisle,
|
||||
s.rack,
|
||||
s.bin,
|
||||
ROUND(SUM(s.`in`) - SUM(s.`out`), 2) AS quantity,
|
||||
{$wh['id']} AS warehouse_id
|
||||
FROM `{$table}` s
|
||||
WHERE s.company_id = {$cid}
|
||||
AND s.lot_number IS NOT NULL
|
||||
AND s.status = 1
|
||||
GROUP BY s.product_sku, s.lot_number, s.zone, s.aisle, s.rack
|
||||
GROUP BY s.product_sku, s.lot_number, s.zone, s.aisle, s.bin
|
||||
HAVING quantity > 0";
|
||||
},
|
||||
$warehouses
|
||||
@@ -1026,7 +1026,7 @@ class ReportManager
|
||||
stock.lot_number,
|
||||
stock.zone,
|
||||
stock.aisle,
|
||||
stock.rack,
|
||||
stock.bin,
|
||||
stock.quantity,
|
||||
l.expiry_date,
|
||||
DATEDIFF(l.expiry_date, CURDATE()) AS days_remaining,
|
||||
@@ -1073,7 +1073,7 @@ class ReportManager
|
||||
'lot_number' => $row['lot_number'],
|
||||
'zone' => $row['zone'],
|
||||
'aisle' => $row['aisle'],
|
||||
'rack' => $row['rack'],
|
||||
'bin' => $row['bin'],
|
||||
'quantity' => (float) $row['quantity'],
|
||||
'expiry_date' => $row['expiry_date'],
|
||||
'days_remaining' => $days,
|
||||
@@ -1085,7 +1085,7 @@ class ReportManager
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// REPORT BASIS — Lot / Rack reports
|
||||
// REPORT BASIS — Lot / Bin reports
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -1097,7 +1097,7 @@ class ReportManager
|
||||
*
|
||||
* @param string $product_sku SKU to filter by.
|
||||
* @param string $lot_number Lot number to filter by.
|
||||
* @return array Stock rows with date, type, zone/aisle/rack, in/out amounts, warehouse_name.
|
||||
* @return array Stock rows with date, type, zone/aisle/bin, in/out amounts, warehouse_name.
|
||||
*/
|
||||
public function getLotStockLog(string $product_sku, string $lot_number): array
|
||||
{
|
||||
@@ -1123,7 +1123,7 @@ class ReportManager
|
||||
s.type,
|
||||
s.zone,
|
||||
s.aisle,
|
||||
s.rack,
|
||||
s.bin,
|
||||
ROUND(COALESCE(s.`in`, 0), 2) AS stock_in,
|
||||
ROUND(COALESCE(s.`out`, 0), 2) AS stock_out,
|
||||
s.serial_number,
|
||||
@@ -1247,21 +1247,21 @@ class ReportManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the action log for a specific rack, with user name.
|
||||
* Return the action log for a specific bin, with user name.
|
||||
*
|
||||
* Used by the rack log dashboard report page.
|
||||
* Used by the bin log dashboard report page.
|
||||
* Joins the wms.user table for the acting user's name.
|
||||
*
|
||||
* Security fix: the database name is now fetched once via a bound query
|
||||
* and stored as $db_name (string), then used as a backtick-quoted identifier
|
||||
* rather than being embedded in the JOIN without escaping.
|
||||
*
|
||||
* @param int $rack_id The md_rack.id to fetch logs for (0 returns empty array).
|
||||
* @param int $bin_id The md_bin.id to fetch logs for (0 returns empty array).
|
||||
* @return array Log rows with dt, action, product_sku, td_stock_id, login, user_name.
|
||||
*/
|
||||
public function getRackLog(int $rack_id): array
|
||||
public function getBinLog(int $bin_id): array
|
||||
{
|
||||
if (!$rack_id) return [];
|
||||
if (!$bin_id) return [];
|
||||
|
||||
$main_db = $this->mainDb;
|
||||
if ($main_db === '' || !ctype_alnum(str_replace('_', '', $main_db))) {
|
||||
@@ -1277,30 +1277,30 @@ class ReportManager
|
||||
rl.td_stock_id,
|
||||
rl.login,
|
||||
u.name AS user_name
|
||||
FROM td_rack_log rl
|
||||
FROM td_bin_log rl
|
||||
LEFT JOIN `{$main_db}`.user u
|
||||
ON u.user_id = rl.user_id
|
||||
WHERE rl.company_id = :company_id
|
||||
AND rl.md_rack_id = :rack_id
|
||||
AND rl.md_bin_id = :bin_id
|
||||
ORDER BY rl.dt DESC"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':rack_id' => $rack_id,
|
||||
':bin_id' => $bin_id,
|
||||
]);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all rack slots across all warehouses with occupancy status,
|
||||
* Return all bin slots across all warehouses with occupancy status,
|
||||
* warehouse name, and product name.
|
||||
*
|
||||
* Used by the rack occupancy dashboard report page to visualise which
|
||||
* racks are empty vs occupied and which product is in each slot.
|
||||
* Results are ordered by warehouse → zone → aisle → rack with
|
||||
* Used by the bin occupancy dashboard report page to visualise which
|
||||
* bins are empty vs occupied and which product is in each slot.
|
||||
* Results are ordered by warehouse → zone → aisle → bin with
|
||||
* numeric-first sorting via CAST.
|
||||
*
|
||||
* @return array All md_rack rows joined to warehouse and product with 'status' field.
|
||||
* @return array All md_bin rows joined to warehouse and product with 'status' field.
|
||||
*/
|
||||
public function getRackOccupancy(): array
|
||||
{
|
||||
@@ -1309,14 +1309,14 @@ class ReportManager
|
||||
r.id,
|
||||
r.zone,
|
||||
r.aisle,
|
||||
r.rack,
|
||||
r.bin,
|
||||
r.product_sku,
|
||||
r.td_stock_id,
|
||||
mw.warehouse_name,
|
||||
mw.id AS warehouse_id,
|
||||
p.product_name,
|
||||
CASE WHEN r.product_sku IS NOT NULL THEN 'occupied' ELSE 'empty' END AS status
|
||||
FROM md_rack r
|
||||
FROM md_bin r
|
||||
INNER JOIN md_warehouse mw
|
||||
ON mw.company_id = r.company_id
|
||||
AND mw.id = r.warehouse
|
||||
@@ -1326,7 +1326,7 @@ class ReportManager
|
||||
WHERE r.company_id = :company_id
|
||||
ORDER BY mw.warehouse_name, r.zone,
|
||||
CAST(r.aisle AS UNSIGNED), r.aisle,
|
||||
CAST(r.rack AS UNSIGNED), r.rack"
|
||||
CAST(r.bin AS UNSIGNED), r.bin"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -1510,7 +1510,7 @@ class ReportManager
|
||||
s.serial_number,
|
||||
s.zone,
|
||||
s.aisle,
|
||||
s.rack,
|
||||
s.bin,
|
||||
ROUND(COALESCE(s.`in`, 0), 2) AS stock_in,
|
||||
ROUND(COALESCE(s.`out`, 0), 2) AS stock_out,
|
||||
CASE
|
||||
|
||||
Reference in New Issue
Block a user