206 lines
7.7 KiB
PHP
206 lines
7.7 KiB
PHP
<?php
|
|
session_start();
|
|
require '../../../assets/utils/db_auth.php';
|
|
|
|
$barcode = trim($data['barcode'] ?? '');
|
|
|
|
if (!$barcode) {
|
|
$answer['message'] = 'No barcode provided.';
|
|
http_response_code(400);
|
|
exit(json_encode($answer));
|
|
}
|
|
|
|
function findProduct(PDO $pdo, int $company_id, string $sku): array|false {
|
|
$sth = $pdo->prepare(
|
|
"SELECT sku, product_name, uom
|
|
FROM md_product
|
|
WHERE company_id = :company_id
|
|
AND sku = :sku
|
|
AND status > 0
|
|
LIMIT 1"
|
|
);
|
|
$sth->execute([':company_id' => $company_id, ':sku' => $sku]);
|
|
return $sth->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
function validateLotSerial(PDO $pdo, int $company_id, string $sku, string $lot, string $serial): void {
|
|
if ($serial === '') return;
|
|
|
|
$warehouses = $pdo->prepare(
|
|
"SELECT id FROM md_warehouse
|
|
WHERE company_id = :company_id AND status = 1"
|
|
);
|
|
$warehouses->execute([':company_id' => $company_id]);
|
|
|
|
foreach ($warehouses->fetchAll(PDO::FETCH_COLUMN) as $warehouse_id) {
|
|
$table = 'td_stock_' . (int)$warehouse_id;
|
|
$sth = $pdo->prepare(
|
|
"SELECT lot_number
|
|
FROM `{$table}`
|
|
WHERE company_id = :company_id
|
|
AND product_sku = :sku
|
|
AND serial_number = :serial
|
|
AND status != -1
|
|
LIMIT 1"
|
|
);
|
|
$sth->execute([':company_id' => $company_id, ':sku' => $sku, ':serial' => $serial]);
|
|
$existing_lot = $sth->fetchColumn();
|
|
if ($existing_lot !== false && (string)$existing_lot !== $lot) {
|
|
throw new Exception('Serial number belongs to a different lot.');
|
|
}
|
|
}
|
|
}
|
|
|
|
function findPreparedLabel(PDO $pdo, int $company_id, string $barcode, string $type): array|false {
|
|
$sth = $pdo->prepare(
|
|
"SELECT *
|
|
FROM md_barcode
|
|
WHERE company_id = :company_id
|
|
AND barcode = :barcode
|
|
AND barcode_type = :barcode_type
|
|
LIMIT 1"
|
|
);
|
|
$sth->execute([
|
|
':company_id' => $company_id,
|
|
':barcode' => $barcode,
|
|
':barcode_type' => $type,
|
|
]);
|
|
$row = $sth->fetch(PDO::FETCH_ASSOC);
|
|
if ($row && (int)$row['status'] !== 1) {
|
|
throw new Exception('Barcode is disabled.');
|
|
}
|
|
return $row ?: false;
|
|
}
|
|
|
|
function advancedLocation(PDO $pdo, int $company_id): bool {
|
|
$sth = $pdo->prepare(
|
|
"SELECT value FROM company_setting
|
|
WHERE company_id = :company_id AND setting_key = 'advanced_location'
|
|
LIMIT 1"
|
|
);
|
|
$sth->execute([':company_id' => $company_id]);
|
|
$value = $sth->fetchColumn();
|
|
return (int)($value === false ? 0 : $value) === 1;
|
|
}
|
|
|
|
function validateLocation(PDO $pdo, int $company_id, int $warehouse_id, string $zone, string $aisle, string $rack): void {
|
|
$sth = $pdo->prepare(
|
|
"SELECT 1 FROM md_rack
|
|
WHERE company_id = :company_id
|
|
AND warehouse = :warehouse
|
|
AND zone = :zone
|
|
AND aisle = :aisle
|
|
AND rack = :rack
|
|
LIMIT 1"
|
|
);
|
|
$sth->execute([
|
|
':company_id' => $company_id,
|
|
':warehouse' => $warehouse_id,
|
|
':zone' => $zone,
|
|
':aisle' => $aisle,
|
|
':rack' => $rack,
|
|
]);
|
|
if (!$sth->fetchColumn()) throw new Exception('Location not found.');
|
|
}
|
|
|
|
$parts = explode('|', $barcode);
|
|
$label_type = strtoupper($parts[0] ?? '');
|
|
|
|
try {
|
|
if ($label_type === 'SKU') {
|
|
if (count($parts) !== 4) throw new Exception('Invalid SKU label format.');
|
|
$sku = trim($parts[1]);
|
|
$lot = trim($parts[2]);
|
|
$serial = trim($parts[3]);
|
|
if ($sku === '' || $lot === '' || $serial === '') throw new Exception('SKU, lot, and serial are required.');
|
|
|
|
$label = findPreparedLabel($pdo2, $company_id, $barcode, 'sku');
|
|
if (!$label) throw new Exception('SKU barcode label was not prepared.');
|
|
if ($label['product_sku'] !== $sku || $label['lot_number'] !== $lot || $label['serial_number'] !== $serial) {
|
|
throw new Exception('SKU barcode label does not match its registry.');
|
|
}
|
|
|
|
$product = findProduct($pdo2, $company_id, $sku);
|
|
if (!$product) throw new Exception('SKU not found.');
|
|
validateLotSerial($pdo2, $company_id, $sku, $lot, $serial);
|
|
|
|
$answer['success'] = 1;
|
|
$answer['type'] = 'sku';
|
|
$answer['sku'] = $product['sku'];
|
|
$answer['product_name'] = $product['product_name'];
|
|
$answer['uom'] = $product['uom'] ?? 'pcs';
|
|
$answer['lot_number'] = $lot;
|
|
$answer['serial_number'] = $serial;
|
|
exit(json_encode($answer));
|
|
}
|
|
|
|
if ($label_type === 'LOC') {
|
|
$advanced = advancedLocation($pdo1, $company_id);
|
|
if ($advanced && count($parts) !== 5) throw new Exception('Invalid advanced location label format.');
|
|
if (!$advanced && count($parts) !== 3) throw new Exception('Invalid location label format.');
|
|
|
|
$warehouse_id = (int)($parts[1] ?? 0);
|
|
if ($advanced) {
|
|
$zone = trim($parts[2]);
|
|
$aisle = trim($parts[3]);
|
|
$rack = trim($parts[4]);
|
|
} else {
|
|
$rack = trim($parts[2]);
|
|
$zone = $rack;
|
|
$aisle = $rack;
|
|
}
|
|
if (!$warehouse_id || $zone === '' || $aisle === '' || $rack === '') throw new Exception('Location label is incomplete.');
|
|
|
|
$label = findPreparedLabel($pdo2, $company_id, $barcode, 'loc');
|
|
if (!$label) throw new Exception('Location barcode label was not prepared.');
|
|
if ((int)$label['warehouse_id'] !== $warehouse_id || $label['zone'] !== $zone || $label['aisle'] !== $aisle || $label['rack'] !== $rack) {
|
|
throw new Exception('Location barcode label does not match its registry.');
|
|
}
|
|
|
|
validateLocation($pdo2, $company_id, $warehouse_id, $zone, $aisle, $rack);
|
|
|
|
$answer['success'] = 1;
|
|
$answer['type'] = 'loc';
|
|
$answer['warehouse_id'] = $warehouse_id;
|
|
$answer['zone'] = $zone;
|
|
$answer['aisle'] = $aisle;
|
|
$answer['rack'] = $rack;
|
|
exit(json_encode($answer));
|
|
}
|
|
} catch (Exception $e) {
|
|
$answer['message'] = $e->getMessage();
|
|
http_response_code(400);
|
|
exit(json_encode($answer));
|
|
}
|
|
|
|
$sth = $pdo2->prepare(
|
|
"SELECT sku, product_name, uom
|
|
FROM md_product
|
|
WHERE company_id = :company_id
|
|
AND (barcode = :barcode OR sku = :sku)
|
|
AND status > 0
|
|
ORDER BY (barcode = :barcode_order) DESC
|
|
LIMIT 1"
|
|
);
|
|
$sth->execute([
|
|
':company_id' => $company_id,
|
|
':barcode' => $barcode,
|
|
':sku' => $barcode,
|
|
':barcode_order' => $barcode,
|
|
]);
|
|
$product = $sth->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$product) {
|
|
$answer['message'] = 'Barcode not found.';
|
|
http_response_code(404);
|
|
exit(json_encode($answer));
|
|
}
|
|
|
|
$answer['success'] = 1;
|
|
$answer['type'] = 'raw';
|
|
$answer['sku'] = $product['sku'];
|
|
$answer['product_name'] = $product['product_name'];
|
|
$answer['uom'] = $product['uom'] ?? 'pcs';
|
|
exit(json_encode($answer));
|
|
?>
|