Skip to content

QBO Bill Account Mapping Engine#110

Open
hhff wants to merge 26 commits into
mainfrom
worktree-qbo-bill-account-mapping-engine
Open

QBO Bill Account Mapping Engine#110
hhff wants to merge 26 commits into
mainfrom
worktree-qbo-bill-account-mapping-engine

Conversation

@hhff

@hhff hhff commented Jun 10, 2026

Copy link
Copy Markdown
Member

Summary

Replaces the hard-coded QBO account routing for every Stacks-managed bill (ContributorPayout, Trueup, ContributorAdjustment, ProfitShare, PayStub) with a database-backed mapping engine:

  • QboChartAccount — local mirror of each realm's chart of accounts (synced daily, on-demand via a new "Refresh Chart of Accounts" admin action, and lazily on first bill sync). The enterprise dashboard now reads balances from the mirror instead of a live QBO fetch per page load.
  • QboBillAccountMapping — one rules table: (enterprise, line_item_key, subject) → chart account, where subject is a ProjectTracker, Contributor, or null for the entity default, across ten line-item kinds (six payout buckets, trueup, adjustment, profit share, pay stub).
  • Qbo::BillAccountResolver — single resolution path: project tracker → contributor → entity default, raising Qbo::UnmappedLineItemError when unmapped (no silent fallbacks). All legacy routing (find_qbo_account! overrides, SPECIFIC_ACCT_NUM_BY_BUCKET, PROFIT_SHARE_LIABILITY_ACCT_NUM, Studio#qbo_subcontractors_categories, the internal-client Marketing conditional) is deleted.
  • Payout bills now split lines per (role bucket × project tracker) so project-level mappings apply per line; pay stubs resolve per project; negative per-tracker groups collapse to the trusted single-line shape.
  • Qbo::SeedBillAccountMappings + rake stacks:seed_qbo_bill_account_mappings — idempotent seeding that reproduces today's behavior exactly (entity defaults, studio routing snapshotted to contributor rows, internal-client trackers → Marketing), with per-enterprise error isolation.
  • Admin UI — mappings CRUD resource (menu: Money → QBO Account Mappings), a per-enterprise mappings panel with unmapped indicators, and override sidebars on ProjectTracker and Contributor pages.

Design doc: docs/superpowers/specs/2026-06-10-qbo-bill-account-mapping-engine-design.md (decision notes cover the accepted behavior deviations). Implementation plan: docs/superpowers/plans/2026-06-10-qbo-bill-account-mapping-engine.md.

Rollout

  1. Deploy.
  2. Run rake stacks:seed_qbo_bill_account_mappings immediately — until it runs, bill syncs fail per-record with Qbo::UnmappedLineItemError (isolated in the nightly loop, flashed in admin; nothing blocks, but it's noisy). Review the created/skipped output per enterprise.
  3. In admin, open each Enterprise → confirm the "QBO Bill Account Mappings" panel shows no unmapped tags (or deliberately leave kinds that enterprise never bills).
  4. Trigger one bill sync per host type (CP / Trueup / CA / ProfitShare / PayStub) on a safe record and verify line accounts in QBO match pre-deploy behavior.
  5. Watch logs for Qbo::UnmappedLineItemError and chart-sync deactivation warnings over the first daily run.

Data checks worth doing before/at deploy

  • Any project trackers with BOTH internal and external forecast clients? (They intentionally get no Marketing seed — lines fall back to contributor/entity resolution.)
  • Any cross-enterprise billing relying on the old any-enterprise is_internal?? (Seeded internality is scoped to the owning enterprise.)
  • Finance sign-off on the two accepted routing changes: tracker-level Marketing now beats studio snapshots unconditionally, and studio changes no longer move routing automatically (admins edit contributor rows).

Test Plan

  • Full suite green: 385 runs, 855 assertions, 0 failures (2 pre-existing skips)
  • Resolver precedence, isolation, and strict-error paths unit-tested
  • Payout line splitting (per-tracker, nil-tracker grouping, negative/out-of-sync/drift collapse) tested
  • PayStub per-project resolution incl. tracker overrides tested
  • Seeding parity (defaults, 2340/5710/6120 fallbacks, studio snapshot, internal trackers, mixed-client exclusion, idempotency, per-enterprise error isolation) tested
  • Manual admin QA post-deploy (panel, form pickers, refresh action)

🤖 Generated with Claude Code

hhff and others added 26 commits June 10, 2026 12:04
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tributor rows

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The schema dumper materializes the three composite FKs to qbo_invoices as
single-column add_foreign_key lines (lossy/incorrect); origin keeps them
as comments. Restore after the qbo_chart_accounts migration regenerated
the file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… rows

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ation

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ubject labels

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… precedence

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rror path

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…a the mapping engine

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…CP sync

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ouping

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ping form

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant