1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 15:49:35 +01:00

fix(inventory): saveChildren Delete-All durch Upsert für stock_batches ersetzen

stock_movements hat einen FK auf stock_batches mit RESTRICT, daher
schlug das bisherige Delete-All + Re-Insert Pattern fehl sobald
Bestandsbewegungen existierten (HTTP 500 bei Reservierung).

Lösung: Upsert-Pattern (UPDATE bestehende, INSERT neue, DELETE entfernte).
This commit is contained in:
Sebastian Frick 2026-02-26 19:42:50 +01:00
parent 8948103957
commit 206921d2a6

View file

@ -223,21 +223,34 @@ public class JdbcStockRepository implements StockRepository {
String stockId = stock.id().value();
// Delete reservations first (cascades to allocations via FK ON DELETE CASCADE)
// Must happen before deleting batches due to FK from allocations -> stock_batches
jdbc.sql("DELETE FROM reservations WHERE stock_id = :stockId")
.param("stockId", stockId)
.update();
// Delete + re-insert batches
jdbc.sql("DELETE FROM stock_batches WHERE stock_id = :stockId")
.param("stockId", stockId)
.update();
// Upsert batches: stock_movements has FK to stock_batches (RESTRICT),
// so we cannot delete-all + re-insert. Instead: remove stale, upsert current.
var currentBatchIds = stock.batches().stream()
.map(b -> b.id().value())
.toList();
if (currentBatchIds.isEmpty()) {
jdbc.sql("DELETE FROM stock_batches WHERE stock_id = :stockId")
.param("stockId", stockId)
.update();
} else {
jdbc.sql("DELETE FROM stock_batches WHERE stock_id = :stockId AND id NOT IN (:batchIds)")
.param("stockId", stockId)
.param("batchIds", currentBatchIds)
.update();
}
for (StockBatch batch : stock.batches()) {
jdbc.sql("""
INSERT INTO stock_batches
(id, stock_id, batch_id, batch_type, quantity_amount, quantity_unit, expiry_date, status, received_at)
VALUES (:id, :stockId, :batchId, :batchType, :quantityAmount, :quantityUnit, :expiryDate, :status, :receivedAt)
int updated = jdbc.sql("""
UPDATE stock_batches
SET batch_id = :batchId, batch_type = :batchType,
quantity_amount = :quantityAmount, quantity_unit = :quantityUnit,
expiry_date = :expiryDate, status = :status, received_at = :receivedAt
WHERE id = :id AND stock_id = :stockId
""")
.param("id", batch.id().value())
.param("stockId", stockId)
@ -249,6 +262,24 @@ public class JdbcStockRepository implements StockRepository {
.param("status", batch.status().name())
.param("receivedAt", batch.receivedAt().atOffset(ZoneOffset.UTC))
.update();
if (updated == 0) {
jdbc.sql("""
INSERT INTO stock_batches
(id, stock_id, batch_id, batch_type, quantity_amount, quantity_unit, expiry_date, status, received_at)
VALUES (:id, :stockId, :batchId, :batchType, :quantityAmount, :quantityUnit, :expiryDate, :status, :receivedAt)
""")
.param("id", batch.id().value())
.param("stockId", stockId)
.param("batchId", batch.batchReference().batchId())
.param("batchType", batch.batchReference().batchType().name())
.param("quantityAmount", batch.quantity().amount())
.param("quantityUnit", batch.quantity().uom().name())
.param("expiryDate", batch.expiryDate())
.param("status", batch.status().name())
.param("receivedAt", batch.receivedAt().atOffset(ZoneOffset.UTC))
.update();
}
}
for (Reservation reservation : stock.reservations()) {