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

    -- Plan the tests.

    SELECT plan(17);

    -- Add data

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

    -- Validate required tables

    SELECT has_table('account');
    SELECT has_table('account_link');
    SELECT has_table('acc_trans');
    SELECT has_table('ap');
    SELECT has_table('business');
    SELECT has_table('company');
    SELECT has_table('entity_credit_account');
    SELECT has_table('session');
    SELECT has_table('users');

    -- Validate required functions

--    SELECT has_function('business_type__list','{}'::text[]);


    -- Validate ledger being balanced
    SELECT ok( coalesce(abs(sum(amount_bc)),0) < 0.01,
               'base currency is balanced' )
      FROM acc_trans
     WHERE approved;

    --- COMMON SETUP

    insert into currency values ('xts', 'xts');
    insert into users (entity_id, username, id)
    values (-200, '_test1', -200);
    INSERT INTO session (users_id, last_used, token)
    values (currval('users_id_seq'),  now(), md5('test2'));
    insert into session (session_id, users_id, token, last_used)
    values (-200, -200, md5(random()::text), now());

    WITH a (accno, description, category) as (
     values ('00001'::text, 'testing AP'::text, 'L'::text ),
           ('00002', 'testing AP cost', 'E'),
           ('00003', 'testing cash', 'A'),
           ('00004', 'fx gain', 'I'),
           ('00005', 'fx loss', 'E')
    )
    INSERT INTO account (accno, description, category, heading)
    SELECT a.accno, a.description, a.category, h.id
    FROM account_heading h
    JOIN a ON h.accno = '000000000000000000000';

    INSERT INTO defaults VALUES ('fxgain_accno_id',
           (select id from account where accno = '00004'));
    INSERT INTO defaults VALUES ('fxloss_accno_id',
           (select id from account where accno = '00005'));

    INSERT INTO account_link (account_id, description)
    SELECT id, 'AP' FROM account WHERE accno = '00001'
    UNION
    SELECT id, 'AP_amount' FROM account WHERE accno = '00002'
    UNION
    SELECT id, 'AP_paid' FROM account WHERE accno = '00003';

    -- TEST 1: payment_post() with fx rate 1.1

    INSERT INTO company (id, legal_name, entity_id) VALUES (-101, 'TEST', -101);
    INSERT INTO business (id, description) values (-101, 'test');
    INSERT INTO entity_credit_account (id, meta_number, threshold, entity_id, entity_class, business_id, ar_ap_account_id, curr)
         VALUES (-101, 'TEST1', 100000, -101, 1, -101, -1000, 'xts');

    INSERT INTO ap (id, transdate, amount_bc, amount_tc, invnumber, curr, entity_credit_account)
         VALUES (-11, '1901-01-01', 100, 110, 'inv_test1', 'xts', -101);
    INSERT INTO acc_trans (trans_id, transdate, amount_bc, curr, amount_tc, approved, chart_id)
         VALUES (-11, '1901-01-01', 100, 'xts', 110, 't', (select id from account where accno = '00001')),
                (-11, '1901-01-01', -100, 'xts', -110, 't', (select id from account where accno = '00002'));

    -- Pay the invoice in full
    SELECT * FROM
        payment_post('1901-01-01', -- datepaid
                     1,            -- account_class
                     -101,         -- entity_credit_id
                     'xts',
                     1.10,
                     NULL,         -- notes
                     'This gl movement is a consequence of a payment transaction',
                     ARRAY[(SELECT id FROM account WHERE accno = '00003')], -- cash_account_id
                     ARRAY[110],       -- amount
                     ARRAY['cash '],   -- source
                     ARRAY[NULL],      -- memo
                     ARRAY[-11],       -- transaction_id
                     NULL,  -- op_amount
                     NULL,  -- op_cash_account_id
                     NULL,  -- op_source
                     NULL,  -- op_memo
                     NULL,  -- op_account_id
                     NULL,  -- ovp_payment_id
                     't');  -- approved
    --     ARRAY[-11], ARRAY[], ARRAY[], ARRAY[], ARRAY[], ARRAY[], NULL, 't');

    -- Run tests

    --TODO: 0.01? Ain't that dependent of the country
    PREPARE test AS SELECT abs(sum(amount_bc)) < 0.01
                        from acc_trans
                       where trans_id = -11
                         and chart_id = (select id from account where accno = '00001');
    SELECT results_eq('test',ARRAY[true],'Local currency marks fully paid');
    DEALLOCATE test;

    --TODO: 0.01? Ain't that dependent of the country
    PREPARE test AS SELECT abs(sum(amount_tc)) < 0.01
                        from acc_trans
                       where trans_id = -11
                         and chart_id = (select id from account where accno = '00001');
    SELECT results_eq('test',ARRAY[true],'Foreign currency marks fully paid');
    DEALLOCATE test;


    -- Test 2: payment_bulk_post

    INSERT INTO ap (id, transdate, amount_bc, amount_tc, invnumber, curr, entity_credit_account)
         VALUES (-12, '1901-01-02', 100, 110, 'inv_test2', 'xts', -101);
    INSERT INTO acc_trans (trans_id, transdate, amount_bc, curr, amount_tc, approved, chart_id)
         VALUES (-12, '1901-01-02', 100, 'xts', 110, 't', (select id from account where accno = '00001')),
                (-12, '1901-01-02', -100, 'xts', -110, 't', (select id from account where accno = '00002'));


    SELECT payment_bulk_post(ARRAY[ARRAY[-12,110]],
                             batch_create('TestBatch', 'TestBatch',
                             'payment', -- payment
                             '1901-01-03'::date), 'source',
                             '00001', '00003',
                             '1901-01-03'::date, 1, 1.10, 'xts');

    PREPARE test AS SELECT abs(sum(amount_bc)) < 0.01
                        from acc_trans
                       where trans_id = -12
                         and chart_id = (select id from account where accno = '00001');
    SELECT results_eq('test',ARRAY[true],'Local currency marks fully paid');
    DEALLOCATE test;

    PREPARE test AS SELECT abs(sum(amount_tc)) < 0.01
                        from acc_trans
                       where trans_id = -12
                         and chart_id = (select id from account where accno = '00001');
    SELECT results_eq('test',ARRAY[true],'Foreign currency marks fully paid');
    DEALLOCATE test;



   -- Test 3 + 4: payment without fx accounts set
   DELETE FROM defaults
         WHERE setting_key IN ('fxgain_accno_id', 'fxloss_accno_id');


    -- Test 3: Single payment
    INSERT INTO ap (id, transdate, amount_bc, amount_tc, invnumber, curr, entity_credit_account)
         VALUES (-13, '1901-01-01', 100, 110, 'inv_test1', 'xts', -101);
    INSERT INTO acc_trans (trans_id, transdate, amount_bc, curr, amount_tc, approved, chart_id)
         VALUES (-13, '1901-01-01', 100, 'xts', 110, 't', (select id from account where accno = '00001')),
                (-13, '1901-01-01', -100, 'xts', -110, 't', (select id from account where accno = '00002'));


    PREPARE test AS
        SELECT * FROM
        payment_post('1901-01-01', -- datepaid
                     1,            -- account_class
                     -101,         -- entity_credit_id
                     'xts',
                     1.10,
                     NULL,         -- notes
                     'This gl movement is a consequence of a payment transaction',
                     ARRAY[(SELECT id FROM account WHERE accno = '00003')], -- cash_account_id
                     ARRAY[110],       -- amount
                     ARRAY['cash '],   -- source
                     ARRAY[NULL],      -- memo
                     ARRAY[-13],       -- transaction_id
                     NULL,  -- op_amount
                     NULL,  -- op_cash_account_id
                     NULL,  -- op_source
                     NULL,  -- op_memo
                     NULL,  -- op_account_id
                     NULL,  -- ovp_payment_id
                     't');  -- approved

    SELECT throws_ok('test', null,
                     'single payment should throw an exception without gain/loss account');
    DEALLOCATE test;


    -- Test 4: Bulk payment
    INSERT INTO ap (id, transdate, amount_bc, amount_tc, invnumber, curr, entity_credit_account)
         VALUES (-14, '1901-01-02', 100, 110, 'inv_test2', 'xts', -101);
    INSERT INTO acc_trans (trans_id, transdate, amount_bc, curr, amount_tc, approved, chart_id)
         VALUES (-14, '1901-01-02', 100, 'xts', 110, 't', (select id from account where accno = '00001')),
                (-14, '1901-01-02', -100, 'xts', -110, 't', (select id from account where accno = '00002'));


    PREPARE test AS
        SELECT payment_bulk_post(ARRAY[ARRAY[-14,110]],
                             batch_create('TestBatch', 'TestBatch',
                             'payment', -- payment
                             '1901-01-03'::date), 'source',
                             '00001', '00003',
                             '1901-01-03'::date, 1, 1.10, 'xts');
    SELECT throws_ok('test', null,
                     'bulk payment should throw an exception without gain/loss account');
    DEALLOCATE test;



    -- Still balanced?
    SELECT ok( abs(sum(amount_bc)) < 0.01,
               'base currency is balanced; ' || abs(sum(amount_bc)) )
      FROM acc_trans
     WHERE approved;


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

ROLLBACK;
