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

    -- Plan the tests.
    SELECT plan(58);

    -- Add data

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

    -- Validate required tables

    SELECT has_table('account_heading');
    SELECT has_table('account');
    SELECT has_table('account_checkpoint');
    SELECT has_table('account_link_description');
    SELECT has_table('account_link');
    SELECT has_table('account_translation');
    SELECT has_table('account_heading_translation');

    -- Validate required functions

    SELECT has_function('account__all_headings','{}'::text[]);
    SELECT has_function('account__delete',ARRAY['integer']);
    SELECT has_function('account__delete_translation',ARRAY['integer','text']);
    SELECT has_function('account__get_by_link_desc',ARRAY['text']);
    SELECT has_function('account__get_from_accno',ARRAY['text']);
    SELECT has_function('account_get',ARRAY['integer']);
    SELECT has_function('account__get_taxes','{}'::text[]);
    SELECT has_function('account_has_transactions',ARRAY['integer']);
    SELECT has_function('account_heading__check_tree','{}'::text[]);
    SELECT has_function('account_heading__delete',ARRAY['integer']);
    SELECT has_function('account_heading__delete_translation',ARRAY['integer','text']);
    SELECT has_function('account_heading__list','{}'::text[]);
    SELECT has_function('account_heading__list_translations',ARRAY['integer']);
    SELECT has_function('account_heading__save_translation',ARRAY['integer','text','text']);
    SELECT has_function('account_heading_get',ARRAY['integer']);
    SELECT has_function('account_heading_list','{}'::text[]);
    SELECT has_function('account_heading_save',ARRAY['integer','text','text','integer']);
    SELECT has_function('account__is_recon',ARRAY['text']);
    SELECT has_function('account__list_by_heading','{}'::text[]);
    SELECT has_function('account__list_translations',ARRAY['integer']);
    SELECT has_function('account__save',ARRAY['integer','text','text','character','text','integer','integer','boolean','boolean','text[]','boolean','boolean']);
    SELECT has_function('account__save_tax',ARRAY['integer','date','numeric','numeric','numeric','text','integer','integer','date']);
    SELECT has_function('account__save_translation',ARRAY['integer','text','text']);
    SELECT has_function('chart_get_ar_ap',ARRAY['integer']);
    SELECT has_function('chart_list_all','{}'::text[]);
    SELECT has_function('chart_list_cash',ARRAY['integer']);
    SELECT has_function('chart_list_discount',ARRAY['integer']);
    SELECT has_function('chart_list_overpayment',ARRAY['integer']);
    SELECT has_function('chart_list_search',ARRAY['text','text']);
    SELECT has_function('cr_coa_to_account_save',ARRAY['text','text']);
    SELECT has_function('get_link_descriptions',ARRAY['boolean','boolean']);
    SELECT has_function('gifi__list','{}'::text[]);
    SELECT has_function('report__coa','{}'::text[]);
    SELECT has_function('report_trial_balance',ARRAY['date','date','integer','integer','boolean']);

    -- Prepare specific data

    CREATE OR REPLACE FUNCTION test_account_link_description(
                    d TEXT, s BOOLEAN, c BOOLEAN)
    RETURNS BOOLEAN AS $$
    DECLARE ret BOOLEAN;
    BEGIN
       INSERT INTO account_link_description(description, summary, custom)
                   VALUES (d, s, c);
--       PREPARE test(TEXT,BOOLEAN,BOOLEAN) AS SELECT description = $1 AND summary = $2
--                  AND custom = $3 AND count(*) = 1
--               FROM account_link_description
--               WHERE description = $1
--               GROUP BY description;
--       SELECT results_eq('test(''' || d || ''',' || s || ',' || c || ')',ARRAY[true],'Account link description for ' || d) INTO ret;
--       DEALLOCATE test;
       RETURN ret;
    END $$ LANGUAGE plpgsql;


    SELECT test_account_link_description('AR_paid1', false, true);
    SELECT test_account_link_description('AP_paid1', false, true);
    SELECT test_account_link_description('AR_p', false, true);
    SELECT test_account_link_description('AP_p', false, true);
    SELECT test_account_link_description('AR_overp', false, true);
    SELECT test_account_link_description('AP_overpayment1', false, true);
    SELECT test_account_link_description('AP_overp', false, true);
    SELECT test_account_link_description('AR_overpayment1', false, true);

    SELECT account__save (null, accno, description, category::char(1),
                null, (select id from account_heading limit 1), null, false, false,
                case when link is not null then link::text[] else '{}' END,
                false, false)
      FROM (VALUES ('TEST testing 1', 'A', 'A', '00001', null),
                   ('TEST testing 2', 'A', 'A', '00002', null),
                   ('TEST AP 1', 'A', 'L', '00003', '{AP}'),
                   ('TEST AP 2', 'A', 'L', '00004', '{AP}'),
                   ('TEST AR 1', 'A', 'A', '00005', '{AR}'),
                   ('TEST AR 2', 'A', 'A', '00006', '{AR}'),
                   ('TEST AR PAID 1', 'A', 'A', '00007', '{AR_paid}'),
                   ('TEST AR PAID 2', 'A', 'A', '00008', '{AR_paid1}'),
                   ('TEST AR PAID 3', 'A', 'A', '00009', '{IC_tax,AR_paid}'),
                   ('TEST AR PAID 4 INVALID', 'A', 'A', '00010', '{AR_p}'),
                   ('TEST AP PAID 1', 'A', 'A', '00011', '{AP_paid}'),
                   ('TEST AP PAID 2', 'A', 'A', '00012', '{AP_paid1}'),
                   ('TEST AP PAID 3', 'A', 'A', '00013', '{IC_tax,AP_paid}'),
                   ('TEST AP PAID 4 INVALID', 'A', 'A', '00014', '{AP_p}'),
                   ('TEST AP Overpayment 1', 'A', 'A', '00015', '{AP_overpayment}'),
                   ('TEST AP Overpayment 2', 'A', 'A', '00016', '{AP_overpayment1}'),
                   ('TEST AP Overpayment 3', 'A', 'A', '00017', '{IC_tax,AP_overpayment}'),
                   ('TEST AP Overpayment 4 INVALID', 'A', 'A', '00018', '{AP_overp}'),
                   ('TEST AP Overpayment 1', 'A', 'A', '00019', '{AR_overpayment}'),
                   ('TEST AP Overpayment 2', 'A', 'A', '00020', '{AR_overpayment1}'),
                   ('TEST AP Overpayment 3', 'A', 'A', '00021', '{IC_tax,AR_overpayment}'),
                   ('TEST AP Overpayment 4 INVALID', 'A', 'A', '00022', '{AR_overp}')
           ) f (description, charttype, category, accno, link);

--psql:xt/42-account.pg:98: ERROR:  insert or update on table "account_link" violates foreign key constraint "account_link_description_fkey"
--DETAIL:  Key (description)=(AR_paid1) is not present in table "account_link_description".
--CONTEXT:  SQL statement "INSERT INTO account_link (account_id, description)
--                VALUES (t_id, t_link.val)"

    INSERT INTO entity_credit_account (id, meta_number, entity_id, entity_class, ar_ap_account_id, curr)
    values (-100, 'test1', -100, 1, -1000, 'XTS');

    INSERT INTO ap (invnumber, netamount_bc, amount_bc, entity_credit_account,
                    id, curr, netamount_tc, amount_tc)
    VALUES ('TEST', '0', '0', -100, -100, 'XTS', 0, 0);
    INSERT INTO acc_trans (trans_id, chart_id, amount_bc, curr, amount_tc)
    VALUES (-100, (select id from account where accno = '00002'), '0', 'XTS', 0);

    -- Run tests

    PREPARE test AS SELECT currval('account_id_seq') IS NOT NULL;
    SELECT results_eq('test',ARRAY[true],'Accounts created');
    DEALLOCATE test;

    PREPARE test AS SELECT account_has_transactions(
                            (SELECT id FROM account WHERE description = 'TEST testing 1')
                           ) IS FALSE;
    SELECT results_eq('test',ARRAY[true],'Chart 1 is orphaned');
    DEALLOCATE test;

    PREPARE test AS SELECT account_has_transactions(
                            (SELECT id FROM account WHERE accno = '00002')
                           ) IS TRUE;
    SELECT results_eq('test',ARRAY[true],'Chart 2 is not orphaned');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 22 FROM chart_list_all()
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'All Test Accounts Exist');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 2 FROM chart_list_cash(2)
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'List AR Cash Test Accounts');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 2 FROM chart_list_cash(1)
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'List AP Cash Test Accounts');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 2 FROM chart_list_overpayment(1)
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'List AP Overpayment Accts');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 2 FROM chart_list_overpayment(2)
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'List AR Overpayment Accts');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 2 FROM chart_get_ar_ap(1)
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'Test AP Accounts Are Found');
    DEALLOCATE test;

    PREPARE test AS SELECT count(*) = 2 FROM chart_get_ar_ap(2)
                    WHERE accno LIKE '0%' AND description LIKE 'TEST%';
    SELECT results_eq('test',ARRAY[true],'Test AR Accounts Are Found');
    DEALLOCATE test;


    -- Tests for get_link_descriptions function
    DELETE FROM account_link;
    DELETE FROM account_link_description;
    INSERT INTO account_link_description(description, summary, custom) VALUES
        ('Plain', false, false),
        ('Summary', true, false),
        ('Custom', false, true),
        ('CustomSummary', true, true);


    PREPARE test AS SELECT description FROM get_link_descriptions(NULL, NULL);
    SELECT set_eq(
        'test',
        ARRAY['Plain', 'Summary', 'CustomSummary', 'Custom'],
        $$get_link_descriptions (no filter) returns expected records$$
    );
    DEALLOCATE test;

    PREPARE test AS SELECT description FROM get_link_descriptions(TRUE, NULL);
    SELECT set_eq(
        'test',
        ARRAY['Summary', 'CustomSummary'],
        $$get_link_descriptions (Summary) returns expected records$$
    );
    DEALLOCATE test;

    PREPARE test AS SELECT description FROM get_link_descriptions(TRUE, FALSE);
    SELECT set_eq(
        'test',
        ARRAY['Summary'],
        $$get_link_descriptions (Summary, not Custom) returns expected records$$
    );
    DEALLOCATE test;

    PREPARE test AS SELECT description FROM get_link_descriptions(TRUE, TRUE);
    SELECT set_eq(
        'test',
        ARRAY['CustomSummary'],
        $$get_link_descriptions (Summary + Custom) returns expected records$$
    );
    DEALLOCATE test;

    PREPARE test AS SELECT description FROM get_link_descriptions(NULL, TRUE);
    SELECT set_eq(
        'test',
        ARRAY['CustomSummary', 'Custom'],
        $$get_link_descriptions (Custom) returns expected records$$
    );
    DEALLOCATE test;

    PREPARE test AS SELECT description FROM get_link_descriptions(FALSE, TRUE);
    SELECT set_eq(
        'test',
        ARRAY['Custom'],
        $$get_link_descriptions (Custom, not Summary) returns expected records$$
    );
    DEALLOCATE test;

    PREPARE test AS SELECT description FROM get_link_descriptions(FALSE, FALSE);
    SELECT set_eq(
        'test',
        ARRAY['Plain'],
        $$get_link_descriptions (Neither Custom nor Summary) returns expected records$$
    );
    DEALLOCATE test;


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

ROLLBACK;
