dodil/erp-brick-payments

DODIL ERP brick: payments

src/brick_payments/schema.sql

-- payments (pay_): receipts, allocations, refunds, collections, statements, credit, configuration and the Odoo migration.
-- Every table prefixed `pay_`, a natural primary key each (never SERIAL), money NUMERIC(18,2), rates NUMERIC(19,4),
-- creation columns last so a later column is an append. Additive only. Kept equal to infrastructure/tables.py by tests/test_schema.py.

CREATE TABLE IF NOT EXISTS pay_allocation (
    source_kind   VARCHAR NOT NULL,
    source_id     VARCHAR NOT NULL,
    invoice_id    VARCHAR NOT NULL,
    seq           INTEGER NOT NULL,
    amount        NUMERIC(18,2),
    currency      VARCHAR,
    allocated_on  DATE,
    allocated_by  VARCHAR,
    reason        VARCHAR,
    reverses_seq  INTEGER,
    suggestion_id VARCHAR,
    decided_how   VARCHAR,
    origin        VARCHAR,
    bp_id         BIGINT,
    source_amount NUMERIC(18,2),
    created_at    TIMESTAMP,
    updated_at    TIMESTAMP,
    PRIMARY KEY (source_kind, source_id, invoice_id, seq)
);

CREATE TABLE IF NOT EXISTS pay_bank_account (
    bank_account_id          VARCHAR NOT NULL,
    name                     VARCHAR,
    currency                 VARCHAR,
    iban_or_sort_code_masked VARCHAR,
    gl_account_id            VARCHAR,
    origin                   VARCHAR,
    house_bank_id            VARCHAR,
    company_code             VARCHAR,
    purposes                 VARCHAR,
    account_name             VARCHAR,
    status                   VARCHAR,
    closed_from              DATE,
    account_ref              VARCHAR,
    iban                     VARCHAR,
    created_at               TIMESTAMP,
    updated_at               TIMESTAMP,
    PRIMARY KEY (bank_account_id)
);

CREATE TABLE IF NOT EXISTS pay_collection (
    bp_id        BIGINT NOT NULL,
    kind         VARCHAR NOT NULL,
    level        INTEGER NOT NULL,
    ref_id       VARCHAR NOT NULL,
    invoice_id   VARCHAR,
    occurred_on  DATE,
    promise_date DATE,
    reason       VARCHAR,
    outcome      VARCHAR,
    note         VARCHAR,
    draft_text   VARCHAR,
    status       VARCHAR,
    origin       VARCHAR,
    recorded_by  VARCHAR,
    created_at   TIMESTAMP,
    updated_at   TIMESTAMP,
    PRIMARY KEY (bp_id, kind, level, ref_id)
);

CREATE TABLE IF NOT EXISTS pay_credit (
    bp_id               BIGINT NOT NULL,
    valid_from          DATE NOT NULL,
    credit_limit_amount NUMERIC(18,2),
    currency            VARCHAR,
    reason              VARCHAR,
    set_by              VARCHAR,
    set_at              TIMESTAMP,
    origin              VARCHAR,
    created_at          TIMESTAMP,
    updated_at          TIMESTAMP,
    PRIMARY KEY (bp_id, valid_from)
);

CREATE TABLE IF NOT EXISTS pay_credit_override (
    bp_id      BIGINT NOT NULL,
    kind       VARCHAR NOT NULL,
    starts_at  TIMESTAMP NOT NULL,
    ends_on    DATE,
    reason     VARCHAR,
    set_by     VARCHAR,
    origin     VARCHAR,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    PRIMARY KEY (bp_id, kind, starts_at)
);

CREATE TABLE IF NOT EXISTS pay_match_suggestion (
    suggestion_id  VARCHAR NOT NULL,
    payment_id     VARCHAR,
    proposed_lines VARCHAR,
    evidence       VARCHAR,
    confidence     NUMERIC(5,2),
    model          VARCHAR,
    exact          INTEGER,
    status         VARCHAR,
    decided_by     VARCHAR,
    decided_at     TIMESTAMP,
    decided_lines  VARCHAR,
    reviewed_by    VARCHAR,
    reviewed_at    TIMESTAMP,
    created_at     TIMESTAMP,
    updated_at     TIMESTAMP,
    PRIMARY KEY (suggestion_id)
);

CREATE TABLE IF NOT EXISTS pay_migration_run (
    run_id         VARCHAR NOT NULL,
    params         VARCHAR,
    odoo_figures   VARCHAR,
    counts         VARCHAR,
    ran_by         VARCHAR,
    ran_at         TIMESTAMP,
    signed_by      VARCHAR,
    signed_at      TIMESTAMP,
    signed_figures VARCHAR,
    created_at     TIMESTAMP,
    updated_at     TIMESTAMP,
    PRIMARY KEY (run_id)
);

CREATE TABLE IF NOT EXISTS pay_odoo_map (
    odoo_ref     VARCHAR NOT NULL,
    target_table VARCHAR,
    target_key   VARCHAR,
    migrated_at  TIMESTAMP,
    created_at   TIMESTAMP,
    updated_at   TIMESTAMP,
    PRIMARY KEY (odoo_ref)
);

CREATE TABLE IF NOT EXISTS pay_receipt (
    payment_id         VARCHAR NOT NULL,
    bp_id              BIGINT,
    currency           VARCHAR,
    amount             NUMERIC(18,2),
    received_on        DATE,
    method             VARCHAR,
    bank_account_id    VARCHAR,
    bank_reference     VARCHAR,
    remittance_text    VARCHAR,
    status             VARCHAR,
    batch_id           VARCHAR,
    fx_rate            NUMERIC(19,4),
    returned_on        DATE,
    bank_return_ref    VARCHAR,
    reversed_on        DATE,
    origin             VARCHAR,
    recorded_by        VARCHAR,
    recorded_at        TIMESTAMP,
    cleared_by         VARCHAR,
    recorded_on        DATE,
    return_reason_code VARCHAR,
    statement_line_id  VARCHAR,
    created_at         TIMESTAMP,
    updated_at         TIMESTAMP,
    PRIMARY KEY (payment_id)
);

CREATE TABLE IF NOT EXISTS pay_receipt_ref (
    bank_account_id VARCHAR NOT NULL,
    bank_reference  VARCHAR NOT NULL,
    payment_id      VARCHAR,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (bank_account_id, bank_reference)
);

CREATE TABLE IF NOT EXISTS pay_refund (
    refund_id    VARCHAR NOT NULL,
    bp_id        BIGINT,
    currency     VARCHAR,
    amount       NUMERIC(18,2),
    status       VARCHAR,
    requested_by VARCHAR,
    requested_at TIMESTAMP,
    approved_by  VARCHAR,
    approved_at  TIMESTAMP,
    approved_on  DATE,
    reason       VARCHAR,
    bank_ref     VARCHAR,
    paid_on      DATE,
    origin       VARCHAR,
    requested_sub VARCHAR,
    created_at   TIMESTAMP,
    updated_at   TIMESTAMP,
    PRIMARY KEY (refund_id)
);

CREATE TABLE IF NOT EXISTS pay_reminder_level (
    policy_id      VARCHAR NOT NULL,
    level          INTEGER NOT NULL,
    days_after_due INTEGER,
    channel        VARCHAR,
    template       VARCHAR,
    mode           VARCHAR,
    created_at     TIMESTAMP,
    updated_at     TIMESTAMP,
    PRIMARY KEY (policy_id, level)
);

CREATE TABLE IF NOT EXISTS pay_settings (
    setting_key VARCHAR NOT NULL,
    value       VARCHAR,
    changes     VARCHAR,
    created_at  TIMESTAMP,
    updated_at  TIMESTAMP,
    PRIMARY KEY (setting_key)
);

CREATE TABLE IF NOT EXISTS pay_settings_log (
    setting_key VARCHAR NOT NULL,
    seq         INTEGER NOT NULL,
    old_value   VARCHAR,
    new_value   VARCHAR,
    changed_by  VARCHAR,
    changed_at  TIMESTAMP,
    created_at  TIMESTAMP,
    updated_at  TIMESTAMP,
    PRIMARY KEY (setting_key, seq)
);

CREATE TABLE IF NOT EXISTS pay_statement (
    bp_id           BIGINT NOT NULL,
    as_at           DATE NOT NULL,
    currency        VARCHAR NOT NULL,
    closing_balance NUMERIC(18,2),
    sent_at         TIMESTAMP,
    sent_by         VARCHAR,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (bp_id, as_at, currency)
);

-- audit 1 (00002_audit1): the claim rows that make two writers of the same money collide, and the dated time zone.
CREATE TABLE IF NOT EXISTS pay_invoice_claim (
    invoice_id VARCHAR NOT NULL,
    n          INTEGER NOT NULL,
    claimed_at TIMESTAMP,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    PRIMARY KEY (invoice_id, n)
);

CREATE TABLE IF NOT EXISTS pay_source_claim (
    source_kind VARCHAR NOT NULL,
    source_id   VARCHAR NOT NULL,
    n           INTEGER NOT NULL,
    claimed_at  TIMESTAMP,
    created_at  TIMESTAMP,
    updated_at  TIMESTAMP,
    PRIMARY KEY (source_kind, source_id, n)
);

CREATE TABLE IF NOT EXISTS pay_timezone (
    valid_from DATE NOT NULL,
    zone       VARCHAR,
    set_by     VARCHAR,
    set_at     TIMESTAMP,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    PRIMARY KEY (valid_from)
);

-- v4 slice A (00003_statements_dd): statements and their lines, rules, remittances, direct debits, claims and objects.

CREATE TABLE IF NOT EXISTS pay_claim (
    claim_scope VARCHAR NOT NULL,
    claim_key   VARCHAR NOT NULL,
    n           INTEGER NOT NULL,
    ref         VARCHAR,
    claimed_by  VARCHAR,
    claimed_at  TIMESTAMP,
    created_at  TIMESTAMP,
    updated_at  TIMESTAMP,
    PRIMARY KEY (claim_scope, claim_key, n)
);

CREATE TABLE IF NOT EXISTS pay_object (
    object_key   VARCHAR NOT NULL,
    content_type VARCHAR,
    sha256       VARCHAR,
    body         VARCHAR,
    created_at   TIMESTAMP,
    updated_at   TIMESTAMP,
    PRIMARY KEY (object_key)
);

CREATE TABLE IF NOT EXISTS pay_house_bank (
    house_bank_id VARCHAR NOT NULL,
    name          VARCHAR,
    bic           VARCHAR,
    sort_code     VARCHAR,
    address       VARCHAR,
    sun           VARCHAR,
    creditor_id   VARCHAR,
    created_at    TIMESTAMP,
    updated_at    TIMESTAMP,
    PRIMARY KEY (house_bank_id)
);

CREATE TABLE IF NOT EXISTS pay_bank_statement (
    statement_id    VARCHAR NOT NULL,
    bank_account_id VARCHAR,
    from_date       DATE,
    to_date         DATE,
    opening_balance NUMERIC(18,2),
    closing_balance NUMERIC(18,2),
    format          VARCHAR,
    file_key        VARCHAR,
    lifecycle       VARCHAR,
    reconciled_by   VARCHAR,
    reconciled_at   TIMESTAMP,
    imported_by     VARCHAR,
    imported_on     DATE,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (statement_id)
);

CREATE TABLE IF NOT EXISTS pay_statement_line (
    line_id                     VARCHAR NOT NULL,
    statement_id                VARCHAR,
    bank_account_id             VARCHAR,
    booked_on                   DATE,
    value_on                    DATE,
    amount                      NUMERIC(18,2),
    currency                    VARCHAR,
    counterparty_name           VARCHAR,
    counterparty_account_masked VARCHAR,
    text                        VARCHAR,
    bank_tx_code                VARCHAR,
    lifecycle                   VARCHAR,
    matched_kind                VARCHAR,
    matched_ref                 VARCHAR,
    account_id                  VARCHAR,
    tax_code                    VARCHAR,
    cost_centre                 VARCHAR,
    journal_id                  VARCHAR,
    decided_how                 VARCHAR,
    decided_by                  VARCHAR,
    decided_on                  DATE,
    receipt_image               VARCHAR,
    vat_amount                  NUMERIC(18,2),
    vat_reclaimed               VARCHAR,
    reversal_reason             VARCHAR,
    created_at                  TIMESTAMP,
    updated_at                  TIMESTAMP,
    PRIMARY KEY (line_id)
);

CREATE TABLE IF NOT EXISTS pay_line_suggestion (
    suggestion_id  VARCHAR NOT NULL,
    line_id        VARCHAR,
    account_id     VARCHAR,
    tax_code       VARCHAR,
    cost_centre    VARCHAR,
    receipt_needed VARCHAR,
    evidence       VARCHAR,
    confidence     VARCHAR,
    model          VARCHAR,
    status         VARCHAR,
    decided_by     VARCHAR,
    decided_on     DATE,
    created_at     TIMESTAMP,
    updated_at     TIMESTAMP,
    PRIMARY KEY (suggestion_id)
);

CREATE TABLE IF NOT EXISTS pay_reconciliation_rule (
    rule_id               VARCHAR NOT NULL,
    valid_from            DATE NOT NULL,
    bank_account_id       VARCHAR,
    direction             VARCHAR,
    text_contains         VARCHAR,
    counterparty_contains VARCHAR,
    amount_min            NUMERIC(18,2),
    amount_max            NUMERIC(18,2),
    account_id            VARCHAR,
    tax_code              VARCHAR,
    cost_centre           VARCHAR,
    mode                  VARCHAR,
    set_by                VARCHAR,
    created_at            TIMESTAMP,
    updated_at            TIMESTAMP,
    PRIMARY KEY (rule_id, valid_from)
);

CREATE TABLE IF NOT EXISTS pay_remittance (
    remittance_id    VARCHAR NOT NULL,
    line_no          INTEGER NOT NULL,
    file_ref         VARCHAR,
    format           VARCHAR,
    payer            VARCHAR,
    payment_id       VARCHAR,
    bp_id            BIGINT,
    invoice_ref      VARCHAR,
    invoice_id       VARCHAR,
    amount           NUMERIC(18,2),
    currency         VARCHAR,
    deduction_reason VARCHAR,
    status           VARCHAR,
    suggestion_id    VARCHAR,
    imported_by      VARCHAR,
    created_at       TIMESTAMP,
    updated_at       TIMESTAMP,
    PRIMARY KEY (remittance_id, line_no)
);

CREATE TABLE IF NOT EXISTS pay_dd_mandate (
    sun                  VARCHAR NOT NULL,
    mandate_ref          VARCHAR NOT NULL,
    bp_id                BIGINT,
    bank_account_id      VARCHAR,
    payer_sort_code      VARCHAR,
    payer_account_masked VARCHAR,
    payer_account_name   VARCHAR,
    scheme               VARCHAR,
    lifecycle            VARCHAR,
    lodged_on            DATE,
    auddis_result        VARCHAR,
    cancelled_reason     VARCHAR,
    cancel_lodged_on     DATE,
    last_collected_on    DATE,
    recorded_on          DATE,
    recorded_by          VARCHAR,
    notice_days          INTEGER,
    ends_on              DATE,
    disputed_on          DATE,
    created_at           TIMESTAMP,
    updated_at           TIMESTAMP,
    PRIMARY KEY (sun, mandate_ref)
);

CREATE TABLE IF NOT EXISTS pay_dd_mandate_details (
    sun            VARCHAR NOT NULL,
    mandate_ref    VARCHAR NOT NULL,
    valid_from     DATE NOT NULL,
    sort_code      VARCHAR,
    account_number VARCHAR,
    source         VARCHAR,
    created_at     TIMESTAMP,
    updated_at     TIMESTAMP,
    PRIMARY KEY (sun, mandate_ref, valid_from)
);

CREATE TABLE IF NOT EXISTS pay_dd_run (
    run_id          VARCHAR NOT NULL,
    bank_account_id VARCHAR,
    collection_date DATE,
    input_day       DATE,
    lifecycle       VARCHAR,
    prepared_by     VARCHAR,
    prepared_by_sub VARCHAR,
    approved_by     VARCHAR,
    approved_by_sub VARCHAR,
    file_key        VARCHAR,
    submission_ref  VARCHAR,
    total           NUMERIC(18,2),
    count           INTEGER,
    currency        VARCHAR,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (run_id)
);

CREATE TABLE IF NOT EXISTS pay_dd_collection (
    run_id             VARCHAR NOT NULL,
    mandate_ref        VARCHAR NOT NULL,
    bp_id              BIGINT,
    sun                VARCHAR,
    invoice_ids        VARCHAR,
    amount             NUMERIC(18,2),
    transaction_code   VARCHAR,
    notice_sent_on     DATE,
    status             VARCHAR,
    payment_id         VARCHAR,
    return_reason_code VARCHAR,
    returned_on        DATE,
    represented        VARCHAR,
    created_at         TIMESTAMP,
    updated_at         TIMESTAMP,
    PRIMARY KEY (run_id, mandate_ref)
);

-- v4 slice B (PAY-24..PAY-29): default receiving accounts, the unmasked-read audit, cash, deposit batches, forecast snapshots
CREATE TABLE IF NOT EXISTS pay_default_bank_account (
    company_code    VARCHAR NOT NULL,
    currency        VARCHAR NOT NULL,
    valid_from      DATE NOT NULL,
    bank_account_id VARCHAR,
    set_by          VARCHAR,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (company_code, currency, valid_from)
);

CREATE TABLE IF NOT EXISTS pay_bank_account_read (
    read_id         VARCHAR NOT NULL,
    bank_account_id VARCHAR,
    caller          VARCHAR,
    requested_at    TIMESTAMP,
    purpose         VARCHAR,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (read_id)
);

CREATE TABLE IF NOT EXISTS pay_cash_journal (
    cash_journal_id VARCHAR NOT NULL,
    company_code    VARCHAR,
    currency        VARCHAR,
    gl_account_id   VARCHAR,
    name            VARCHAR,
    status          VARCHAR,
    opening_balance NUMERIC(18,2),
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (cash_journal_id)
);

CREATE TABLE IF NOT EXISTS pay_cash_day (
    cash_journal_id       VARCHAR NOT NULL,
    day                   DATE NOT NULL,
    lifecycle             VARCHAR,
    opening_balance       NUMERIC(18,2),
    expected_balance      NUMERIC(18,2),
    counted_amount        NUMERIC(18,2),
    difference            NUMERIC(18,2),
    counted_by            VARCHAR,
    approved_by           VARCHAR,
    approval_reason       VARCHAR,
    closed_by             VARCHAR,
    closed_at             TIMESTAMP,
    difference_journal_id VARCHAR,
    created_at            TIMESTAMP,
    updated_at            TIMESTAMP,
    PRIMARY KEY (cash_journal_id, day)
);

CREATE TABLE IF NOT EXISTS pay_cash_entry (
    cash_journal_id   VARCHAR NOT NULL,
    day               DATE NOT NULL,
    seq               INTEGER NOT NULL,
    kind              VARCHAR,
    amount            NUMERIC(18,2),
    currency          VARCHAR,
    bp_id             BIGINT,
    payment_id        VARCHAR,
    account_id        VARCHAR,
    tax_code          VARCHAR,
    description       VARCHAR,
    receipt_image     VARCHAR,
    vat_amount        NUMERIC(18,2),
    vat_reclaimed     VARCHAR,
    journal_id        VARCHAR,
    statement_line_id VARCHAR,
    recorded_by       VARCHAR,
    recorded_at       TIMESTAMP,
    created_at        TIMESTAMP,
    updated_at        TIMESTAMP,
    PRIMARY KEY (cash_journal_id, day, seq)
);

CREATE TABLE IF NOT EXISTS pay_cash_count (
    cash_journal_id VARCHAR NOT NULL,
    day             DATE NOT NULL,
    seq             INTEGER NOT NULL,
    counted_amount  NUMERIC(18,2),
    denominations   VARCHAR,
    counted_by      VARCHAR,
    counted_by_ids  VARCHAR,
    counted_at      TIMESTAMP,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (cash_journal_id, day, seq)
);

CREATE TABLE IF NOT EXISTS pay_deposit_batch (
    batch_id          VARCHAR NOT NULL,
    bank_account_id   VARCHAR,
    currency          VARCHAR,
    slip_no           VARCHAR,
    lifecycle         VARCHAR,
    total             NUMERIC(18,2),
    cheque_count      INTEGER,
    deposited_on      DATE,
    statement_line_id VARCHAR,
    final_batch_id    VARCHAR,
    opened_by         VARCHAR,
    kind              VARCHAR,
    batch_ref         VARCHAR,
    source_module     VARCHAR,
    clearing_purpose  VARCHAR,
    expected_on       DATE,
    company_code      VARCHAR,
    difference        NUMERIC(18,2),
    accepted_by       VARCHAR,
    accepted_sub      VARCHAR,
    created_at        TIMESTAMP,
    updated_at        TIMESTAMP,
    PRIMARY KEY (batch_id)
);

CREATE TABLE IF NOT EXISTS pay_card_settlement (
    settlement_ref    VARCHAR NOT NULL,
    provider          VARCHAR,
    company_code      VARCHAR,
    currency          VARCHAR,
    gross             NUMERIC(18,2),
    business_date     DATE,
    transaction_count INTEGER,
    source_module     VARCHAR,
    lifecycle         VARCHAR,
    bank_account_id   VARCHAR,
    statement_line_id VARCHAR,
    fees              NUMERIC(18,2),
    fee_pct           NUMERIC(19,4),
    matched_by        VARCHAR,
    matched_sub       VARCHAR,
    accepted_by       VARCHAR,
    accepted_sub      VARCHAR,
    accept_reason     VARCHAR,
    claim             VARCHAR,
    created_at        TIMESTAMP,
    updated_at        TIMESTAMP,
    PRIMARY KEY (settlement_ref)
);

CREATE TABLE IF NOT EXISTS pay_payout (
    payout_ref        VARCHAR NOT NULL,
    payout_id         VARCHAR,
    payee_bp_id       BIGINT,
    person_id         VARCHAR,
    company_code      VARCHAR,
    currency          VARCHAR,
    amount            NUMERIC(18,2),
    due_on            DATE,
    reference         VARCHAR,
    source_module     VARCHAR,
    source_document   VARCHAR,
    clearing_purpose  VARCHAR,
    lifecycle         VARCHAR,
    bank_account_id   VARCHAR,
    requested_by      VARCHAR,
    approved_by       VARCHAR,
    approved_sub      VARCHAR,
    approved_on       DATE,
    exported_by       VARCHAR,
    exported_sub      VARCHAR,
    exported_on       DATE,
    export_key        VARCHAR,
    paid_on           DATE,
    bank_ref          VARCHAR,
    statement_line_id VARCHAR,
    journal_id        VARCHAR,
    returned_on       DATE,
    cancel_reason     VARCHAR,
    cancelled_by      VARCHAR,
    told_source_at    TIMESTAMP,
    created_at        TIMESTAMP,
    updated_at        TIMESTAMP,
    PRIMARY KEY (payout_ref)
);

CREATE TABLE IF NOT EXISTS pay_forecast_snapshot (
    snapshot_id VARCHAR NOT NULL,
    saved_on    DATE,
    saved_by    VARCHAR,
    body        VARCHAR,
    created_at  TIMESTAMP,
    updated_at  TIMESTAMP,
    PRIMARY KEY (snapshot_id)
);

-- v4 slice C (PAY-33, PAY-35): the FX difference posted per allocation, open-banking feed consents
CREATE TABLE IF NOT EXISTS pay_fx_posting (
    payment_id      VARCHAR NOT NULL,
    invoice_id      VARCHAR NOT NULL,
    seq             INTEGER NOT NULL,
    event           VARCHAR,
    direction       VARCHAR,
    source_document VARCHAR,
    journal_id      VARCHAR,
    amount          NUMERIC(18,2),
    currency        VARCHAR,
    receipt_rate    NUMERIC(19,4),
    invoice_rate    NUMERIC(19,4),
    posted_on       DATE,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (payment_id, invoice_id, seq)
);

CREATE TABLE IF NOT EXISTS pay_feed_consent (
    bank_account_id VARCHAR NOT NULL,
    granted_on      DATE NOT NULL,
    provider        VARCHAR,
    expires_on      DATE,
    recorded_by     VARCHAR,
    created_at      TIMESTAMP,
    updated_at      TIMESTAMP,
    PRIMARY KEY (bank_account_id, granted_on)
);