BEGIN;
    -- Load the TAP functions.
    CREATE EXTENSION pgtap;
    SET client_min_messages TO warning;

    -- Plan the tests.

    SELECT plan(132);

    -- Add data

    \i xt/data/42-pg/Base.sql

    -- Validate required tables

    SELECT has_table('account');
    SELECT has_table('account_heading');
    SELECT has_table('ap');
    SELECT has_table('ar');
    SELECT has_table('entity_credit_account');
    SELECT has_table('entity');
    SELECT has_table('invoice');
    SELECT has_table('parts');

    -- Validate required functions

    SELECT has_function('cogs__add_for_ap',ARRAY['integer','numeric','numeric','date']);
    SELECT has_function('cogs__add_for_ap_line',ARRAY['integer','date']);
    SELECT has_function('cogs__add_for_ar',ARRAY['integer','numeric']);
    SELECT has_function('cogs__add_for_ar_line',ARRAY['integer']);
    SELECT has_function('cogs__reverse_ap',ARRAY['integer','numeric']);
    SELECT has_function('cogs__reverse_ar',ARRAY['integer','numeric']);

    -- Set specific data

    INSERT INTO account_heading (id, accno, description)
    VALUES (-1000, '-1000', 'Test heading');

    INSERT INTO account (id, accno, category, description, heading)
    VALUES (-1101, 'TEST1001', 'A', 'COGS test series 1 Inventory', -1000),
           (-1102, 'TEST1002', 'E', 'COGS test series 1 COGS', -1000),
           (-1103, 'TEST1003', 'E', 'COGS test series 1 returns', -1000),
           (-1104, 'TEST1004', 'I', 'COGS test series 1 income', -1000),
           (-2101, 'TEST2001', 'A', 'COGS test series 2 Inventory', -1000),
           (-2102, 'TEST2002', 'E', 'COGS test series 1 COGS', -1000),
           (-2103, 'TEST2003', 'E', 'COGS test series 1 returns', -1000),
           (-2104, 'TEST2004', 'I', 'COGS test series 1 income', -1000),
           (-3101, 'TEST3002', 'A', 'COGS test series 2 Inventory', -1000),
           (-3102, 'TEST3001', 'E', 'COGS test series 1 COGS', -1000),
           (-3103, 'TEST3003', 'E', 'COGS test series 1 returns', -1000),
           (-3104, 'TEST3004', 'I', 'COGS test series 1 income', -1000),
           (-4101, 'TEST4001', 'A', 'COGS test series 2 Inventory', -1000),
           (-4102, 'TEST4002', 'E', 'COGS test series 1 COGS', -1000),
           (-4103, 'TEST4003', 'E', 'COGS test series 1 returns', -1000),
           (-4104, 'TEST4004', 'I', 'COGS test series 1 income', -1000),
           (-5101, 'TEST5001', 'A', 'COGS test series 2 Inventory', -1000),
           (-5102, 'TEST5002', 'E', 'COGS test series 1 COGS', -1000),
           (-5103, 'TEST5003', 'E', 'COGS test series 1 returns', -1000),
           (-5104, 'TEST5004', 'I', 'COGS test series 1 income', -1000),
           (-6101, 'TEST6001', 'A', 'COGS test series 2 Inventory', -1000),
           (-6102, 'TEST6002', 'E', 'COGS test series 1 COGS', -1000),
           (-6103, 'TEST6003', 'E', 'COGS test series 1 returns', -1000),
           (-6104, 'TEST6004', 'I', 'COGS test series 1 income', -1000);

    INSERT INTO parts
           (id, partnumber, description, income_accno_id, expense_accno_id,
            inventory_accno_id, returns_accno_id)
    VALUES (-1, 'TS1', 'COGS Test Series 1', -1101, -1102, -1104, -1103),
           (-2, 'TS2', 'COGS Test Series 2', -2101, -2102, -2104, -2103),
           (-3, 'TS3', 'COGS Test Series 3', -3101, -3102, -3104, -3103),
           (-4, 'TS4', 'COGS Test Series 4', -4101, -4102, -4104, -4103),
           (-5, 'TS5', 'COGS Test Series 5', -5101, -5102, -5104, -5103),
           (-6, 'TS5/part2', 'COGS Test Series 5/part2', -6101, -6102, -6104, -6103);

    INSERT INTO entity (id, name, country_id)
    VALUES (-1000, 'Test act', 232);

    INSERT INTO entity_credit_account
            (id, entity_class, meta_number, entity_id, curr, ar_ap_account_id)
    VALUES (-1000, 1, 'cogs test1', -1000, 'XTS', -1103),
           (-2000, 2, 'cogs test2', -1000, 'XTS', -1103);

    -- Run tests


/*
    # First series of tests, AR before AP

    This test concerns 3 invoices:

    1. id=-1201; AR invoice
    2. id=-1202; AP invoice
    3. id=-1203, the second AR invoice
    4. id=-1204, the second AP invoice
    5. id=-1205, the third AP invoice

    Summary of steps:

    1. sell 100 items (back-order: 100)
    2. purchase 75 items (back-order: 25 / invoice -1201)
    3. sell 100 items (back-order: 25 @ -1201 / 100 @ -1203)
    4. purchase 75 (back-order: 0 @ -1201 / 50 @ -1203)
    5. purchase 50 (back-order: 0)

*/

    -----------------------------------
    --  Step 1: Create invoice -1201

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account, approved)
    VALUES (-1201, true, 'test1001', now() - '10 days'::interval, -2000, 't');
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-1201, -1201, -1, 100, 0, 3);

    SELECT is(sum(amount_bc),
              NULL,
              'initial COGS is null, (invoice 1, series 1)')
      FROM acc_trans
     WHERE trans_id = -1201 AND chart_id = -1102;


    -----------------------------------
    --  Step 2: Generate COGS for invoice -1201 (AR)

    SELECT cogs__add_for_ar_line(-1201);

    SELECT is(sum(amount_bc),
              0::numeric,
              'post-run COGS is 0, (invoice 1, series 1)')
      FROM acc_trans
     WHERE trans_id = -1201 AND chart_id = -1102;


    -----------------------------------
    --  Step 3: Create invoice -1202 (AP) and post COGS

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account, approved)
    VALUES (-1202,  true, 'test1002', now() - '10 days'::interval, -1000, 't');
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-1202, -1202, -1, -75, 0, 0.5);

    SELECT cogs__add_for_ap_line(-1202);


    SELECT is(sum(amount_bc),
              -37.5,
              'post-ap-run COGS is 37.50, (invoice 1, series 1)')
      FROM acc_trans
     WHERE trans_id = -1201 AND chart_id = -1102;

    SELECT is(ARRAY(SELECT allocated FROM invoice WHERE id IN (-1201, -1202) ORDER BY id),
              ARRAY[75, -75]::numeric[],
              'post-ap-run allocated 75 (invoice 2+1, series 1)');



    -----------------------------------
    --  Step 4: Create invoice -1203 (AR) and post COGS

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-1203, true, 'test1003', now() - '9 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-1203, -1203, -1, 100, 0, 3);

    SELECT is(sum(amount_bc),
              NULL,
              'initial COGS is null, (invoice 3, series 1)')
      FROM acc_trans
     WHERE trans_id = -1203 AND chart_id = -1102;

    SELECT cogs__add_for_ar_line(-1203);

    SELECT is(ARRAY(SELECT allocated FROM invoice WHERE id IN (-1201, -1202, -1203) ORDER BY id),
              ARRAY[0, 75, -75]::numeric[],
              'post-ap-run allocated (invoice 3+2+1, series 1)');

    PREPARE test AS SELECT
                       sum(amount_bc) = -37.5
                      from acc_trans
                     where trans_id = -1201 and chart_id = -1102;
    SELECT results_eq('test',ARRAY[true],'post-ap-run COGS still 37.50, (invoice 1, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT
                        sum(amount_bc) = 0
                      from acc_trans
                     where trans_id = -1203 and chart_id = -1102;
    SELECT results_eq('test',ARRAY[true],'post-run COGS is 0, (invoice 3, series 1)');
    DEALLOCATE test;

    -----------------------------------
    --  Step 5: Create invoice -1204 (AP) and post COGS

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-1204,  true, 'test1004', now() - '8 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-1204, -1204, -1, -75, 0, 1);

    SELECT cogs__add_for_ap_line(-1204);

    PREPARE test AS SELECT allocated = -100
                    FROM invoice WHERE id = -1201;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated 100 (invoice 1, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 75
                    FROM invoice WHERE id = -1202;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated still 75 (invoice 2, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -50
                    FROM invoice WHERE id = -1203;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated 50 (invoice 3, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 75
                    FROM invoice WHERE id = -1204;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated 75 (invoice 4, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
                      from acc_trans
                     where trans_id = -1201 and chart_id = -1102;
    SELECT results_eq('test',ARRAY[true],'post-ap-run COGS is 62.50, (invoice 1, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -50
                      from acc_trans
                     where trans_id = -1203 and chart_id = -1102;
    SELECT results_eq('test',ARRAY[true],'post-ap-run COGS is 50, (invoice 2, series 1)');
    DEALLOCATE test;

    -----------------------------------
    --  Step 6: Create invoice -1205 (AP) and post COGS

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-1205,  true, 'test1004', now() - '8 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-1205, -1205, -1, -50, 0, 2);

    SELECT cogs__add_for_ap_line(-1205);

    PREPARE test AS SELECT allocated = -100
                    FROM invoice WHERE id = -1201;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated still 100 (invoice 1, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 75
                    FROM invoice WHERE id = -1202;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated still 75 (invoice 2, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -100
                    FROM invoice WHERE id = -1203;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated 100 (invoice 3, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 75
                    FROM invoice WHERE id = -1204;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated still 75 (invoice 4, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 50
                    FROM invoice WHERE id = -1205;
    SELECT results_eq('test',ARRAY[true],'post-ap-run allocated 50 (invoice 5, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
                      from acc_trans
                     where trans_id = -1201 and chart_id = -1102;
    SELECT results_eq('test',ARRAY[true],'post-ap-run COGS is 62.50, (invoice 1, series 1)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -150
                      from acc_trans
                     where trans_id = -1203 and chart_id = -1102;
    SELECT results_eq('test',ARRAY[true],'post-ap-run COGS is 150, (invoice 2, series 1)');
    DEALLOCATE test;


/*
    # Series 2, AP invoices first, cogs only added to AR


*/
    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-2201,  true, 'test2001', now() - '10 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-2201, -2201, -2, -100, 0, 0.5);

    SELECT cogs__add_for_ap_line(-2201);

    PREPARE test AS SELECT allocated = 0
                    FROM invoice WHERE id = -2201;
    SELECT results_eq('test',ARRAY[true],'Allocated is 0 post-AP run (invoice 1 series 2)');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-2202,  true, 'test2001', now() - '10 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-2202, -2202, -2, 75, 0, 3);

    SELECT cogs__add_for_ar_line(-2202);

    PREPARE test AS SELECT allocated = 75
                    FROM invoice WHERE id = -2201;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AR run (invoice 1 series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -2202;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AR run (invoice 2 series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
                      from acc_trans
                     where trans_id = -2202 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-run COGS is 37.50, (invoice 2, series 2)');
    DEALLOCATE test;

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-2203,  true, 'test2003', now() - '9 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-2203, -2203, -2, -100, 0, 1);

    SELECT cogs__add_for_ap_line(-2203);

    PREPARE test AS SELECT allocated = 75
                    FROM invoice WHERE id = -2201;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AP run (invoice 1 series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -2202;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AP run (invoice 2 series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 0
                    FROM invoice WHERE id = -2203;
    SELECT results_eq('test',ARRAY[true],'Allocated is 0 post-AP run (invoice 3 series 2)');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-2204,  true, 'test2004', now() - '7 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-2204, -2204, -2, 75, 0, 3);

    SELECT cogs__add_for_ar_line(-2204);

    PREPARE test AS SELECT allocated = 100
                    FROM invoice WHERE id = -2201;
    SELECT results_eq('test',ARRAY[true],'post-ar-4, allocation invoice 1 series 2 is 100');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -2202;
    SELECT results_eq('test',ARRAY[true],'post-ar-4, allocation invoice 2 series 2 is 75');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 50
                    FROM invoice WHERE id = -2203;
    SELECT results_eq('test',ARRAY[true],'post-ar-4, allocation invoice 3 series 2 is 50');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -2204;
    SELECT results_eq('test',ARRAY[true],'post-ar-4, allocation invoice 4 series 2 is 75');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
                      from acc_trans
                     where trans_id = -2202 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-4 COGS is 37.50, (invoice 2, series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
                      from acc_trans
                     where trans_id = -2204 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-4 COGS is 62.50, (invoice 2, series 4)');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-2205,  true, 'test2005', now() - '5 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-2205, -2205, -2, 50, 0, 3);

    SELECT cogs__add_for_ar_line(-2205);

    PREPARE test AS SELECT allocated = 100
                    FROM invoice WHERE id = -2201;
    SELECT results_eq('test',ARRAY[true],'post-ar-5, allocation invoice 1 series 2 is 100');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -2202;
    SELECT results_eq('test',ARRAY[true],'post-ar-5, allocation invoice 2 series 2 is 75');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 100
                    FROM invoice WHERE id = -2203;
    SELECT results_eq('test',ARRAY[true],'post-ar-5, allocation invoice 3 series 2 is 100');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -2204;
    SELECT results_eq('test',ARRAY[true],'post-ar-5, allocation invoice 4 series 2 is 75');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -50
                    FROM invoice WHERE id = -2205;
    SELECT results_eq('test',ARRAY[true],'post-ar-5, allocation invoice 5 series 2 is 50');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
                      from acc_trans
                     where trans_id = -2202 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-5 COGS is 37.50, (invoice 2, series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
                      from acc_trans
                     where trans_id = -2204 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-5 COGS is 62.50, (invoice 2, series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -50
                      from acc_trans
                     where trans_id = -2205 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-5 COGS is 50, (invoice 2, series 5)');
    DEALLOCATE test;

/*
    # Series 2.5, AR reversal


*/
    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-2206,  true, 'test2006', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-2206, -2206, -2, -150, 0, 3);

    SELECT cogs__add_for_ar_line(-2206);

    PREPARE test AS SELECT allocated = 50
      FROM invoice WHERE id = -2201;
    SELECT results_eq('test',ARRAY[true],'post-ar-6, allocation invoice 1 series 2 is 50; ');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -2202;
    SELECT results_eq('test',ARRAY[true],'post-ar-6, allocation invoice 2 series 2 is -75');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 0
      FROM invoice WHERE id = -2203;
    SELECT results_eq('test',ARRAY[true],'post-ar-6, allocation invoice 3 series 2 is 0; ');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -2204;
    SELECT results_eq('test',ARRAY[true],'post-ar-6, allocation invoice 4 series 2 is -75; ');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -50
      FROM invoice WHERE id = -2205;
    SELECT results_eq('test',ARRAY[true],'post-ar-6, allocation invoice 5 series 2 is -50; ');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 150
      FROM invoice WHERE id = -2206;
    SELECT results_eq('test',ARRAY[true],'post-ar-6, allocation invoice 6 series 2 is 150; ');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
    from acc_trans
     where trans_id = -2202 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-6 COGS is 37.50, (invoice 2, series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
    from acc_trans
     where trans_id = -2204 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-6 COGS is 62.50, (invoice 4, series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -50
    from acc_trans
     where trans_id = -2205 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-6 COGS is 50, (invoice 5, series 2)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = 125
    from acc_trans
     where trans_id = -2206 and chart_id = -2102;
    SELECT results_eq('test',ARRAY[true],'post-ar-6 COGS is -125, (invoice 6, series 2)');
    DEALLOCATE test;

/*
    # Series 3, Mixed


*/
    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-3201,  true, 'test3001', now() - '10 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-3201, -3201, -3, -100, 0, 0.5);

    SELECT cogs__add_for_ap_line(-3201);

    PREPARE test AS SELECT allocated = 0
      FROM invoice WHERE id = -3201;
    SELECT results_eq('test',ARRAY[true],'post-ap-1, allocation invoice 1 series 3 is 0');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-3202,  true, 'test3002', now() - '9 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-3202, -3202, -3, 75, 0, 3);

    SELECT cogs__add_for_ar_line(-3202);

    PREPARE test AS SELECT allocated = 75
      FROM invoice WHERE id = -3201;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AR run (invoice 1 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -3202;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AR run (invoice 2 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
    from acc_trans
     where trans_id = -3202 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ar-run COGS is 37.50, (invoice 2, series 3)');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-3203,  true, 'test3003', now() - '9 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-3203, -3203, -3, 75, 0, 3);

    SELECT cogs__add_for_ar_line(-3203);

    PREPARE test AS SELECT allocated = 100
      FROM invoice WHERE id = -3201;
    SELECT results_eq('test',ARRAY[true],'Allocated is 100 post-AR run (invoice 1 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -3202;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AR run (invoice 2 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -25
      FROM invoice WHERE id = -3203;
    SELECT results_eq('test',ARRAY[true],'Allocated is 75 post-AR run (invoice 3 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
    from acc_trans
     where trans_id = -3202 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ar-run COGS is 37.50, (invoice 2, series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -12.5
    from acc_trans
     where trans_id = -3203 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ar-run COGS is 12.5, (invoice 3, series 3)');
    DEALLOCATE test;

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-3204,  true, 'test3004', now() - '8 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-3204, -3204, -3, -100, 0, 1);

    SELECT cogs__add_for_ap_line(-3204);

    PREPARE test AS SELECT
           allocated = 100
      FROM invoice WHERE id = -3201;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 100 post-AR run (invoice 1 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT
            allocated = -75
      FROM invoice WHERE id = -3202;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 75 post-AR run (invoice 2 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -3203;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 75 post-AR run (invoice 3 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 50
      FROM invoice WHERE id = -3204;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 50 post-AR run (invoice 4 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
    from acc_trans
     where trans_id = -3202 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 COGS is 37.50, (invoice 2, series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
    from acc_trans
     where trans_id = -3203 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 COGS is 62.5, (invoice 3, series 3)');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-3205,  true, 'test3005', now() - '9 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-3205, -3205, -3, 75, 0, 3);

    SELECT cogs__add_for_ar_line(-3205);

    PREPARE test AS SELECT
           allocated = 100
      FROM invoice WHERE id = -3201;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 Allocated is 100 post-AR run (invoice 1 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT
            allocated = -75
      FROM invoice WHERE id = -3202;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 Allocated is 75 post-AR run (invoice 2 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -3203;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 Allocated is 75 post-AR run (invoice 3 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT
           allocated = 100
      FROM invoice WHERE id = -3204;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 Allocated is 100 post-AR run (invoice 4 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -50
      FROM invoice WHERE id = -3205;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 Allocated is 50 post-AR run (invoice 5 series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -37.5
    from acc_trans
     where trans_id = -3202 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 COGS is 37.50, (invoice 2, series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -62.5
    from acc_trans
     where trans_id = -3203 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 COGS is 62.5, (invoice 3, series 3)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = -50
    from acc_trans
     where trans_id = -3205 and chart_id = -3102;
    SELECT results_eq('test',ARRAY[true],'post-ap-5 COGS is 50, (invoice 3, series 5)');
    DEALLOCATE test;

/*
    # Series 4, AP Reversal


*/
    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-4201,  true, 'test3001', now() - '10 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-4201, -4201, -4, -100, 0, 1);

    SELECT cogs__add_for_ap_line(-4201);

    PREPARE test AS SELECT allocated = 0
      FROM invoice WHERE id = -4201;
    SELECT results_eq('test',ARRAY[true],'post-ap-1 Allocated is 0 (invoice 1 series 4)');
    DEALLOCATE test;

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-4202,  true, 'test4002', now() - '10 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-4202, -4202, -4, 75, 0, 1);

    SELECT cogs__add_for_ap_line(-4202);

    PREPARE test AS SELECT allocated = 75
      FROM invoice WHERE id = -4201;
    SELECT results_eq('test',ARRAY[true],'post-ap-2 Allocated is 75 (invoice 1 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -4202;
    SELECT results_eq('test',ARRAY[true],'post-ap-2 Allocated is -75 (invoice 2 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = 0
      FROM acc_trans
     WHERE trans_id = -4202 and chart_id = -4102;
    SELECT results_eq('test',ARRAY[true],'post-ap-2 COGS is 0, invoice 2, series 4)');
    DEALLOCATE test;

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-4203,  true, 'test4003', now() - '7 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-4203, -4203, -4, -100, 0, 0.5);

    SELECT cogs__add_for_ap_line(-4203);

    PREPARE test AS SELECT allocated = 75
      FROM invoice WHERE id = -4201;
    SELECT results_eq('test',ARRAY[true],'post-ap-3 Allocated is 75 (invoice 1 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -4202;
    SELECT results_eq('test',ARRAY[true],'post-ap-3 Allocated is -75 (invoice 2 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 0
      FROM invoice WHERE id = -4203;
    SELECT results_eq('test',ARRAY[true],'post-ap-3 Allocated is 0 (invoice 3 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = 0
      FROM acc_trans
     WHERE trans_id = -4202 and chart_id = -4102;
    SELECT results_eq('test',ARRAY[true],'post-ap-3 COGS is 0, invoice 2, series 4)');
    DEALLOCATE test;

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-4204,  true, 'test4002', now() - '5 days'::interval, -1000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-4204, -4204, -4, 75, 0, 1);

    SELECT cogs__add_for_ap_line(-4204);

    PREPARE test AS SELECT allocated = 100
      FROM invoice WHERE id = -4201;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 100 (invoice 1 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -4202;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is -75 (invoice 2 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 50
      FROM invoice WHERE id = -4203;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 50 (invoice 3 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = -75
      FROM invoice WHERE id = -4204;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 Allocated is 75 (invoice 4 series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = 0
      FROM acc_trans
     WHERE trans_id = -4202 and chart_id = -4102;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 COGS is 0, invoice 2, series 4)');
    DEALLOCATE test;

    PREPARE test AS SELECT sum(amount_bc) = 25
      FROM acc_trans
     WHERE trans_id = -4204 and chart_id = -4102;
    SELECT results_eq('test',ARRAY[true],'post-ap-4 COGS is 25, invoice 2, series 4)');
    DEALLOCATE test;

--    SELECT results_eq('test',
--        $$ SELECT cogs__add_for_ar_line(i.id) = 0
--        FROM invoice i JOIN ar ON ar.id = i.trans_id
--        WHERE i.id < -1000 $$,
--        ARRAY[true],'multi-call-safe ar cogs, id ' || i.id);

--    SELECT results_eq('test',
--        $$ SELECT cogs__add_for_ap_line(i.id) = 0
--           FROM invoice i JOIN ap ON ap.id = i.trans_id
--           WHERE i.id < -1000 $$,
--    ARRAY[true],'multi-call-safe ap cogs, id ' || i.id);




/*
    # Series 5, AR reversal


*/

    ---------------------------------------
    -- Step 1:  Simple reversal of invoice without allocation
    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5201,  true, 'test5001', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5201, -5201, -5, 150, 0, 3);

    SELECT cogs__add_for_ar_line(-5201);

    PREPARE test AS SELECT allocated = 0
      FROM invoice WHERE id = -5201;
    SELECT results_eq('test',ARRAY[true],'post-ar-1, allocation invoice 1 series 5 is 0; ');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5202,  true, 'test5002', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5202, -5202, -5, -150, 0, 3);

    SELECT cogs__add_for_ar_line(-5202);

    PREPARE test AS SELECT allocated = -150
      FROM invoice WHERE id = -5201;
    SELECT results_eq('test',ARRAY[true],'post-ar-2, allocation invoice 1 series 5 is -150; ');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 150
      FROM invoice WHERE id = -5202;
    SELECT results_eq('test',ARRAY[true],'post-ar-2, allocation invoice 2 series 5 is 150; ');
    DEALLOCATE test;

    ---------------------------------------
    -- Step 2:  Reversal of AR invoice with allocation, reallocates to invoice without and AP

    -- Test outline:
    --  * Set up an ar invoice and an ap invoice, each at 150 units
    --  * Allocate these against each other
    --  * Set up another ar invoice at 75 units
    --  * Allocate the new invoice / no units availeble == no effect
    --  * Reverse the original AR invoice at 150 units
    --  * Allocate the reversal invoice
    --  * The second AR invoice is now allocated
    --  * The AP invoice is 50% de-allocated

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5203,  true, 'test5003', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5203, -5203, -5, 150, 0, 3);

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5204,  true, 'test5004', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5204, -5204, -5, -150, 0, 3);

    SELECT is(
              cogs__add_for_ap_line(-5204),
              150::numeric,
              'ar-1, allocation invoice 3 series 5'
              );
    SELECT is(
              sum(amount_bc),
              -450::numeric,
              'ar-1, cogs 1 series 5, expense account total')
     FROM acc_trans WHERE chart_id = -5102;

    PREPARE test AS SELECT allocated = -150
                    FROM invoice WHERE id = -5203;
    SELECT results_eq('test',ARRAY[true],'post-ar-1, allocation invoice 3 series 5 is -150; ');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 150
                    FROM invoice WHERE id = -5204;
    SELECT results_eq('test',ARRAY[true],'post-ar-1, allocation invoice 4 series 5 is 150; ');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5205,  true, 'test5005', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5205, -5205, -5, 75, 0, 3);

    SELECT is(
              cogs__add_for_ar_line(-5205),
              0::numeric,
              'ar-1, allocation invoice 5 series 5'
              );
    SELECT is(
              sum(amount_bc),
              -450::numeric,
              'ar-1, cogs 2 series 5, expense account total')
     FROM acc_trans WHERE chart_id = -5102;

    PREPARE test AS SELECT allocated = 0
      FROM invoice WHERE id = -5205;
    SELECT results_eq('test',ARRAY[true],'post-ar-2, allocation invoice 5 series 5 is 0');
    DEALLOCATE test;

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5206,  true, 'test5006-rev3', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5206, -5206, -5, -150, 0, 3);

    SELECT is(
              cogs__add_for_ar_line(-5206),
              -150::numeric,
              'ar-1, allocation invoice 6 series 5'
              );
    SELECT is(
              sum(amount_bc),
              -225::numeric,
              'ar-1, cogs 3 series 5, expense account total')
     FROM acc_trans WHERE chart_id = -5102;

    PREPARE test AS SELECT allocated = -75
                    FROM invoice WHERE id = -5205;
    SELECT results_eq('test',ARRAY[true],'post-ar-3, allocation invoice 5 series 5 is -75');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 150
                    FROM invoice WHERE id = -5206;
    SELECT results_eq('test',ARRAY[true],'post-ar-3, allocation invoice 6 series 5 is 150');
    DEALLOCATE test;

    PREPARE test AS SELECT allocated = 75
       FROM invoice WHERE id = -5204;
    SELECT results_eq('test',ARRAY[true],'post-ar-3, allocation invoice 4 series 5 is -75');
    DEALLOCATE test;


    ---------------------------------------
    -- Step 3:  Reversal of AP invoice with allocation (reallocates to invoice without and removes AR allocation)

    -- TODO
    -- Test outline:
    --  * Set up an ap invoice and an ar invoice, each at 150 units
    --  * Allocate these against each other
    --  * Set up another ap invoice at 75 units
    --  * Allocate the new invoice / no units available == no effect
    --  * Reverse the original AP invoice at 150 units
    --  * Allocate the reversal invoice
    --  * The second AP invoice is now allocated
    --  * The AR invoice is 50% de-allocated

    INSERT INTO ar (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5207,  true, 'test5007', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5207, -5207, -6, 150, 0, 3);

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5208,  true, 'test5008', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5208, -5208, -6, -150, 0, 3);

    SELECT is(
              cogs__add_for_ar_line(-5207)::numeric,
              150::numeric,
              'ar-1, cogs calculation series 5 invoices 8,7');
    SELECT is(
              sum(amount_bc),
              -450::numeric,
              'ar-1, cogs 2 series 5, expense account total')
     FROM acc_trans WHERE chart_id = -6102;

    SELECT is(ARRAY(select allocated from invoice where id in (-5207, -5208) order by id),
              ARRAY[150, -150]::numeric[],
              'post-ar-1, allocation invoice 8,7 series 5 is 150,-150; ');

    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5209,  true, 'test5009', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5209, -5209, -6, -75, 0, 3);

    SELECT is(
              cogs__add_for_ap_line(-5209)::numeric,
              0::numeric,
              'ap-1, cogs calculation series 5 invoices 9');
    SELECT is(
              sum(amount_bc),
              -450::numeric,
              'ap-1, cogs series 5, expense account total')
     FROM acc_trans WHERE chart_id = -6102;

    SELECT is(allocated, 0::numeric, 'post-ap-1, allocation invoice 9 series 5 is 0')
      FROM invoice WHERE id = -5209;


    INSERT INTO ap (id, invoice, invnumber, transdate, entity_credit_account)
    VALUES (-5210,  true, 'test5010-rev8', now() - '4 days'::interval, -2000);
    INSERT INTO invoice (id, trans_id, parts_id, qty, allocated, sellprice)
    VALUES (-5210, -5210, -6, 150, 0, 3);

    SELECT is(
              cogs__add_for_ap_line(-5210)::numeric,
              -150::numeric,
              'ap-2, cogs calculation series 5 invoice 10');
    SELECT is(
              sum(amount_bc),
              -225::numeric,
              'ap-2, cogs series 5, expense account total')
     FROM acc_trans WHERE chart_id = -6102;

    SELECT is(ARRAY(select allocated from invoice where id in (-5207, -5208, -5209, -5210) order by id),
              ARRAY[-150, 75, 150, -75]::numeric[],
              'post-ap-2, allocation invoice 10,9,8,7 series 5 is -150,75,150,-75; ');


/*
    # Goods history search


*/

    PREPARE test AS select count(*) = 30
  from goods__history(null, null, null, null, null, false, false, false, false, true, true);
    select results_eq('test', ARRAY[true], 'get correct count of ar and ap lines from inv. history (30)');
     DEALLOCATE test;

    PREPARE test AS select count(*) = 15
  from goods__history(null, null, null, null, null, false, false, false, false, true, false);
    select results_eq('test', ARRAY[true], 'get correct count of ar lines from inv. history');
     DEALLOCATE test;

    PREPARE test AS select count(*) = 15
  from goods__history(null, null, null, null, null, false, false, false, false, false, true);
    select results_eq('test', ARRAY[true], 'get correct count (15) of ap lines from inv. history');
     DEALLOCATE test;

    PREPARE test AS select count(*) = 0
  from goods__history(null, null, null, null, null, false, false, false, false, false, false);
    select results_eq('test', ARRAY[true], 'get correct count (0) of ap lines from inv. history with all exclused');
     DEALLOCATE test;

    PREPARE test AS select count(*) = 30
  from goods__history(null, null, null, null, null, null, null, null, null, null, null);
    select results_eq('test', ARRAY[true], 'get correct count (30) of ar and ap lines from inv. history with all default');
     DEALLOCATE test;

    -- Finish the tests and clean up.
    SELECT * FROM finish();

ROLLBACK;
