Reconcile virtual shortage allocations on lot activation

This commit is contained in:
gitea_admin committed 2026-09-08 17:07:04 +02:00
1 parent 0e8df45548
commit 4a8936761b
2 files changed
+85 -5

No files matched your search

+1 -1
View File
@@ -126,7 +126,7 @@ try {
$lotNumber === ''
);
sync_open_lot_activation_selection($pdo, $productId);
if (promote_open_lot_when_virtual_shortage_is_current($pdo, $productId, $lotId)) {
if (promote_open_lot_when_virtual_shortage_is_current($pdo, $productId, $lotId, (string) ($currentUser['username'] ?? $currentUser['email'] ?? 'unknown'))) {
$preparedLot['status'] = 'current';
$preparedLot['next_active'] = false;
} else {
+84 -4
View File
@@ -590,7 +590,7 @@ function sync_open_lot_activation_selection(PDO $pdo, int $productId): void
}
}
function promote_open_lot_when_virtual_shortage_is_current(PDO $pdo, int $productId, int $lotId): bool
function promote_open_lot_when_virtual_shortage_is_current(PDO $pdo, int $productId, int $lotId, string $changedBy): bool
{
$startedTransaction = !$pdo->inTransaction();
if ($startedTransaction) {
@@ -608,7 +608,8 @@ function promote_open_lot_when_virtual_shortage_is_current(PDO $pdo, int $produc
FOR UPDATE"
);
$currentStmt->execute([':product_id' => $productId]);
if ($currentStmt->fetchColumn() === false || !is_qualified_open_lot($pdo, $lotId)) {
$virtualShortageLotId = $currentStmt->fetchColumn();
if ($virtualShortageLotId === false || !is_qualified_open_lot($pdo, $lotId)) {
if ($startedTransaction) {
$pdo->commit();
}
@@ -675,6 +676,14 @@ function promote_open_lot_when_virtual_shortage_is_current(PDO $pdo, int $produc
);
$promoteStmt->execute([':lot_id' => $lotId]);
reconcile_virtual_shortage_allocations(
$pdo,
(int) $virtualShortageLotId,
$lotId,
$changedBy,
'Automatische Verrechnung bei Aktivierung einer echten Charge'
);
if ($startedTransaction) {
$pdo->commit();
}
@@ -687,6 +696,78 @@ function promote_open_lot_when_virtual_shortage_is_current(PDO $pdo, int $produc
}
}
function reconcile_virtual_shortage_allocations(
PDO $pdo,
int $virtualLotId,
int $realLotId,
string $changedBy,
string $reason
): void {
$allocationStmt = $pdo->prepare(
"SELECT id, qty
FROM sales_order_line_lot_allocation
WHERE lot_id = :lot_id
AND allocation_status = 'reserved'
ORDER BY id
FOR UPDATE"
);
$allocationStmt->execute([':lot_id' => $virtualLotId]);
$allocations = $allocationStmt->fetchAll();
foreach ($allocations as $allocation) {
$balanceStmt = $pdo->prepare(
"SELECT COALESCE(qty_net, 0)
FROM v_stock_lot_balance
WHERE stock_lot_id = :lot_id"
);
$balanceStmt->execute([':lot_id' => $realLotId]);
$availableQty = (float) ($balanceStmt->fetchColumn() ?: 0);
if ($availableQty <= 0.0000001) {
break;
}
$replaceQty = min((float) $allocation['qty'], $availableQty);
replace_virtual_lot_allocation(
$pdo,
(int) $allocation['id'],
$realLotId,
$replaceQty,
$changedBy,
$reason
);
}
$remainingStmt = $pdo->prepare(
"SELECT COUNT(*)
FROM sales_order_line_lot_allocation
WHERE lot_id = :lot_id
AND allocation_status = 'reserved'"
);
$remainingStmt->execute([':lot_id' => $virtualLotId]);
if ((int) $remainingStmt->fetchColumn() !== 0) {
return;
}
$closeStmt = $pdo->prepare(
"UPDATE stock_lot
SET status = 'closed', next_active = FALSE, updated_at = NOW()
WHERE id = :lot_id
AND status = 'virtual_shortage'"
);
$closeStmt->execute([':lot_id' => $virtualLotId]);
if ($closeStmt->rowCount() !== 1) {
throw new RuntimeException('Virtuelle Fehlbestandscharge konnte nicht aufgeloest werden');
}
system_write_audit_log($pdo, 'stock_lot', (string) $virtualLotId, 'closed', $changedBy, [
'status' => 'virtual_shortage',
], [
'status' => 'closed',
], [
'module' => 'erp.lager',
'reason' => $reason,
]);
}
function select_open_lot_for_activation(PDO $pdo, int $productId, int $lotId): void
{
if ($productId <= 0 || $lotId <= 0) {
@@ -1217,8 +1298,7 @@ function replace_virtual_lot_allocation(
$balanceStmt = $pdo->prepare(
"SELECT COALESCE(v.qty_net, 0)
FROM v_stock_lot_balance v
WHERE v.stock_lot_id = :lot_id
FOR UPDATE"
WHERE v.stock_lot_id = :lot_id"
);
$balanceStmt->execute([':lot_id' => $realLotId]);
$available = (float) ($balanceStmt->fetchColumn() ?: 0);