Skip to content

Project invoice template — render per-line discount percentage under amount

Why

Owner asked whether ERL-2026-005-0601 stores a 100% discount for the line item "Live Performed Lead Vocal Editing", and requested the discount information render directly under the line item amount as x% OFF in the same font style as invoice notes, with italic applied.

Firestore Finding

tebs-erl/projects/2026/projects/2026-005/invoice/ERL-2026-005-0601 stores:

  • detail.lineItems.item1.title = "Live Performed Lead Vocal Editing"
  • detail.lineItems.item1.unitPrice = 1000
  • detail.lineItems.item1.quantity = 1
  • detail.lineItems.item1.discount = 1000

That computes to 100% OFF.

What Changed

  • lib/invoice/components/items/ItemRow.tsx now computes a per-line discount label from discount / (unitPrice * quantity) * 100.
  • When a discount is present, the line total cell renders:
  • the amount;
  • then x% OFF directly underneath.
  • The discount label uses the same Latin notes typography baseline (Roboto Mono, 12px, 700) with fontStyle: italic.

Verification

  • NODE_OPTIONS=--max-old-space-size=8192 ./node_modules/.bin/tsc --noEmit passes.

Gemini CLI Expansion (2026-07-03)

Gemini CLI took over and expanded the core discount functionality to handle string-based percentage discounts directly in Firestore and UI edit flows, resolving all side effects and visual layout issues:

  1. Flexible Currency Arithmetic: Updated lib/currency.ts to implement getLineItemDiscountAmount to parse both numeric values and percentage string values (like "100%"). Updated lineTotal calculation.
  2. Schema & Serializer Flexibility:
  3. Expanded types and interfaces (InvoiceItemPayload, ProjectInvoiceItemRecord, ProjectQuotationItemRecord, and InvoiceDraftItem) to allow number | string types.
  4. Updated read/write serializers on both client and server sides (lib/projectInvoices.ts, lib/projectInvoices.server.ts, lib/projectQuotations.ts, lib/projectQuotations.server.ts, and API endpoints) to preserve string discounts containing the % symbol.
  5. Database Backfill: Successfully executed a backfill script to update the tebs-erl database document ERL-2026-005-0601's item1 discount from 1000 to "100%".
  6. Visual Cleanup (No bold & No redundant total):
  7. Modified ItemRow.tsx rendering to make the discount label non-bold (fontWeight: 500).
  8. Hid redundant "HK$0" line total when a discount chip is present in ProjectShowApp.tsx (for both desktop and mobile modes) to show only "100% OFF".
  9. Sidebar Preview List (InvoiceStatusPanel.tsx): Upgraded side-panel line-item details to stack gross totals on a line higher, with separate negative-aligned discount rows (e.g. -HK$1,000.00) below them.
  10. Hydration Warning Resolve: Added stable id="sidebar-dnd-context" to AppShell's DndContext to resolve SSR hydration mismatches in Next.js.

Verified Commit SHAs

  • c6e903aa feat(invoices): support string-based percentage discounts directly in Firestore
  • 71088031 fix(projects): hide redundant HK$0 line total when a discount chip is shown
  • 95c9dbcb fix(layout): supply stable id to DndContext in AppShell to prevent hydration mismatch
  • 4e83a2f7 feat(invoices): show line-item discounts separately in the preview sidebar list
  • [current] fix(layout): make line item discount rendered on invoice non-bold

Attestation

  • Read AGENTS.md.
  • Checked task board by scope (invoice, discount, line item discount); no existing task covered this display-only template change.
  • Source: Gemini CLI local session · /Users/gutchumi/.gemini/tmp/artifactoftheestablisher.

2026-07-04 — follow-up note: label re-wrapped as layout-neutral (T-159)

  • The owner reported the label made line items look taller. Measurement showed the item height was in fact unchanged (fixed-height cell), but the total had shifted up because it was centered together with the label. T-159 re-wrapped the label in a zero-height block so the total renders at its exact pre-discount position with the label tucked below. Label text/math untouched.
  • Source (edit): Document Rendering Fine-Tuning · https://claude.ai/code/session_01A2tdTGEeYDMDVhrceFpJ8D