Ergaenze offene Chargen und Fehlbestands-Hinweis
This commit is contained in:
1 parent
0401a7ae2a
commit
43cb4b9885
3 files changed
+173
-4
No files matched your search
@@ -87,6 +87,14 @@ function get_lager_product_overview(PDO $pdo): array
|
||||
sl.purchase_date,
|
||||
sl.sellout_date,
|
||||
sl.sellout_forecast_status,
|
||||
COALESCE((
|
||||
SELECT SUM(a.qty)
|
||||
FROM sales_order_line_lot_allocation a
|
||||
INNER JOIN stock_lot virtual_lot ON virtual_lot.id = a.lot_id
|
||||
WHERE virtual_lot.product_id = p.id
|
||||
AND virtual_lot.status = 'virtual_shortage'
|
||||
AND a.allocation_status = 'reserved'
|
||||
), 0) AS virtual_shortage_qty,
|
||||
(
|
||||
SELECT virtual_lot.lot_number
|
||||
FROM stock_lot virtual_lot
|
||||
@@ -127,6 +135,7 @@ function get_lager_product_overview(PDO $pdo): array
|
||||
'purchase_date' => $row['purchase_date'],
|
||||
'sellout_date' => $row['sellout_date'],
|
||||
'sellout_forecast_status' => (string) ($row['sellout_forecast_status'] ?? 'no_demand'),
|
||||
'virtual_shortage_qty' => (float) ($row['virtual_shortage_qty'] ?? 0),
|
||||
'virtual_lot_number' => $row['virtual_lot_number'],
|
||||
],
|
||||
$stmt->fetchAll()
|
||||
@@ -176,8 +185,44 @@ function get_lager_product_overview(PDO $pdo): array
|
||||
];
|
||||
}
|
||||
|
||||
$openStmt = $pdo->query(
|
||||
"SELECT
|
||||
sl.product_id,
|
||||
sl.id AS lot_id,
|
||||
sl.lot_number,
|
||||
sl.manufacturer_party_id,
|
||||
sl.manufacturer_lot_number,
|
||||
mp.name AS manufacturer_name,
|
||||
sl.mfg_date,
|
||||
sl.expiry_date,
|
||||
sl.purchase_date,
|
||||
COALESCE(v.qty_in, 0) AS qty_in,
|
||||
COALESCE(v.qty_net, 0) AS qty_net
|
||||
FROM stock_lot sl
|
||||
LEFT JOIN party mp ON mp.id = sl.manufacturer_party_id
|
||||
LEFT JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
||||
WHERE sl.status = 'open'
|
||||
ORDER BY sl.product_id, sl.id"
|
||||
);
|
||||
$openLotsByProduct = [];
|
||||
foreach ($openStmt->fetchAll() as $openLot) {
|
||||
$openLotsByProduct[(int) $openLot['product_id']][] = [
|
||||
'lot_id' => (int) $openLot['lot_id'],
|
||||
'lot_number' => $openLot['lot_number'],
|
||||
'manufacturer_party_id' => $openLot['manufacturer_party_id'] === null ? null : (int) $openLot['manufacturer_party_id'],
|
||||
'manufacturer_lot_number' => $openLot['manufacturer_lot_number'],
|
||||
'manufacturer_name' => $openLot['manufacturer_name'],
|
||||
'mfg_date' => $openLot['mfg_date'],
|
||||
'expiry_date' => $openLot['expiry_date'],
|
||||
'purchase_date' => $openLot['purchase_date'],
|
||||
'qty_in' => (float) $openLot['qty_in'],
|
||||
'qty_net' => (float) $openLot['qty_net'],
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($products as &$product) {
|
||||
$product['historical_lots'] = $historicalLotsByProduct[$product['id']] ?? [];
|
||||
$product['open_lots'] = $openLotsByProduct[$product['id']] ?? [];
|
||||
}
|
||||
unset($product);
|
||||
|
||||
@@ -195,7 +240,8 @@ function update_stock_lot_traceability(
|
||||
string $changedBy,
|
||||
float $receiptQty = 0.0,
|
||||
float $adjustmentQty = 0.0,
|
||||
float $outQty = 0.0
|
||||
float $outQty = 0.0,
|
||||
?string $lotNumber = null
|
||||
): array {
|
||||
if ($lotId <= 0) {
|
||||
throw new InvalidArgumentException('Chargen-ID fehlt');
|
||||
@@ -205,6 +251,10 @@ function update_stock_lot_traceability(
|
||||
if ($manufacturerLotNumber === '') {
|
||||
$manufacturerLotNumber = null;
|
||||
}
|
||||
$lotNumber = $lotNumber !== null ? trim($lotNumber) : null;
|
||||
if ($lotNumber === '') {
|
||||
throw new InvalidArgumentException('Naurua-Chargennummer fehlt');
|
||||
}
|
||||
|
||||
if (!is_finite($receiptQty) || !is_finite($adjustmentQty) || !is_finite($outQty)) {
|
||||
throw new InvalidArgumentException('Ungueltige Bewegungsmenge');
|
||||
@@ -256,6 +306,9 @@ function update_stock_lot_traceability(
|
||||
if ((string) $before['status'] === 'virtual_shortage') {
|
||||
throw new InvalidArgumentException('Virtuelle Fehlbestandschargen koennen nicht gepflegt werden');
|
||||
}
|
||||
if ($lotNumber !== null && (string) $before['status'] !== 'open') {
|
||||
throw new InvalidArgumentException('Nur offene Chargen koennen neu angelegt werden');
|
||||
}
|
||||
|
||||
if ($manufacturerPartyId !== null) {
|
||||
$manufacturerStmt = $pdo->prepare(
|
||||
@@ -277,13 +330,14 @@ function update_stock_lot_traceability(
|
||||
if ($manufacturerPartyId !== null && $manufacturerLotNumber === null && (string) $before['status'] !== 'open') {
|
||||
throw new InvalidArgumentException('Hersteller-Chargennummer fehlt');
|
||||
}
|
||||
if (($receiptQty > 0 || $adjustmentQty !== 0.0 || $outQty > 0) && (string) $before['status'] !== 'current') {
|
||||
throw new InvalidArgumentException('Lagerbewegungen koennen nur auf der aktiven Charge gebucht werden');
|
||||
if (($adjustmentQty !== 0.0 || $outQty > 0) && (string) $before['status'] !== 'current') {
|
||||
throw new InvalidArgumentException('Korrekturen und Abgaenge koennen nur auf der aktiven Charge gebucht werden');
|
||||
}
|
||||
|
||||
$updateStmt = $pdo->prepare(
|
||||
"UPDATE stock_lot
|
||||
SET manufacturer_party_id = :manufacturer_party_id,
|
||||
SET lot_number = COALESCE(:lot_number, lot_number),
|
||||
manufacturer_party_id = :manufacturer_party_id,
|
||||
manufacturer_lot_number = :manufacturer_lot_number,
|
||||
mfg_date = :mfg_date,
|
||||
expiry_date = :expiry_date,
|
||||
@@ -292,6 +346,7 @@ function update_stock_lot_traceability(
|
||||
WHERE id = :id"
|
||||
);
|
||||
$updateStmt->execute([
|
||||
':lot_number' => $lotNumber,
|
||||
':manufacturer_party_id' => $manufacturerPartyId,
|
||||
':manufacturer_lot_number' => $manufacturerLotNumber,
|
||||
':mfg_date' => $dates['mfg_date'],
|
||||
@@ -301,6 +356,9 @@ function update_stock_lot_traceability(
|
||||
]);
|
||||
|
||||
$after = $before;
|
||||
if ($lotNumber !== null) {
|
||||
$after['lot_number'] = $lotNumber;
|
||||
}
|
||||
$after['manufacturer_party_id'] = $manufacturerPartyId;
|
||||
$after['manufacturer_lot_number'] = $manufacturerLotNumber;
|
||||
$after['mfg_date'] = $dates['mfg_date'];
|
||||
@@ -681,6 +739,37 @@ function get_or_create_virtual_shortage_lot(PDO $pdo, int $productId): int
|
||||
return (int) $newLotId;
|
||||
}
|
||||
|
||||
function get_or_create_open_lot(PDO $pdo, int $productId): int
|
||||
{
|
||||
$select = $pdo->prepare(
|
||||
"SELECT id
|
||||
FROM stock_lot
|
||||
WHERE product_id = :product_id
|
||||
AND status = 'open'
|
||||
ORDER BY id
|
||||
LIMIT 1
|
||||
FOR UPDATE"
|
||||
);
|
||||
$select->execute([':product_id' => $productId]);
|
||||
$lotId = $select->fetchColumn();
|
||||
if ($lotId !== false) {
|
||||
return (int) $lotId;
|
||||
}
|
||||
|
||||
$insert = $pdo->prepare(
|
||||
"INSERT INTO stock_lot (product_id, status, created_at, updated_at)
|
||||
VALUES (:product_id, 'open', NOW(), NOW())
|
||||
RETURNING id"
|
||||
);
|
||||
$insert->execute([':product_id' => $productId]);
|
||||
$newLotId = $insert->fetchColumn();
|
||||
if ($newLotId === false) {
|
||||
throw new RuntimeException('Offene Charge konnte nicht angelegt werden');
|
||||
}
|
||||
|
||||
return (int) $newLotId;
|
||||
}
|
||||
|
||||
function replace_virtual_lot_allocation(
|
||||
PDO $pdo,
|
||||
int $allocationId,
|
||||
|
||||
Reference in new issue
Block a user