-- test/sql/14_end_to_end_warehouse.sql -- End-to-end test: warehouse stock management scenario from README BEGIN; SELECT plan(11); -- ============================================================ -- Create warehouse register (matches README example) -- ============================================================ SELECT accum.register_create( name := 'inventory', dimensions := '{"warehouse": "int", "product": "int"}', resources := '{"quantity": "numeric(18,4)", "amount": "numeric(18,2)"}', kind := 'balance' ); -- ============================================================ -- Scenario: Receipt → Sale → Check balance → Correction → Verify -- ============================================================ -- Step 1: Receive 100 units of product 42 at warehouse 1 SELECT accum.register_post('inventory', '{ "recorder": "receipt:1", "period": "2026-04-18", "warehouse": 1, "product": 42, "quantity": 100, "amount": 5000.00 }'); SELECT is( (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=1 AND product=42), 100.0000::numeric, 'Step 1: After receipt, balance should be 100' ); -- Step 2: Sell 10 units from warehouse 1, transfer 10 to warehouse 2 SELECT accum.register_post('inventory', '[ {"recorder":"sale:1","period":"2026-04-18","warehouse":1,"product":42,"quantity":-10,"amount":-500}, {"recorder":"transfer:1","period":"2026-04-18","warehouse":1,"product":42,"quantity":-10,"amount":-500}, {"recorder":"transfer:1","period":"2026-04-18","warehouse":2,"product":42,"quantity":10,"amount":500} ]'); SELECT is( (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=1 AND product=42), 80.0000::numeric, 'Step 2: After sale+transfer, wh1 balance should be 100-10-10=80' ); SELECT is( (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=2 AND product=42), 10.0000::numeric, 'Step 2: Warehouse 2 should have 10 units' ); -- Step 3: Receive another product SELECT accum.register_post('inventory', '{ "recorder":"receipt:2","period":"2026-04-18","warehouse":1,"product":99,"quantity":200,"amount":4000 }'); SELECT is( (SELECT count(*)::int FROM accum.inventory_balance_cache WHERE quantity != 0), 3, 'Step 3: Should have 3 non-zero balance rows' ); -- Step 4: Cancel the sale (discovered error) SELECT accum.register_unpost('inventory', 'sale:1'); SELECT is( (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=1 AND product=42), 90.0000::numeric, 'Step 4: After cancel sale, wh1 balance should be 80+10=90' ); -- Step 5: Correct the transfer amount (was 10, should be 15) SELECT accum.register_repost('inventory', 'transfer:1', '[ {"period":"2026-04-18","warehouse":1,"product":42,"quantity":-15,"amount":-750}, {"period":"2026-04-18","warehouse":2,"product":42,"quantity":15,"amount":750} ]'); SELECT is( (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=1 AND product=42), 85.0000::numeric, 'Step 5: After corrected transfer, wh1 should be 100-15=85' ); SELECT is( (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=2 AND product=42), 15.0000::numeric, 'Step 5: Warehouse 2 should now have 15' ); -- Step 6: Verify totals consistency SELECT is( (SELECT sum(quantity) FROM accum.inventory_movements WHERE warehouse=1 AND product=42), (SELECT quantity FROM accum.inventory_balance_cache WHERE warehouse=1 AND product=42), 'Step 6a: Balance cache quantity must equal SUM(movements) for wh1,prod42' ); SELECT is( (SELECT sum(amount) FROM accum.inventory_movements WHERE warehouse=1 AND product=42), (SELECT amount FROM accum.inventory_balance_cache WHERE warehouse=1 AND product=42), 'Step 6b: Balance cache amount must equal SUM(movements) for wh1,prod42' ); -- Step 7: Verify total product 42 across all warehouses SELECT is( (SELECT sum(quantity) FROM accum.inventory_balance_cache WHERE product=42), 100.0000::numeric, 'Step 7: Total product 42 across all warehouses should be 100 (receipt only)' ); -- Step 8: Verify grand total SELECT is( (SELECT sum(quantity) FROM accum.inventory_balance_cache), 300.0000::numeric, 'Step 8: Grand total should be 100(prod42) + 200(prod99) = 300' ); -- Cleanup SELECT accum.register_drop('inventory', force := true); SELECT * FROM finish(); ROLLBACK;