Skip to content

feat: expose unit_config on the v3 invoice line rate card#4730

Merged
rolosp merged 1 commit into
mainfrom
feat/unit-config-v3-invoice-surface
Jul 17, 2026
Merged

feat: expose unit_config on the v3 invoice line rate card#4730
rolosp merged 1 commit into
mainfrom
feat/unit-config-v3-invoice-surface

Conversation

@rolosp

@rolosp rolosp commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

Surfaces the OM-398 unit_config snapshot on the v3 invoice API's per-line
rate card (read-only). The config that was applied when a usage-based line was
billed — the conversion rule that turned raw metered units into billed units —
is now readable on BillingInvoiceLineRateCard. Pure exposure: no schema, no
migration, nil snapshot is omitted, so invoices without a unit_config are
byte-identical to today.

Why

unit_config was fully persisted on invoice lines (OM-398,
BillingInvoiceUsageBasedLineConfig.unit_config) and reached the billing domain
(StandardLine.GetUnitConfig), but stopped at the v3 invoice converter —
mapRateCard never read it and no v3 invoice type had a field to hold it, so
the applied conversion was invisible over the API (v1 or v3). This is the first
of the invoice-read exposure fast-follows the epic deferred behind the v3
invoice API track; billed amounts were already correct, this just makes the
applied config auditable to API consumers.

How

  • TypeSpec — add a read-only unit_config field to InvoiceLineRateCard
    (invoices/invoice.tsp), reusing the existing productcatalog UnitConfig
    model; regenerate OpenAPI + the Go/JS SDKs.
  • ConvertermapRateCard maps the snapshot via the existing
    plans.ToAPIBillingUnitConfig (reused, not hand-rolled); a nil snapshot is
    omitted, so the field is naturally identity when no config was applied.
  • SDK type split (consequence, not a choice) — marking the field
    @visibility(Lifecycle.Read) forks the SDK's update projection into a
    distinct UpdateInvoiceLineRateCard. This is correct: unit_config is a
    write-once billing-time snapshot and must not be settable via invoice update.
    The one e2e literal that built an update line is moved to the new type.
  • Tests — two converter unit tests: all five fields round-trip onto the API
    type, and a nil snapshot is omitted. No e2e: the v3 invoice API only serves
    standard invoices, but a pure-usage subscription line stays on a gathering
    invoice until its period closes in the past (v3 SubscriptionCreate can't
    start a subscription in the past), so an end-to-end fixture would need a
    v1 past-dated subscription — deferred as not worth the fragility since the
    mapping is unit-tested.

No schema/migration. Gated implicitly by the same unitConfig.enabled authoring
flag — an absent snapshot reads as omitted.

Summary by CodeRabbit

  • New Features
    • Invoice line rate cards now include an optional, read-only unit_config snapshot that shows how metered quantity is converted at billing time.
    • Added support for providing unit_config when creating or updating invoice line rate cards via the new input payload type.
  • Documentation / Schema Updates
    • Updated OpenAPI/Swagger schemas to expose the new unit_config field.
  • Tests
    • Added coverage to verify unit_config is mapped when present and omitted when absent, and updated e2e request helpers for the new rate-card update type.

Greptile Summary

This PR exposes the billing-time unit conversion snapshot on v3 invoice line rate cards. The main changes are:

  • Adds an optional, read-only unit_config field to the TypeSpec and OpenAPI models.
  • Maps persisted unit configuration snapshots into v3 invoice responses.
  • Regenerates the Go and JavaScript SDK types with separate read and update projections.
  • Adds converter coverage for populated and absent snapshots.

Confidence Score: 5/5

This looks safe to merge.

  • The response converter preserves the existing output when no snapshot is present.
  • The generated Go update model excludes the read-only field.
  • Tests cover both populated and absent unit configuration snapshots.
  • No blocking issue related to an earlier review finding remains in the updated code.

Important Files Changed

Filename Overview
api/spec/packages/aip/src/invoices/invoice.tsp Adds the optional read-only unit configuration snapshot to the invoice line rate card.
api/v3/handlers/billinginvoices/convert.go Maps a stored unit configuration snapshot into the v3 invoice response.
api/v3/handlers/billinginvoices/convert_test.go Covers complete snapshot mapping and omission when no snapshot exists.
api/v3/client/models_invoices.go Adds the response field and separates the update rate-card model.
api/spec/packages/aip-client-javascript/src/models/types.ts Regenerates JavaScript SDK model projections for the new field.
api/v3/openapi.yaml Publishes unit_config as an optional read-only API property.

Reviews (2): Last reviewed commit: "feat: expose unit_config on the v3 invoi..." | Re-trigger Greptile

Context used (3)

  • Context used - CLAUDE.md (source)
  • Context used - AGENTS.md (source)
  • Context used - api/spec/AGENTS.md (source)

@rolosp rolosp added the release-note/misc Miscellaneous changes label Jul 16, 2026
@rolosp
rolosp requested a review from a team as a code owner July 16, 2026 15:59
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 460a9665-3771-4947-a67e-5c49bd1b357d

📥 Commits

Reviewing files that changed from the base of the PR and between 4121b30 and d55d33f.

⛔ Files ignored due to path filters (1)
  • api/v3/openapi.yaml is excluded by !**/openapi.yaml
📒 Files selected for processing (9)
  • api/spec/packages/aip-client-javascript/src/index.ts
  • api/spec/packages/aip-client-javascript/src/models/schemas.ts
  • api/spec/packages/aip-client-javascript/src/models/types.ts
  • api/spec/packages/aip/src/invoices/invoice.tsp
  • api/v3/api.gen.go
  • api/v3/client/models_invoices.go
  • api/v3/handlers/billinginvoices/convert.go
  • api/v3/handlers/billinginvoices/convert_test.go
  • e2e/billinginvoices_v3_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • api/spec/packages/aip-client-javascript/src/index.ts
  • api/v3/handlers/billinginvoices/convert_test.go
  • api/v3/handlers/billinginvoices/convert.go
  • api/v3/client/models_invoices.go
  • api/spec/packages/aip-client-javascript/src/models/schemas.ts
  • api/spec/packages/aip-client-javascript/src/models/types.ts

📝 Walkthrough

Walkthrough

Invoice line rate-card contracts now expose optional unit configuration snapshots across the API specification, generated clients, and JavaScript SDK. Billing conversion populates the snapshot, tests cover both presence and absence, and update payloads use dedicated input types.

Changes

Invoice unit configuration propagation

Layer / File(s) Summary
Invoice rate-card API contracts
api/spec/packages/aip/..., api/spec/packages/aip-client-javascript/src/..., api/v3/api.gen.go, api/v3/openapi.yaml
Invoice rate-card models and schemas add optional read-only unit configuration snapshots, while generated API and JavaScript SDK exports reflect the new contract.
Update rate-card payload contracts
api/v3/client/models_invoices.go, e2e/billinginvoices_v3_test.go
Update invoice lines use the dedicated UpdateInvoiceLineRateCard request type in client models and end-to-end fixtures.
Billing conversion and validation
api/v3/handlers/billinginvoices/convert.go, api/v3/handlers/billinginvoices/convert_test.go
mapRateCard converts available unit configuration snapshots into API rate cards, with tests for present and absent configurations.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BillingStandardLine
  participant mapRateCard
  participant BillingInvoiceLineRateCard
  participant APIClient
  BillingStandardLine->>mapRateCard: provide unit configuration snapshot
  mapRateCard->>BillingInvoiceLineRateCard: populate UnitConfig
  BillingInvoiceLineRateCard->>APIClient: expose unit_config in invoice response
Loading

Possibly related PRs

Suggested labels: area/billing, kind/feature

Suggested reviewers: chrisgacsal, turip, tothandras

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: exposing unit_config on the v3 invoice line rate card.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/unit-config-v3-invoice-surface

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.

@rolosp
rolosp force-pushed the feat/unit-config-v3-invoice-surface branch from 4121b30 to d55d33f Compare July 16, 2026 16:04
@rolosp
rolosp merged commit 9369c6a into main Jul 17, 2026
30 checks passed
@rolosp
rolosp deleted the feat/unit-config-v3-invoice-surface branch July 17, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release-note/misc Miscellaneous changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants