Fix order import mapping and lot auto-switch robustness
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
2. `db/migrations/0002_phase1_seed_methods.sql`
|
||||
3. `db/migrations/0003_phase1_inventory_forecast.sql`
|
||||
4. `db/migrations/0004_phase1_direct_sales.sql`
|
||||
5. `db/migrations/0005_phase1_auto_switch_fix.sql`
|
||||
|
||||
## Beispielausfuehrung
|
||||
|
||||
@@ -14,6 +15,7 @@ psql "$DATABASE_URL" -f db/migrations/0001_phase1_core.sql
|
||||
psql "$DATABASE_URL" -f db/migrations/0002_phase1_seed_methods.sql
|
||||
psql "$DATABASE_URL" -f db/migrations/0003_phase1_inventory_forecast.sql
|
||||
psql "$DATABASE_URL" -f db/migrations/0004_phase1_direct_sales.sql
|
||||
psql "$DATABASE_URL" -f db/migrations/0005_phase1_auto_switch_fix.sql
|
||||
```
|
||||
|
||||
## Enthaltene Kernlogik in `0001`
|
||||
|
||||
@@ -665,7 +665,10 @@ BEGIN
|
||||
END IF;
|
||||
|
||||
UPDATE stock_lot
|
||||
SET status = 'current', updated_at = NOW()
|
||||
SET
|
||||
status = 'current',
|
||||
lot_number = COALESCE(lot_number, format('AUTO-%s-%s', v_product_id, v_open_lot_id)),
|
||||
updated_at = NOW()
|
||||
WHERE id = v_open_lot_id;
|
||||
|
||||
INSERT INTO stock_lot (product_id, lot_number, status)
|
||||
|
||||
99
db/migrations/0005_phase1_auto_switch_fix.sql
Normal file
99
db/migrations/0005_phase1_auto_switch_fix.sql
Normal file
@@ -0,0 +1,99 @@
|
||||
BEGIN;
|
||||
|
||||
-- Fix lot auto-switch when current lot reaches zero:
|
||||
-- if the next open lot has no lot_number yet, assign one before switching to status=current.
|
||||
-- This avoids violating chk_stock_lot_number_required_for_non_open.
|
||||
|
||||
CREATE OR REPLACE FUNCTION fn_auto_switch_lot_when_depleted()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_product_id BIGINT;
|
||||
v_open_lot_id BIGINT;
|
||||
v_current_net NUMERIC;
|
||||
v_event_key TEXT;
|
||||
BEGIN
|
||||
-- only relevant when the updated lot is currently active
|
||||
SELECT product_id
|
||||
INTO v_product_id
|
||||
FROM stock_lot
|
||||
WHERE id = NEW.lot_id;
|
||||
|
||||
-- if lot is not current anymore, nothing to do
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM stock_lot WHERE id = NEW.lot_id AND status = 'current'
|
||||
) THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
SELECT qty_net
|
||||
INTO v_current_net
|
||||
FROM v_stock_lot_balance
|
||||
WHERE stock_lot_id = NEW.lot_id;
|
||||
|
||||
IF COALESCE(v_current_net, 0) > 0 THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
-- lock all lots for this product to avoid race conditions
|
||||
PERFORM 1
|
||||
FROM stock_lot
|
||||
WHERE product_id = v_product_id
|
||||
FOR UPDATE;
|
||||
|
||||
-- confirm current lot is still current after lock
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM stock_lot WHERE id = NEW.lot_id AND status = 'current'
|
||||
) THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
UPDATE stock_lot
|
||||
SET status = 'closed', updated_at = NOW()
|
||||
WHERE id = NEW.lot_id;
|
||||
|
||||
SELECT id
|
||||
INTO v_open_lot_id
|
||||
FROM stock_lot
|
||||
WHERE product_id = v_product_id
|
||||
AND status = 'open'
|
||||
ORDER BY id
|
||||
LIMIT 1
|
||||
FOR UPDATE;
|
||||
|
||||
IF v_open_lot_id IS NULL THEN
|
||||
RAISE EXCEPTION 'No open lot available for product % during auto switch', v_product_id;
|
||||
END IF;
|
||||
|
||||
-- current/closed lots must have a lot_number due to chk_stock_lot_number_required_for_non_open.
|
||||
UPDATE stock_lot
|
||||
SET
|
||||
status = 'current',
|
||||
lot_number = COALESCE(lot_number, format('AUTO-%s-%s', v_product_id, v_open_lot_id)),
|
||||
updated_at = NOW()
|
||||
WHERE id = v_open_lot_id;
|
||||
|
||||
INSERT INTO stock_lot (product_id, lot_number, status)
|
||||
VALUES (v_product_id, NULL, 'open');
|
||||
|
||||
v_event_key := format('lot.auto_switched:%s:%s', v_product_id, txid_current());
|
||||
|
||||
PERFORM fn_enqueue_event(
|
||||
'lot.auto_switched',
|
||||
v_event_key,
|
||||
'stock_lot',
|
||||
NEW.lot_id::TEXT,
|
||||
jsonb_build_object(
|
||||
'productId', v_product_id,
|
||||
'closedLotId', NEW.lot_id,
|
||||
'newCurrentLotId', v_open_lot_id,
|
||||
'occurredAt', NOW()
|
||||
)
|
||||
);
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMIT;
|
||||
Reference in New Issue
Block a user