223 lines
9.9 KiB
PHP
223 lines
9.9 KiB
PHP
<?php
|
|
session_start();
|
|
require '../../../assets/utils/db_auth.php';
|
|
require '../../../assets/utils/classes/WarehouseManager.php';
|
|
|
|
try {
|
|
|
|
dbTransaction($pdo2, function($pdo) use ($data, $company_id, $logging, $uuid) {
|
|
|
|
$id = (int)($data['id'] ?? 0);
|
|
$whMgmt = new WarehouseManager($pdo, $company_id);
|
|
|
|
// Metadata that's editable on BOTH create and edit
|
|
$contact_id = (int)($data['contact_id'] ?? 0);
|
|
$description = ($data['description'] ?? '');
|
|
|
|
// ══════════════════════════════════════════════════════════
|
|
// EDIT FLOW
|
|
// Physical state (racks, balances, quantities) is frozen.
|
|
// Only metadata (contact, description) can change.
|
|
// ══════════════════════════════════════════════════════════
|
|
if ($id > 0) {
|
|
|
|
// Find the "from" row that's being edited.
|
|
// We look it up across all td_stock_<wh> via warehouse_from
|
|
// since $id alone isn't enough (it's per-table).
|
|
$from_warehouse = (int)($data['warehouse_from'] ?? 0);
|
|
$to_warehouse = (int)($data['warehouse_to'] ?? 0);
|
|
|
|
$from_ctx = $whMgmt->getStockContext($from_warehouse, $id);
|
|
$from_table = $from_ctx['table'];
|
|
$from_row = $from_ctx['row'];
|
|
|
|
if (!$from_row) {
|
|
throw new Exception("Transfer record not found.");
|
|
}
|
|
|
|
// Find the paired "to" row via ref_id stored on the "from" row
|
|
$to_id = (int) $from_row['ref_id'];
|
|
$to_ctx = $whMgmt->getStockContext($to_warehouse, $to_id);
|
|
$to_table = $to_ctx['table'];
|
|
$to_row = $to_ctx['row'];
|
|
|
|
if (!$to_row) {
|
|
throw new Exception("Paired destination record missing — data integrity issue.");
|
|
}
|
|
|
|
// Append this edit to both rows' logs
|
|
$from_log = json_decode($from_row['log'] ?? '[]', true) ?: [];
|
|
$from_log[] = $logging;
|
|
|
|
$to_log = json_decode($to_row['log'] ?? '[]', true) ?: [];
|
|
$to_log[] = $logging;
|
|
|
|
// UPDATE "from" row — only metadata fields
|
|
$sql = "UPDATE `$from_table` SET
|
|
contact_id = :contact_id,
|
|
description = :description,
|
|
`log` = :log
|
|
WHERE id = :id AND company_id = :company_id";
|
|
$pdo->prepare($sql)->execute([
|
|
":contact_id" => $contact_id,
|
|
":description" => $description,
|
|
":log" => json_encode($from_log),
|
|
":id" => $id,
|
|
":company_id" => $company_id,
|
|
]);
|
|
|
|
// UPDATE "to" row — same metadata
|
|
$sql = "UPDATE `$to_table` SET
|
|
contact_id = :contact_id,
|
|
description = :description,
|
|
`log` = :log
|
|
WHERE id = :id AND company_id = :company_id";
|
|
$pdo->prepare($sql)->execute([
|
|
":contact_id" => $contact_id,
|
|
":description" => $description,
|
|
":log" => json_encode($to_log),
|
|
":id" => $to_id,
|
|
":company_id" => $company_id,
|
|
]);
|
|
|
|
// Done — no rack ops, no balance changes on edit.
|
|
return;
|
|
}
|
|
|
|
// ══════════════════════════════════════════════════════════
|
|
// CREATE FLOW (unchanged from before)
|
|
// ══════════════════════════════════════════════════════════
|
|
|
|
// Gather source + destination parameters
|
|
$from_warehouse = (int)$data['warehouse_from'];
|
|
$from_zone = $data['zone_from'];
|
|
$from_aisle = $data['aisle_from'];
|
|
$from_rack = $data['rack_from'];
|
|
|
|
$to_warehouse = (int)$data['warehouse_to'];
|
|
$to_zone = $data['zone_to'];
|
|
$to_aisle = $data['aisle_to'];
|
|
$to_rack = $data['rack_to'];
|
|
|
|
// Validate source rack has stock of the expected SKU.
|
|
// Quantity comes from here — NOT user input.
|
|
$source_stock = $whMgmt->getRackStock(
|
|
$from_warehouse, $from_zone, $from_aisle, $from_rack
|
|
);
|
|
|
|
if (!$source_stock) {
|
|
throw new Exception(
|
|
"Source rack {$from_zone}-{$from_aisle}-{$from_rack} is empty."
|
|
);
|
|
}
|
|
|
|
if ($source_stock['product_sku'] !== $data["product_sku"]) {
|
|
throw new Exception(
|
|
"Source rack holds {$source_stock['product_sku']}, not {$data['product_sku']}."
|
|
);
|
|
}
|
|
|
|
$quantity = (int) $source_stock['in'];
|
|
|
|
// Resolve both td_stock_<wh> tables
|
|
$from_ctx = $whMgmt->getStockContext($from_warehouse, 0);
|
|
$to_ctx = $whMgmt->getStockContext($to_warehouse, 0);
|
|
$from_table = $from_ctx['table'];
|
|
$to_table = $to_ctx['table'];
|
|
|
|
// Share UUID across both paired rows for easy grouping
|
|
$transfer_uuid = $uuid;
|
|
|
|
// INSERT "from" row (outbound from source warehouse)
|
|
$table_log = [$logging];
|
|
|
|
$sql = "INSERT INTO `$from_table`
|
|
(uuid, company_id, `date`, product_sku, `out`,
|
|
ref_warehouse, zone, aisle, rack,
|
|
contact_id, `description`, `log`, `type`)
|
|
VALUES
|
|
(:uuid, :company_id, :date, :product_sku, :quantity,
|
|
:ref_warehouse, :zone, :aisle, :rack,
|
|
:contact_id, :description, :log, 'transfer')";
|
|
$pdo->prepare($sql)->execute([
|
|
":uuid" => $transfer_uuid,
|
|
":company_id" => $company_id,
|
|
":date" => date('Y-m-d H:i:s'),
|
|
":product_sku" => $data["product_sku"],
|
|
":quantity" => $quantity,
|
|
":ref_warehouse" => $to_warehouse,
|
|
":zone" => $from_zone,
|
|
":aisle" => $from_aisle,
|
|
":rack" => $from_rack,
|
|
":contact_id" => $contact_id,
|
|
":description" => $description,
|
|
":log" => json_encode($table_log),
|
|
]);
|
|
$from_stock_id = (int) $pdo->lastInsertId();
|
|
|
|
// INSERT "to" row (inbound at destination warehouse)
|
|
$sql = "INSERT INTO `$to_table`
|
|
(uuid, company_id, `date`, product_sku, `in`,
|
|
ref_warehouse, ref_id, zone, aisle, rack,
|
|
contact_id, `description`, `log`, `type`)
|
|
VALUES
|
|
(:uuid, :company_id, :date, :product_sku, :quantity,
|
|
:ref_warehouse, :ref_id, :zone, :aisle, :rack,
|
|
:contact_id, :description, :log, 'transfer')";
|
|
$pdo->prepare($sql)->execute([
|
|
":uuid" => $transfer_uuid,
|
|
":company_id" => $company_id,
|
|
":date" => date('Y-m-d H:i:s'),
|
|
":product_sku" => $data["product_sku"],
|
|
":quantity" => $quantity,
|
|
":ref_warehouse" => $from_warehouse,
|
|
":ref_id" => $from_stock_id,
|
|
":zone" => $to_zone,
|
|
":aisle" => $to_aisle,
|
|
":rack" => $to_rack,
|
|
":contact_id" => $contact_id,
|
|
":description" => $description,
|
|
":log" => json_encode($table_log),
|
|
]);
|
|
$to_stock_id = (int) $pdo->lastInsertId();
|
|
|
|
// Back-fill the "from" row's ref_id now that we have to_stock_id
|
|
// so both rows point at each other
|
|
$sql = "UPDATE `$from_table`
|
|
SET ref_id = :ref_id
|
|
WHERE id = :id AND company_id = :company_id";
|
|
$pdo->prepare($sql)->execute([
|
|
":ref_id" => $to_stock_id,
|
|
":id" => $from_stock_id,
|
|
":company_id" => $company_id,
|
|
]);
|
|
|
|
// Move rack state: release source, occupy destination
|
|
// md_rack.log gets 'release' + 'occupy' entries automatically
|
|
$whMgmt->releaseRack($from_warehouse, $from_zone, $from_aisle, $from_rack);
|
|
$whMgmt->occupyRack(
|
|
$to_warehouse, $to_zone, $to_aisle, $to_rack,
|
|
$data["product_sku"], $to_stock_id
|
|
);
|
|
|
|
// Balance adjustments on both warehouses
|
|
$whMgmt->adjustBalance('out', $from_warehouse, $data["product_sku"], 0, $quantity);
|
|
$whMgmt->adjustBalance('in', $to_warehouse, $data["product_sku"], 0, $quantity);
|
|
|
|
});
|
|
|
|
$answer["success"] = 1;
|
|
|
|
} catch (PDOException $e) {
|
|
$answer["success"] = 0;
|
|
$answer["message"] = "Database error, please try again";
|
|
http_response_code(500);
|
|
|
|
} catch (Exception $e) {
|
|
$answer["success"] = 0;
|
|
$answer["message"] = $e->getMessage();
|
|
http_response_code(400);
|
|
}
|
|
|
|
exit(json_encode($answer));
|
|
?>
|