Files
erp_naurua/db/migrations/0005_phase1_auto_switch_fix.sql

100 lines
2.3 KiB
PL/PgSQL

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;