Fix virtual shortage lot activation and warning

This commit is contained in:
gitea_admin committed 2026-09-08 16:55:37 +02:00
1 parent 17efaee53f
commit 8846a57b43
3 files changed
+129 -11

No files matched your search

+22 -2
View File
@@ -126,7 +126,12 @@ try {
$lotNumber === ''
);
sync_open_lot_activation_selection($pdo, $productId);
$preparedLot['next_active'] = is_open_lot_selected_for_activation($pdo, $lotId);
if (promote_open_lot_when_virtual_shortage_is_current($pdo, $productId, $lotId)) {
$preparedLot['status'] = 'current';
$preparedLot['next_active'] = false;
} else {
$preparedLot['next_active'] = is_open_lot_selected_for_activation($pdo, $lotId);
}
refresh_lager_stock_lot_forecast_for_product($pdo, $productId);
$forecast = get_lager_product_forecast($pdo, $productId);
json_response(200, ['ok' => true, 'productId' => $productId, 'lot' => $preparedLot, 'balance' => get_stock_lot_balance($pdo, $lotId), 'availableQty' => get_lager_product_available_qty($pdo, $productId), 'forecast' => $forecast]);
@@ -136,7 +141,8 @@ try {
$productId = (int) ($data['productId'] ?? 0);
$lotId = (int) ($data['lotId'] ?? 0);
select_open_lot_for_activation($pdo, $productId, $lotId);
json_response(200, ['ok' => true, 'productId' => $productId, 'selectedLotId' => $lotId]);
refresh_lager_stock_lot_forecast_for_product($pdo, $productId);
json_response(200, ['ok' => true, 'productId' => $productId, 'selectedLotId' => $lotId, 'forecast' => get_lager_product_forecast($pdo, $productId)]);
}
json_response(422, ['ok' => false, 'error' => 'Unsupported action']);
@@ -145,5 +151,19 @@ try {
} catch (InvalidArgumentException $error) {
json_response(422, ['ok' => false, 'error' => $error->getMessage()]);
} catch (Throwable $error) {
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
try {
system_write_audit_log($pdo, 'lager_api', 'lager-charge.php', 'request_failed', $currentUser['username'] ?? $currentUser['email'] ?? 'unknown', [], [], [
'action' => $action ?? '',
'product_id' => $data['productId'] ?? null,
'lot_id' => $data['lotId'] ?? null,
'exception_class' => get_class($error),
'exception_message' => $error->getMessage(),
]);
} catch (Throwable) {
error_log('lager-charge API failure audit logging failed');
}
json_response(500, ['ok' => false, 'error' => 'Interner Serverfehler']);
}
+98 -1
View File
@@ -523,7 +523,7 @@ function sync_open_lot_activation_selection(PDO $pdo, int $productId): void
"SELECT sl.id
FROM stock_lot sl
INNER JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
WHERE sl.product_id = :product_id
WHERE product_id = :product_id
AND sl.status = 'open'
AND NULLIF(TRIM(sl.lot_number), '') IS NOT NULL
AND sl.manufacturer_party_id IS NOT NULL
@@ -590,6 +590,103 @@ 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
{
$startedTransaction = !$pdo->inTransaction();
if ($startedTransaction) {
$pdo->beginTransaction();
}
try {
$currentStmt = $pdo->prepare(
"SELECT id
FROM stock_lot
WHERE product_id = :product_id
AND status = 'virtual_shortage'
ORDER BY id
LIMIT 1
FOR UPDATE"
);
$currentStmt->execute([':product_id' => $productId]);
if ($currentStmt->fetchColumn() === false || !is_qualified_open_lot($pdo, $lotId)) {
if ($startedTransaction) {
$pdo->commit();
}
return false;
}
$realCurrentStmt = $pdo->prepare(
"SELECT id
FROM stock_lot
WHERE product_id = :product_id
AND status = 'current'
LIMIT 1
FOR UPDATE"
);
$realCurrentStmt->execute([':product_id' => $productId]);
$realCurrent = $realCurrentStmt->fetch();
if (is_array($realCurrent)) {
$realCurrentBalanceStmt = $pdo->prepare(
"SELECT COALESCE(qty_net, 0)
FROM v_stock_lot_balance
WHERE stock_lot_id = :lot_id"
);
$realCurrentBalanceStmt->execute([':lot_id' => (int) $realCurrent['id']]);
$realCurrentQty = (float) ($realCurrentBalanceStmt->fetchColumn() ?: 0);
} else {
$realCurrentQty = 0.0;
}
if ($realCurrentQty > 0.0000001) {
if ($startedTransaction) {
$pdo->commit();
}
return false;
}
$lotStmt = $pdo->prepare(
"SELECT id
FROM stock_lot
WHERE id = :lot_id
AND product_id = :product_id
AND status = 'open'
FOR UPDATE"
);
$lotStmt->execute([':lot_id' => $lotId, ':product_id' => $productId]);
if ($lotStmt->fetchColumn() === false) {
if ($startedTransaction) {
$pdo->commit();
}
return false;
}
if (is_array($realCurrent)) {
$closeStmt = $pdo->prepare(
"UPDATE stock_lot
SET status = 'closed', updated_at = NOW()
WHERE id = :lot_id"
);
$closeStmt->execute([':lot_id' => (int) $realCurrent['id']]);
}
$promoteStmt = $pdo->prepare(
"UPDATE stock_lot
SET status = 'current', next_active = FALSE, updated_at = NOW()
WHERE id = :lot_id"
);
$promoteStmt->execute([':lot_id' => $lotId]);
if ($startedTransaction) {
$pdo->commit();
}
return true;
} catch (Throwable $error) {
if ($startedTransaction && $pdo->inTransaction()) {
$pdo->rollBack();
}
throw $error;
}
}
function select_open_lot_for_activation(PDO $pdo, int $productId, int $lotId): void
{
if ($productId <= 0 || $lotId <= 0) {