warehouse layers [switchable]
This commit is contained in:
@@ -78,7 +78,12 @@ class WarehouseManager {
|
||||
$from = trim($from);
|
||||
$to = trim($to);
|
||||
|
||||
// Numeric range
|
||||
// Same value — single location, any format allowed (e.g. "Shelf-A", "Bin-3")
|
||||
if ($from === $to) {
|
||||
return [$from];
|
||||
}
|
||||
|
||||
// Numeric range e.g. 1 → 10
|
||||
if (is_numeric($from) && is_numeric($to)) {
|
||||
$f = (int) $from;
|
||||
$t = (int) $to;
|
||||
@@ -86,15 +91,62 @@ class WarehouseManager {
|
||||
return array_map('strval', range($f, $t));
|
||||
}
|
||||
|
||||
// Single-letter alpha range
|
||||
// Single-letter alpha range e.g. A → Z
|
||||
if (ctype_alpha($from) && ctype_alpha($to)
|
||||
&& strlen($from) === 1 && strlen($to) === 1) {
|
||||
if (ord($from) > ord($to)) throw new Exception("Range start ($from) must be <= end ($to)");
|
||||
return range($from, $to); // PHP range() handles 'A' → 'Z' natively
|
||||
if (ord(strtoupper($from)) > ord(strtoupper($to))) {
|
||||
throw new Exception("Range start ($from) must be <= end ($to)");
|
||||
}
|
||||
return range(strtoupper($from), strtoupper($to));
|
||||
}
|
||||
|
||||
// Prefix + suffix range e.g. Shelf-A → Shelf-E or Bin-1 → Bin-5
|
||||
// Split on the last sequence of digits or single letter at the end
|
||||
$pattern = '/^(.*?)([A-Za-z]|[0-9]+)$/';
|
||||
if (preg_match($pattern, $from, $mf) && preg_match($pattern, $to, $mt)) {
|
||||
$prefix_f = $mf[1];
|
||||
$prefix_t = $mt[1];
|
||||
$suffix_f = $mf[2];
|
||||
$suffix_t = $mt[2];
|
||||
|
||||
// Prefixes must match
|
||||
if ($prefix_f !== $prefix_t) {
|
||||
throw new Exception(
|
||||
"Location prefix mismatch: '$prefix_f' vs '$prefix_t'. " .
|
||||
"From and To must share the same prefix (e.g. Shelf-A → Shelf-E)."
|
||||
);
|
||||
}
|
||||
|
||||
$prefix = $prefix_f;
|
||||
|
||||
// Suffix: numeric range
|
||||
if (is_numeric($suffix_f) && is_numeric($suffix_t)) {
|
||||
$f = (int) $suffix_f;
|
||||
$t = (int) $suffix_t;
|
||||
if ($f > $t) throw new Exception("Range start ($from) must be <= end ($to)");
|
||||
return array_map(fn($n) => $prefix . $n, range($f, $t));
|
||||
}
|
||||
|
||||
// Suffix: single-letter range
|
||||
if (ctype_alpha($suffix_f) && ctype_alpha($suffix_t)
|
||||
&& strlen($suffix_f) === 1 && strlen($suffix_t) === 1) {
|
||||
$sf = strtoupper($suffix_f);
|
||||
$st = strtoupper($suffix_t);
|
||||
if (ord($sf) > ord($st)) {
|
||||
throw new Exception("Range start ($from) must be <= end ($to)");
|
||||
}
|
||||
return array_map(fn($c) => $prefix . $c, range($sf, $st));
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
"Location suffix must be a number (e.g. 1–99) or single letter (e.g. A–Z). " .
|
||||
"Got: '$suffix_f' → '$suffix_t'"
|
||||
);
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
"Aisle/rack values must be either numbers (e.g. 1–99) or single uppercase letters (e.g. A–Z). Got: '$from' → '$to'"
|
||||
"Invalid location range: '$from' → '$to'. " .
|
||||
"Use formats like: 1–10, A–Z, Shelf-1–Shelf-10, or Shelf-A–Shelf-Z."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -848,6 +900,16 @@ class WarehouseManager {
|
||||
*/
|
||||
public function getRacksAll(int $warehouse_id, string $zone, string $aisle): array
|
||||
{
|
||||
if ($zone === '' || $aisle === '') {
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT DISTINCT rack FROM md_rack
|
||||
WHERE company_id = :company_id AND warehouse = :warehouse
|
||||
ORDER BY CAST(rack AS UNSIGNED), rack"
|
||||
);
|
||||
$sth->execute([':company_id' => $this->company_id, ':warehouse' => $warehouse_id]);
|
||||
return array_column($sth->fetchAll(PDO::FETCH_ASSOC), 'rack');
|
||||
}
|
||||
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT DISTINCT rack FROM md_rack
|
||||
WHERE company_id = :company_id AND warehouse = :warehouse AND zone = :zone AND aisle = :aisle
|
||||
@@ -1703,6 +1765,21 @@ class WarehouseManager {
|
||||
*/
|
||||
public function getRacksIn(int $warehouse_id, string $zone, string $aisle): array
|
||||
{
|
||||
if ($zone === '' || $aisle === '') {
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT DISTINCT rack FROM md_rack
|
||||
WHERE company_id = :company_id
|
||||
AND warehouse = :warehouse
|
||||
AND product_sku IS NULL
|
||||
ORDER BY CAST(rack AS UNSIGNED), rack"
|
||||
);
|
||||
$sth->execute([
|
||||
':company_id' => $this->company_id,
|
||||
':warehouse' => $warehouse_id,
|
||||
]);
|
||||
return array_column($sth->fetchAll(PDO::FETCH_ASSOC), 'rack');
|
||||
}
|
||||
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT DISTINCT rack FROM md_rack
|
||||
WHERE company_id = :company_id
|
||||
@@ -1746,17 +1823,20 @@ class WarehouseManager {
|
||||
[$lot_cond, $serial_cond, $params] = $this->buildLotSerialCondition(
|
||||
$warehouse_id, $product_sku, $lot_number, $serial_number
|
||||
);
|
||||
$params[':zone'] = $zone;
|
||||
$params[':aisle'] = $aisle;
|
||||
$location_cond = '';
|
||||
if ($zone !== '' && $aisle !== '') {
|
||||
$location_cond = "AND r.zone = :zone AND r.aisle = :aisle";
|
||||
$params[':zone'] = $zone;
|
||||
$params[':aisle'] = $aisle;
|
||||
}
|
||||
|
||||
$sth = $this->pdo->prepare(
|
||||
"SELECT DISTINCT r.rack
|
||||
FROM md_rack r
|
||||
WHERE r.company_id = :company_id
|
||||
AND r.warehouse = :warehouse
|
||||
AND r.zone = :zone
|
||||
AND r.aisle = :aisle
|
||||
AND r.product_sku = :product_sku
|
||||
{$location_cond}
|
||||
AND r.td_stock_id IN (
|
||||
SELECT s.id FROM `{$table}` s
|
||||
WHERE s.company_id = :company_id2
|
||||
@@ -2055,4 +2135,4 @@ class WarehouseManager {
|
||||
$sth->execute($params);
|
||||
return $sth->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user