Skip to content

feat(advisor-branding P1): wire trip-order invoices to resolveBrand (letterhead brand, pinned TICO footer)#1476

Merged
Systemsaholic merged 2 commits into
mainfrom
feature/advisor-branding-p1-invoices
Jul 5, 2026
Merged

feat(advisor-branding P1): wire trip-order invoices to resolveBrand (letterhead brand, pinned TICO footer)#1476
Systemsaholic merged 2 commits into
mainfrom
feature/advisor-branding-p1-invoices

Conversation

@Systemsaholic

Copy link
Copy Markdown
Owner

Advisor Self-Branding P1 — invoices. Codex gpt-5.5 xhigh: APPROVE on 8b84281 (r1 BLOCK → r2 APPROVE). Builds on P0 (#1475, merged).

The invoice letterhead now renders the acting advisor's brand (headline + logo); the footer / TICO §38 fine-print ALWAYS renders the agency registrant (Phoenix + TICO#), non-overridable, regardless of tier. Ships LIVE but is effectively inert until an advisor has an active brand row — default tier='none' → agency headline = today's output (proven byte-identical by test).

  • Wiring: getBusinessConfiguration(agencyId, advisorId?)resolveBrand bakes brand_headline/logo/color/tier + advisor_user_id into BusinessConfiguration (frozen into the snapshot at finalize; legacy snapshots fall back to the agency). Registrant fields left untouched. Both context builders expose a brand key (letterhead) alongside the unchanged agency key (registrant). Live PDF + email + group-trip-order brand by the trip/booking-trip owner; manifest/rooming/checklist stay agency-only.
  • Per-advisor template cascade (dormant → activated): render paths + renderEmail pass the advisor as the resolvePublishedTemplate userId, so a per-advisor published override wins the 3-tier cascade. Tier 1 is agency-scoped (Codex r1 fix) — a cross-agency/stale advisor template can never override another agency's legal invoice (fails closed).
  • §38 validator: now asserts the registrant (agency) legal name is present regardless of brand headline. Existing checks unchanged.
  • Tests: unbranded → identical to today; personal → "X by Phoenix Voyages" + advisor logo, footer still Phoenix+TICO; DBA → bare DBA name + advisor logo, footer still Phoenix+TICO#50028032; §38 registrant present for all tiers; agency-scoped cascade. 68 unit specs + updated group integration specs green.

No migration. Money boundary untouched (no pricing/commission/totals/payment logic changed — Codex-confirmed). P2 (email header/from-name) consumes resolveBrand next.

Systemsaholic and others added 2 commits July 5, 2026 16:38
Advisor self-branding P1 — the invoice LETTERHEAD renders the acting advisor's
brand (headline + logo); the FOOTER / TICO §38 fine-print ALWAYS renders the
agency registrant (Phoenix + TICO#), non-overridable, regardless of tier. Ships
LIVE but inert until an advisor has an active brand row (default tier='none' →
agency headline = today's output). No migration; money boundary untouched.

Wiring
- getBusinessConfiguration(agencyId, advisorId?) resolves the brand via
  resolveBrand and bakes brand_headline/brand_logo_url/brand_color/brand_tier +
  advisor_user_id into BusinessConfiguration (frozen into the snapshot at
  finalize, so a reissue re-resolves the same brand + per-advisor template).
  Registrant fields (company_name/tico/address/phone/email) are LEFT UNTOUCHED.
- Both context builders expose a `brand` key (letterhead) alongside the
  unchanged `agency` key (registrant); templates read brand.headline/logoUrl in
  the letterhead only. embedLogoAsBase64 now embeds the brand logo.
- Live PDF + email + group-trip-order pass the advisor (trip.ownerId /
  bookingTrip.ownerId); manifest/rooming/checklist stay agency-only.

Per-advisor template cascade (dormant → activated)
- renderTripOrderPdf / renderTripOrderEmail / renderGroupPdf and
  DocumentTemplatesService.renderEmail now pass the acting advisor as the
  resolvePublishedTemplate userId, so a per-advisor published override wins the
  3-tier cascade (user → agency → system).

§38 validator
- validateTICOCompliance now asserts the registrant (agency) legal name is
  present REGARDLESS of any brand headline (a DBA/personal invoice must still
  carry the agency legal name + TICO#). Existing checks unchanged.

Tests (foreground)
- trip-order.branding.render.spec.ts: unbranded → identical to today; personal
  → "X by Phoenix Voyages" + advisor logo, footer still Phoenix+TICO; DBA →
  bare DBA name + advisor logo, footer still Phoenix+TICO#50028032; registrant
  pinned across all tiers; group template branded/unbranded.
- trip-order-tico-compliance.spec.ts: §38(6) registrant present for
  unbranded/personal/dba; flags a missing registrant name.
- resolve-published-template.cascade.spec.ts: 3-tier precedence with userId.
- Updated 6 group specs for the new brandingService constructor arg.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…odex r1)

Codex gpt-5.5 xhigh r1 BLOCK — the newly activated per-advisor template cascade
was not agency-scoped, so passing the advisor userId into a TICO §38 invoice
render could let a cross-agency or stale user template override another agency's
legal document.

resolvePublishedTemplate Tier 1 (user-level) matched slug + userId + status
only. Added eq(documentTemplates.agencyId, agencyId) so it FAILS CLOSED — a user
template row always carries its agencyId (forkTemplate sets both), so this
excludes any foreign-agency advisor template. Protects both the trip-order
render path and the renderEmail agentId path.

+2 regression specs: cross-agency user template is ignored (falls through to the
agency template); structural guard that Tier 1's WHERE references agency_id.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tailfire-client Ready Ready Preview, Comment Jul 5, 2026 8:48pm
tailfire-ota Ready Ready Preview, Comment Jul 5, 2026 8:48pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Systemsaholic, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 988a61fe-63e3-44cf-824d-c2a519e047d8

📥 Commits

Reviewing files that changed from the base of the PR and between be346a5 and 8b84281.

📒 Files selected for processing (16)
  • apps/api/src/document-templates/document-templates.service.ts
  • apps/api/src/document-templates/resolve-published-template.cascade.spec.ts
  • apps/api/src/document-templates/system-templates/group-trip-order.template.ts
  • apps/api/src/document-templates/system-templates/trip-order.branding.render.spec.ts
  • apps/api/src/document-templates/system-templates/trip-order.template.ts
  • apps/api/src/financials/__tests__/group-booking-finalize-invoiced.spec.ts
  • apps/api/src/financials/__tests__/group-booking-trip-order.integration.spec.ts
  • apps/api/src/financials/__tests__/group-checklist.integration.spec.ts
  • apps/api/src/financials/__tests__/group-manifest.integration.spec.ts
  • apps/api/src/financials/__tests__/group-rooming-list.integration.spec.ts
  • apps/api/src/financials/__tests__/trip-order-tico-compliance.spec.ts
  • apps/api/src/financials/financials.module.ts
  • apps/api/src/financials/pdf/types.ts
  • apps/api/src/financials/tico-compliance.ts
  • apps/api/src/financials/trip-order.service.ts
  • apps/api/src/trips/__tests__/group-dual-trip-orders.integration.spec.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/advisor-branding-p1-invoices

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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