fix(qbo): pin TxnTaxCodeRef from the estimate's jurisdiction on milestone pushes - #432
Open
Clarion1631 wants to merge 3 commits into
Open
fix(qbo): pin TxnTaxCodeRef from the estimate's jurisdiction on milestone pushes#432Clarion1631 wants to merge 3 commits into
Clarion1631 wants to merge 3 commits into
Conversation
…tone pushes
QBO milestone invoices were sent with a pre-tax line + TxnTaxDetail.TotalTax but no
TxnTaxCodeRef, so QuickBooks applied the customer/company default tax code and
recomputed the tax at THAT code's rate. Berg ADU INV-00177-2 (Winlock, 8.0%) came
out at WA-Vancouver 8.9%: $15,125 against a $15,000 milestone, leaving a phantom
$125 balance after the customer's check.
- resolveQBTaxCodeId(): map Estimate.taxRateName ("Winlock") to the active QBO
TaxCode with the same name; null (and a warning) when unset/unmatched/lookup
fails, so billing never blocks on the lookup.
- createQBMilestoneInvoice(): optional taxCodeId -> TxnTaxDetail.TxnTaxCodeRef,
emitted only on taxed invoices; payload unchanged when no code resolves.
- pushMilestoneToQuickBooks / stageProgressBillingToQuickBooksCore: select the
estimate's taxRateName and pass the resolved code.
- tests/qbo-tax-code-pin.test.ts: name matching, inactive/no-match/error
fallbacks, quote escaping, and the three payload shapes.
Stacked on fix/qbo-milestone-ship-addr (#431) since both edit the same push sites.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nETMsFif1rbvPijc6BgQN
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nETMsFif1rbvPijc6BgQN
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nETMsFif1rbvPijc6BgQN
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
QBO milestone invoices carried
TxnTaxDetail.TotalTaxbut noTxnTaxCodeRef, so QuickBooks applied its default tax code and recomputed tax at that code's rate. Berg ADU INV-00177-2 (Winlock, 8.0%) was created at WA-Vancouver 8.9%: $15,125 on a $15,000 milestone, a phantom $125 balance after the customer paid by check. (Data already corrected in QBO on 2026-08-29.)What
resolveQBTaxCodeId(tokens, taxRateName):SELECT ... FROM TaxCode WHERE Name = '<Estimate.taxRateName>', active + case-insensitive match; returns null with a console warning when unset, unmatched, or the lookup errors (fail-soft, billing never blocks).createQBMilestoneInvoice: new optionaltaxCodeId→TxnTaxDetail.TxnTaxCodeRef; only on taxed invoices; payload byte-identical to before when no code resolves.pushMilestoneToQuickBooks,stageProgressBillingToQuickBooksCore) selectestimate.taxRateNameand pass the code.tests/qbo-tax-code-pin.test.ts(registered intest:unit): 7 cases covering matching, fallbacks, escaping, and the three payload shapes.Verification
npx tsx --test tests/qbo-tax-code-pin.test.ts: 7/7 passnpx tsc --noEmit: cleanNotes
fix/qbo-milestone-ship-addr) because both change the same push call sites; retarget tomainonce fix(qbo): send job-site ShipAddr on milestone invoices; fail on total drift #431 merges.taxRateName(today: "Winlock" ↔ 13, "Vancouver City" ↔ 5). Unmatched names keep today's behavior and log a warning.🤖 Generated with Claude Code
https://claude.ai/code/session_013nETMsFif1rbvPijc6BgQN