Fix incomplete Rack→Bin rename: missing file renames, stale UI labels, ReportManager property bug
- Rename rack_log.php → bin_log.php and rack_occupancy.php → bin_occupancy.php (occupy_rack.php was already calling bin_*.php, causing 404 on every load) - Fix occupy_rack.php: page title, stat card label (add id="stat_label_bins"), section headings, and <th> column headers still read "Rack/Racks" - Fix ReportManager: constructor wrote to $this->companyId (dynamic property) instead of the declared $this->company_id, causing all queries to filter on company_id = 0 under strict PHP 8.2+ property semantics Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
8f57ab5570
commit
5df67367fa
@@ -27,7 +27,7 @@ class ReportManager
|
||||
public function __construct(PDO $pdo, int $company_id, string $mainDb = '')
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
$this->companyId = $company_id;
|
||||
$this->company_id = $company_id;
|
||||
$this->mainDb = $mainDb;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ class ReportManager
|
||||
"SELECT id FROM md_warehouse
|
||||
WHERE company_id = :company_id AND id = :id AND status = 1"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':id' => $warehouse_id]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':id' => $warehouse_id]);
|
||||
$id = $sth->fetchColumn();
|
||||
if (!$id) return null;
|
||||
|
||||
@@ -70,7 +70,7 @@ class ReportManager
|
||||
private function fetchScalar(string $sql)
|
||||
{
|
||||
$sth = $this->pdo->prepare($sql);
|
||||
$sth->execute([":company_id" => $this->companyId]);
|
||||
$sth->execute([":company_id" => $this->company_id]);
|
||||
return $sth->fetchColumn();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class ReportManager
|
||||
private function fetchAll(string $sql): array
|
||||
{
|
||||
$sth = $this->pdo->prepare($sql);
|
||||
$sth->execute([":company_id" => $this->companyId]);
|
||||
$sth->execute([":company_id" => $this->company_id]);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ class ReportManager
|
||||
FROM etl_stock_summary
|
||||
WHERE company_id = :company_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
return $sth->fetch(PDO::FETCH_ASSOC) ?: ['total_in' => 0, 'total_out' => 0];
|
||||
}
|
||||
|
||||
@@ -329,7 +329,7 @@ class ReportManager
|
||||
WHERE company_id = :company_id
|
||||
AND status != -1"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
[$total_orders, $total_revenue] = $sth->fetch(PDO::FETCH_NUM) ?: [0, 0];
|
||||
|
||||
return [
|
||||
@@ -346,7 +346,7 @@ class ReportManager
|
||||
AND doc_type = 'invoice'
|
||||
AND status IN (0, 1, 3)"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
$unpaid_invoices = (int)$sth->fetchColumn();
|
||||
|
||||
$sth = $this->pdo->prepare(
|
||||
@@ -354,7 +354,7 @@ class ReportManager
|
||||
WHERE company_id = :company_id
|
||||
AND status = 0"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
$pending_returns = (int)$sth->fetchColumn();
|
||||
|
||||
return [
|
||||
@@ -497,7 +497,7 @@ class ReportManager
|
||||
WHERE company_id = :company_id
|
||||
AND month = :month"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':month' => $month]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':month' => $month]);
|
||||
return $sth->fetch(PDO::FETCH_ASSOC) ?: [
|
||||
'total_in' => 0, 'total_out' => 0, 'active_products' => 0
|
||||
];
|
||||
@@ -524,7 +524,7 @@ class ReportManager
|
||||
WHERE wb.company_id = :company_id
|
||||
GROUP BY wb.product_sku, mp.min_stock"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
$count = 0;
|
||||
foreach ($rows as $row) {
|
||||
@@ -560,7 +560,7 @@ class ReportManager
|
||||
ORDER BY month ASC"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':company_id' => $this->company_id,
|
||||
':start' => $start,
|
||||
':end' => $end,
|
||||
]);
|
||||
@@ -616,7 +616,7 @@ class ReportManager
|
||||
LIMIT {$limit}"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':company_id' => $this->company_id,
|
||||
':month' => $month,
|
||||
]);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -637,7 +637,7 @@ class ReportManager
|
||||
WHERE company_id = :company_id
|
||||
ORDER BY month DESC"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
return $sth->fetchAll(PDO::FETCH_COLUMN);
|
||||
}
|
||||
|
||||
@@ -657,7 +657,7 @@ class ReportManager
|
||||
"SELECT id, warehouse_name FROM md_warehouse
|
||||
WHERE company_id = :company_id AND status = 1"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
$warehouses = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($warehouses)) return [];
|
||||
@@ -665,7 +665,7 @@ class ReportManager
|
||||
$unions = implode("\nUNION ALL\n", array_map(
|
||||
function ($wh) {
|
||||
$table = $this->stockTableNameFromWarehouseId((int)$wh['id']);
|
||||
$cid = (int) $this->companyId;
|
||||
$cid = (int) $this->company_id;
|
||||
$warehouse_name = $this->pdo->quote($wh['warehouse_name']);
|
||||
return "SELECT s.date, s.product_sku, s.type,
|
||||
ROUND(COALESCE(s.`in`, 0), 2) AS stock_in,
|
||||
@@ -721,7 +721,7 @@ class ReportManager
|
||||
"SELECT COUNT(*) FROM md_bin
|
||||
WHERE company_id = :company_id AND warehouse = :warehouse_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':warehouse_id' => $warehouse_id]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':warehouse_id' => $warehouse_id]);
|
||||
return (int) $sth->fetchColumn();
|
||||
}
|
||||
|
||||
@@ -738,7 +738,7 @@ class ReportManager
|
||||
WHERE company_id = :company_id AND warehouse = :warehouse_id
|
||||
AND product_sku IS NOT NULL"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':warehouse_id' => $warehouse_id]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':warehouse_id' => $warehouse_id]);
|
||||
return (int) $sth->fetchColumn();
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@ class ReportManager
|
||||
FROM etl_stock_summary
|
||||
WHERE company_id = :company_id AND warehouse_id = :warehouse_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':warehouse_id' => $warehouse_id]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':warehouse_id' => $warehouse_id]);
|
||||
return $sth->fetch(PDO::FETCH_ASSOC) ?: ['total_in' => 0, 'total_out' => 0];
|
||||
}
|
||||
|
||||
@@ -783,7 +783,7 @@ class ReportManager
|
||||
AND wb.warehouse_id = :warehouse_id
|
||||
GROUP BY wb.product_sku, mp.min_stock"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':warehouse_id' => $warehouse_id]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':warehouse_id' => $warehouse_id]);
|
||||
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
$count = 0;
|
||||
foreach ($rows as $row) {
|
||||
@@ -823,7 +823,7 @@ class ReportManager
|
||||
ORDER BY sort_key ASC"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':company_id' => $this->company_id,
|
||||
':start' => $start,
|
||||
':end' => $end,
|
||||
]);
|
||||
@@ -870,7 +870,7 @@ class ReportManager
|
||||
FROM `{$table}`
|
||||
WHERE company_id = :company_id AND status = 1 AND date < :start"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':start' => $start]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':start' => $start]);
|
||||
$running = (float)$sth->fetchColumn();
|
||||
|
||||
$sth = $this->pdo->prepare(
|
||||
@@ -885,7 +885,7 @@ class ReportManager
|
||||
ORDER BY sort_key ASC"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':company_id' => $this->company_id,
|
||||
':start' => $start,
|
||||
':end' => $end,
|
||||
]);
|
||||
@@ -935,7 +935,7 @@ class ReportManager
|
||||
ORDER BY a.date DESC, a.id DESC
|
||||
LIMIT 10"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
|
||||
$activities = [];
|
||||
foreach ($sth->fetchAll(PDO::FETCH_ASSOC) as $row) {
|
||||
@@ -986,19 +986,19 @@ class ReportManager
|
||||
"SELECT id, warehouse_name FROM md_warehouse
|
||||
WHERE company_id = :company_id AND status = 1 AND id = :warehouse_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':warehouse_id' => $warehouse_id]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':warehouse_id' => $warehouse_id]);
|
||||
} else {
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT id, warehouse_name FROM md_warehouse
|
||||
WHERE company_id = :company_id AND status = 1"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
}
|
||||
$warehouses = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if (empty($warehouses)) return [];
|
||||
|
||||
$cid = (int) $this->companyId; // cast before interpolation
|
||||
$cid = (int) $this->company_id; // cast before interpolation
|
||||
|
||||
$unions = implode("\nUNION ALL\n", array_map(
|
||||
function ($wh) use ($cid) {
|
||||
@@ -1107,7 +1107,7 @@ class ReportManager
|
||||
"SELECT id, warehouse_name FROM md_warehouse
|
||||
WHERE company_id = :company_id AND status = 1"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
$warehouses = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$rows = [];
|
||||
@@ -1137,7 +1137,7 @@ class ReportManager
|
||||
ORDER BY s.date DESC"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':company_id' => $this->company_id,
|
||||
':product_sku' => $product_sku,
|
||||
':lot_number' => $lot_number,
|
||||
]);
|
||||
@@ -1169,13 +1169,13 @@ class ReportManager
|
||||
"SELECT id, warehouse_name FROM md_warehouse
|
||||
WHERE company_id = :company_id AND status = 1"
|
||||
);
|
||||
$warehouses->execute([':company_id' => $this->companyId]);
|
||||
$warehouses->execute([':company_id' => $this->company_id]);
|
||||
$wh_list = $warehouses->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Build per-lot balance by summing approved td_stock rows across all warehouses.
|
||||
// etl_stock_summary is per-product, not per-lot, so we query td_stock directly.
|
||||
$lot_balance = [];
|
||||
$cid = (int) $this->companyId;
|
||||
$cid = (int) $this->company_id;
|
||||
|
||||
foreach ($wh_list as $wh) {
|
||||
$table = $this->stockTableNameFromWarehouseId((int)$wh['id']);
|
||||
@@ -1211,7 +1211,7 @@ class ReportManager
|
||||
WHERE l.company_id = :company_id
|
||||
ORDER BY l.product_sku, l.expiry_date ASC"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$active = $expired = $near = 0;
|
||||
@@ -1285,7 +1285,7 @@ class ReportManager
|
||||
ORDER BY rl.dt DESC"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->companyId,
|
||||
':company_id' => $this->company_id,
|
||||
':bin_id' => $bin_id,
|
||||
]);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
@@ -1328,7 +1328,7 @@ class ReportManager
|
||||
CAST(r.aisle AS UNSIGNED), r.aisle,
|
||||
CAST(r.bin AS UNSIGNED), r.bin"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
@@ -1353,7 +1353,7 @@ class ReportManager
|
||||
FROM etl_stock_summary
|
||||
WHERE company_id = :company_id"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId]);
|
||||
$sth->execute([':company_id' => $this->company_id]);
|
||||
return $sth->fetch(PDO::FETCH_ASSOC) ?: [];
|
||||
}
|
||||
|
||||
@@ -1409,7 +1409,7 @@ class ReportManager
|
||||
AND date BETWEEN :date_from AND :date_to
|
||||
ORDER BY product_sku ASC"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':date_from' => $date_from, ':date_to' => $date_to]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':date_from' => $date_from, ':date_to' => $date_to]);
|
||||
$skus = $sth->fetchAll(PDO::FETCH_COLUMN);
|
||||
|
||||
// Summary stats across full range
|
||||
@@ -1423,7 +1423,7 @@ class ReportManager
|
||||
AND status = 1
|
||||
AND date BETWEEN :date_from AND :date_to"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':date_from' => $date_from, ':date_to' => $date_to]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':date_from' => $date_from, ':date_to' => $date_to]);
|
||||
$stats = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
return [
|
||||
@@ -1477,7 +1477,7 @@ class ReportManager
|
||||
AND status = 1
|
||||
AND date < :date_from"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':sku' => $product_sku, ':date_from' => $date_from]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':sku' => $product_sku, ':date_from' => $date_from]);
|
||||
$bf = $sth->fetch(PDO::FETCH_ASSOC);
|
||||
$bf_in = (float)($bf['bf_in'] ?? 0);
|
||||
$bf_out = (float)($bf['bf_out'] ?? 0);
|
||||
@@ -1488,7 +1488,7 @@ class ReportManager
|
||||
"SELECT product_name, uom FROM md_product
|
||||
WHERE company_id = :company_id AND sku = :sku LIMIT 1"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':sku' => $product_sku]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':sku' => $product_sku]);
|
||||
$product_row = $sth->fetch(PDO::FETCH_ASSOC) ?: [];
|
||||
$product_name = $product_row['product_name'] ?: $product_sku;
|
||||
$product_uom = $product_row['uom'] ?? '';
|
||||
@@ -1538,7 +1538,7 @@ class ReportManager
|
||||
AND s.date BETWEEN :date_from AND :date_to
|
||||
ORDER BY s.date ASC, s.id ASC"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->companyId, ':sku' => $product_sku, ':date_from' => $date_from, ':date_to' => $date_to]);
|
||||
$sth->execute([':company_id' => $this->company_id, ':sku' => $product_sku, ':date_from' => $date_from, ':date_to' => $date_to]);
|
||||
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// Append running_total and margin to each row.
|
||||
|
||||
+10
-10
@@ -17,7 +17,7 @@
|
||||
<div class="col-12">
|
||||
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-5 gap-3">
|
||||
<div>
|
||||
<h1 class="fs-3 mb-1">Rack Occupancy</h1>
|
||||
<h1 class="fs-3 mb-1">Bin Occupancy</h1>
|
||||
<p class="mb-0">View occupied and available bin positions across all warehouses</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -34,7 +34,7 @@
|
||||
<i class="ti ti-box-seam fs-4"></i>
|
||||
</div>
|
||||
<div>
|
||||
<span>Total Racks</span>
|
||||
<span id="stat_label_bins">Total Bins</span>
|
||||
<h2 class="fw-bold mb-0" id="stat_total">—</h2>
|
||||
</div>
|
||||
</div>
|
||||
@@ -111,7 +111,7 @@
|
||||
<div class="card-body p-6">
|
||||
<div class="mb-6 d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h3 class="mb-1 fs-4">All Racks</h3>
|
||||
<h3 class="mb-1 fs-4">All Bins</h3>
|
||||
<p class="mb-0">Complete bin list across all warehouses</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,7 +131,7 @@
|
||||
<th>Warehouse</th>
|
||||
<th class="th_loc_zone">Zone</th>
|
||||
<th class="th_loc_aisle">Aisle</th>
|
||||
<th class="th_loc_bin">Rack</th>
|
||||
<th class="th_loc_bin">Bin</th>
|
||||
<th>SKU</th>
|
||||
<th>Product</th>
|
||||
<th>Status</th>
|
||||
@@ -154,8 +154,8 @@
|
||||
<div class="card-body p-6">
|
||||
<div class="mb-6 d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h3 class="mb-1 fs-4">Occupied Racks</h3>
|
||||
<p class="mb-0">Racks currently holding stock</p>
|
||||
<h3 class="mb-1 fs-4">Occupied Bins</h3>
|
||||
<p class="mb-0">Bins currently holding stock</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12 mb-5">
|
||||
@@ -174,7 +174,7 @@
|
||||
<th>Warehouse</th>
|
||||
<th class="th_loc_zone">Zone</th>
|
||||
<th class="th_loc_aisle">Aisle</th>
|
||||
<th class="th_loc_bin">Rack</th>
|
||||
<th class="th_loc_bin">Bin</th>
|
||||
<th>SKU</th>
|
||||
<th>Product</th>
|
||||
<th>Action</th>
|
||||
@@ -196,8 +196,8 @@
|
||||
<div class="card-body p-6">
|
||||
<div class="mb-6 d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h3 class="mb-1 fs-4">Available Racks</h3>
|
||||
<p class="mb-0">Empty racks ready to receive stock</p>
|
||||
<h3 class="mb-1 fs-4">Available Bins</h3>
|
||||
<p class="mb-0">Empty bins ready to receive stock</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12 mb-5">
|
||||
@@ -216,7 +216,7 @@
|
||||
<th>Warehouse</th>
|
||||
<th class="th_loc_zone">Zone</th>
|
||||
<th class="th_loc_aisle">Aisle</th>
|
||||
<th class="th_loc_bin">Rack</th>
|
||||
<th class="th_loc_bin">Bin</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
Reference in New Issue
Block a user