120 lines
2.8 KiB
PL/PgSQL
120 lines
2.8 KiB
PL/PgSQL
BEGIN;
|
|
|
|
ALTER TABLE stock_lot
|
|
ADD COLUMN IF NOT EXISTS next_active BOOLEAN NOT NULL DEFAULT FALSE;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS uq_stock_lot_one_next_active_per_product
|
|
ON stock_lot(product_id)
|
|
WHERE status = 'open' AND next_active = TRUE;
|
|
|
|
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_qualified_count INTEGER;
|
|
v_current_net NUMERIC;
|
|
v_event_key TEXT;
|
|
BEGIN
|
|
SELECT product_id
|
|
INTO v_product_id
|
|
FROM stock_lot
|
|
WHERE id = NEW.lot_id;
|
|
|
|
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;
|
|
|
|
PERFORM 1
|
|
FROM stock_lot
|
|
WHERE product_id = v_product_id
|
|
FOR UPDATE;
|
|
|
|
IF NOT EXISTS (
|
|
SELECT 1 FROM stock_lot WHERE id = NEW.lot_id AND status = 'current'
|
|
) THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
SELECT sl.id
|
|
INTO v_open_lot_id
|
|
FROM stock_lot sl
|
|
INNER JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
|
WHERE sl.product_id = v_product_id
|
|
AND sl.status = 'open'
|
|
AND sl.next_active = TRUE
|
|
AND NULLIF(TRIM(sl.lot_number), '') IS NOT NULL
|
|
AND sl.manufacturer_party_id IS NOT NULL
|
|
AND NULLIF(TRIM(sl.manufacturer_lot_number), '') IS NOT NULL
|
|
AND sl.mfg_date IS NOT NULL
|
|
AND sl.expiry_date IS NOT NULL
|
|
AND sl.purchase_date IS NOT NULL
|
|
AND v.qty_net > 0
|
|
LIMIT 1;
|
|
|
|
IF v_open_lot_id IS NULL THEN
|
|
SELECT COUNT(*), MIN(sl.id)
|
|
INTO v_qualified_count, v_open_lot_id
|
|
FROM stock_lot sl
|
|
INNER JOIN v_stock_lot_balance v ON v.stock_lot_id = sl.id
|
|
WHERE sl.product_id = v_product_id
|
|
AND sl.status = 'open'
|
|
AND NULLIF(TRIM(sl.lot_number), '') IS NOT NULL
|
|
AND sl.manufacturer_party_id IS NOT NULL
|
|
AND NULLIF(TRIM(sl.manufacturer_lot_number), '') IS NOT NULL
|
|
AND sl.mfg_date IS NOT NULL
|
|
AND sl.expiry_date IS NOT NULL
|
|
AND sl.purchase_date IS NOT NULL
|
|
AND v.qty_net > 0;
|
|
|
|
IF v_qualified_count <> 1 THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
UPDATE stock_lot
|
|
SET next_active = TRUE, updated_at = NOW()
|
|
WHERE id = v_open_lot_id;
|
|
END IF;
|
|
|
|
UPDATE stock_lot
|
|
SET status = 'closed', updated_at = NOW()
|
|
WHERE id = NEW.lot_id;
|
|
|
|
UPDATE stock_lot
|
|
SET status = 'current', next_active = FALSE, updated_at = NOW()
|
|
WHERE id = v_open_lot_id;
|
|
|
|
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;
|