Skip to content

Release/1.9.1 - #219

Closed
fivetran-catfritz wants to merge 2 commits into
mainfrom
release/1.9.1
Closed

Release/1.9.1#219
fivetran-catfritz wants to merge 2 commits into
mainfrom
release/1.9.1

Conversation

@fivetran-catfritz

Copy link
Copy Markdown
Contributor

PR Overview

Package version introduced in this PR:

This PR addresses the following Issue/Feature(s):

Summary of changes:

Submission Checklist

  • Alignment meeting with the reviewer (if needed)
    • Timeline and validation requirements discussed
  • Provide validation details:
    • Validation Steps: Check for unintentional effects (e.g., add/run consistency & integrity tests)
    • Testing Instructions: Confirm the change addresses the issue(s)
    • Focus Areas: Complex logic or queries that need extra attention
  • Merge any relevant open PRs into this PR

Changelog

  • Draft changelog for PR
  • Final changelog for release review

bernhardF1984 and others added 2 commits August 5, 2026 17:20
* Bug fix - multiple accounts payable

Bug: payable_account_id is dropped in stg_quickbooks__bill_payment, causing data fanout in int_quickbooks__bill_payment_double_entry when more than one account shares account_type = 'Accounts Payable'
Package
fivetran/dbt_quickbooks (also present in the deprecated fivetran/dbt_quickbooks_source)
Summary
int_quickbooks__bill_payment_double_entry.sql posts the debit side of every Bill Payment to every account whose account_type = 'Accounts Payable', instead of to the one specific AP account each payment actually clears. This silently multiplies real accounts-payable activity onto any other account in the chart of accounts that happens to share that account_type — which QuickBooks allows, even though it isn't the intended one-AP-account-per-currency design the package assumes.

The root cause is that the source bill_payment object does carry a payable_account_id field (confirmed present in the raw Fivetran-synced bill_payment table), but stg_quickbooks__bill_payment.sql never selects it through to the staging layer. Because that field isn't available downstream, int_quickbooks__bill_payment_double_entry.sql has no way to join precisely, and falls back to matching by account_type + currency_id alone.

This is inconsistent with int_quickbooks__bill_double_entry.sql, which handles the equivalent case correctly by using bills.payable_account_id directly for its credit-side entry — that model is not affected by this bug.
Where the bug is
models/staging/stg_quickbooks__bill_payment.sql — final select omits payable_account_id even though it exists on the source table:

final as (
    select 
        cast(id as {{ dbt.type_string() }}) as bill_payment_id,
        cast(check_bank_account_id as {{ dbt.type_string() }}) as check_bank_account_id,
        check_print_status,
        cast(credit_card_account_id as {{ dbt.type_string() }}) as credit_card_account_id,
        exchange_rate,
        currency_id,
        cast(department_id as {{ dbt.type_string() }}) as department_id,
        pay_type,
        total_amount,
        cast( {{ dbt.date_trunc('day', 'transaction_date') }} as date) as transaction_date,
        cast(vendor_id as {{ dbt.type_string() }}) as vendor_id,
        created_at,
        updated_at,
        _fivetran_deleted,
        source_relation
    from fields
)

models/double_entry_transactions/int_quickbooks__bill_payment_double_entry.sql — because payable_account_id isn't available, the join falls back to matching every account of the configured account_type:

ap_accounts as (
    select
        account_id,
        currency_id,
        source_relation
    from accounts
    where account_type = '{{ var('quickbooks__accounts_payable_reference', 'Accounts Payable') }}'
        and is_active
        and not is_sub_account
),

bill_payment_join as (
    select
        ...
        coalesce(bill_payments.credit_card_account_id, bill_payments.check_bank_account_id) as payment_account_id,
        ap_accounts.account_id,
        ...
    from bill_payments
    left join ap_accounts
        on ap_accounts.currency_id = bill_payments.currency_id
        and ap_accounts.source_relation = bill_payments.source_relation
),

Since the join only matches on currency_id + source_relation, every Bill Payment fans out into one debit row per matching AP-type account, not one debit row for the specific account it actually pays down.

The DECISIONLOG does document that a single AP account per currency is a requirement and that multiple AP-typed accounts cause fanout, but since payable_account_id is already present on the source object, this looks like an unintentional oversight rather than an inherent limitation — the fix is available in the data, it's just not being used.
Reproduction
In a company file with 4 accounts sharing account_type = 'Accounts Payable' (one real "Accounts Payable" control account, plus three other liability-type accounts that were misconfigured with that same account_type in QuickBooks), querying quickbooks__general_ledger shows:

account_id
account_name
debit txn count
debit total
131
Accounts Payable (real)
2,769
$19,734,953.91
211
Loan Payable
2,758
$19,726,244.63
286
Loan Payable-Equipment
2,758
$19,726,244.63
178
Payroll Taxes Pay
2,758
$19,726,244.63


Three unrelated accounts show a nearly identical transaction count and dollar total to the real AP account — because they're all receiving a copy of the same underlying Bill Payment activity. This produced multi-million-dollar phantom balances on quickbooks__balance_sheet for accounts that should be at or near $0.
Impact
Any customer with more than one account carrying account_type = 'Accounts Payable' (which QuickBooks Online permits, even if not best practice) will see their non-AP account(s) silently inflated by the full company-wide AP payment volume, with no error or warning — the totals are close enough to the real AP account's totals that it can look plausible rather than obviously broken.
Suggested fix
Add payable_account_id to the final select in stg_quickbooks__bill_payment.sql:

cast(payable_account_id as {{ dbt.type_string() }}) as payable_account_id,

In int_quickbooks__bill_payment_double_entry.sql, join bill_payment_join to ap_accounts on the specific account instead of (or in addition to) account_type:

left join ap_accounts
    on ap_accounts.account_id = bill_payments.payable_account_id
    and ap_accounts.source_relation = bill_payments.source_relation

This mirrors how int_quickbooks__bill_double_entry.sql already handles the Bill side correctly via bills.payable_account_id.
Workaround
Until this is fixed upstream, we're overriding both models locally (defining models of the same name in our own dbt project, which take precedence over the installed package version) with the change above. We're also correcting the account_type of the misclassified accounts directly in QuickBooks, since that's the proper long-term fix regardless of this package behavior — but the package should not silently fan out data even when a customer's chart of accounts is misconfigured this way.

* bug fix - multiple accounts payable

Bug: payable_account_id is dropped in stg_quickbooks__bill_payment, causing data fanout in int_quickbooks__bill_payment_double_entry when more than one account shares account_type = 'Accounts Payable'
Package
fivetran/dbt_quickbooks (also present in the deprecated fivetran/dbt_quickbooks_source)
Summary
int_quickbooks__bill_payment_double_entry.sql posts the debit side of every Bill Payment to every account whose account_type = 'Accounts Payable', instead of to the one specific AP account each payment actually clears. This silently multiplies real accounts-payable activity onto any other account in the chart of accounts that happens to share that account_type — which QuickBooks allows, even though it isn't the intended one-AP-account-per-currency design the package assumes.

The root cause is that the source bill_payment object does carry a payable_account_id field (confirmed present in the raw Fivetran-synced bill_payment table), but stg_quickbooks__bill_payment.sql never selects it through to the staging layer. Because that field isn't available downstream, int_quickbooks__bill_payment_double_entry.sql has no way to join precisely, and falls back to matching by account_type + currency_id alone.

This is inconsistent with int_quickbooks__bill_double_entry.sql, which handles the equivalent case correctly by using bills.payable_account_id directly for its credit-side entry — that model is not affected by this bug.
Where the bug is
models/staging/stg_quickbooks__bill_payment.sql — final select omits payable_account_id even though it exists on the source table:

final as (
    select 
        cast(id as {{ dbt.type_string() }}) as bill_payment_id,
        cast(check_bank_account_id as {{ dbt.type_string() }}) as check_bank_account_id,
        check_print_status,
        cast(credit_card_account_id as {{ dbt.type_string() }}) as credit_card_account_id,
        exchange_rate,
        currency_id,
        cast(department_id as {{ dbt.type_string() }}) as department_id,
        pay_type,
        total_amount,
        cast( {{ dbt.date_trunc('day', 'transaction_date') }} as date) as transaction_date,
        cast(vendor_id as {{ dbt.type_string() }}) as vendor_id,
        created_at,
        updated_at,
        _fivetran_deleted,
        source_relation
    from fields
)

models/double_entry_transactions/int_quickbooks__bill_payment_double_entry.sql — because payable_account_id isn't available, the join falls back to matching every account of the configured account_type:

ap_accounts as (
    select
        account_id,
        currency_id,
        source_relation
    from accounts
    where account_type = '{{ var('quickbooks__accounts_payable_reference', 'Accounts Payable') }}'
        and is_active
        and not is_sub_account
),

bill_payment_join as (
    select
        ...
        coalesce(bill_payments.credit_card_account_id, bill_payments.check_bank_account_id) as payment_account_id,
        ap_accounts.account_id,
        ...
    from bill_payments
    left join ap_accounts
        on ap_accounts.currency_id = bill_payments.currency_id
        and ap_accounts.source_relation = bill_payments.source_relation
),

Since the join only matches on currency_id + source_relation, every Bill Payment fans out into one debit row per matching AP-type account, not one debit row for the specific account it actually pays down.

The DECISIONLOG does document that a single AP account per currency is a requirement and that multiple AP-typed accounts cause fanout, but since payable_account_id is already present on the source object, this looks like an unintentional oversight rather than an inherent limitation — the fix is available in the data, it's just not being used.
Reproduction
In a company file with 4 accounts sharing account_type = 'Accounts Payable' (one real "Accounts Payable" control account, plus three other liability-type accounts that were misconfigured with that same account_type in QuickBooks), querying quickbooks__general_ledger shows:

account_id
account_name
debit txn count
debit total
131
Accounts Payable (real)
2,769
$19,734,953.91
211
Loan Payable
2,758
$19,726,244.63
286
Loan Payable-Equipment
2,758
$19,726,244.63
178
Payroll Taxes Pay
2,758
$19,726,244.63


Three unrelated accounts show a nearly identical transaction count and dollar total to the real AP account — because they're all receiving a copy of the same underlying Bill Payment activity. This produced multi-million-dollar phantom balances on quickbooks__balance_sheet for accounts that should be at or near $0.
Impact
Any customer with more than one account carrying account_type = 'Accounts Payable' (which QuickBooks Online permits, even if not best practice) will see their non-AP account(s) silently inflated by the full company-wide AP payment volume, with no error or warning — the totals are close enough to the real AP account's totals that it can look plausible rather than obviously broken.
Suggested fix
Add payable_account_id to the final select in stg_quickbooks__bill_payment.sql:

cast(payable_account_id as {{ dbt.type_string() }}) as payable_account_id,

In int_quickbooks__bill_payment_double_entry.sql, join bill_payment_join to ap_accounts on the specific account instead of (or in addition to) account_type:

left join ap_accounts
    on ap_accounts.account_id = bill_payments.payable_account_id
    and ap_accounts.source_relation = bill_payments.source_relation

This mirrors how int_quickbooks__bill_double_entry.sql already handles the Bill side correctly via bills.payable_account_id.
Workaround
Until this is fixed upstream, we're overriding both models locally (defining models of the same name in our own dbt project, which take precedence over the installed package version) with the change above. We're also correcting the account_type of the misclassified accounts directly in QuickBooks, since that's the proper long-term fix regardless of this package behavior — but the package should not silently fan out data even when a customer's chart of accounts is misconfigured this way.

* Fix join condition for ap_accounts in SQL query

bug in case of multiple accounts payable
* fix/je-ar-lookup

* fix cast
@fivetran-catfritz
fivetran-catfritz deleted the release/1.9.1 branch August 5, 2026 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants