Skip to content

feat(charges): support custom currency credits-only charges#4769

Merged
gergely-kurucz-konghq merged 2 commits into
mainfrom
feat/credits-only
Jul 21, 2026
Merged

feat(charges): support custom currency credits-only charges#4769
gergely-kurucz-konghq merged 2 commits into
mainfrom
feat/credits-only

Conversation

@turip

@turip turip commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary

  • allow promotional credit purchases to use custom currencies
  • allow flat-fee and usage-based credits_only charges to use custom currencies
  • remove currency from detailed-line domain objects and persistence writes
  • deprecate the legacy detailed-line currency columns and make them nullable
  • add integration coverage using live charge adapters with mocked ledger and lineage boundaries

Why

Custom currencies are supported by charges after #4755, but create-time validation still rejected the promotional and credits-only flows. These flows should be accepted by the charge lifecycle while the ledger integration remains responsible for rejecting unsupported custom-currency operations.

Detailed-line currency duplicated the parent charge or invoice currency and its three-character database type prevented valid custom currencies from being persisted. Detailed lines now derive currency context from their parent instead.

Testing

  • go test -tags=dynamic -count=1 ./openmeter/billing/charges/service
  • go test -count=1 ./tools/migrate
  • go test -tags=dynamic -run '^$' ./...
  • focused billing adapter, detailed-line, rating, and migration validation suites

Stack

Depends on #4755.

Summary by CodeRabbit

  • New Features
    • Promotional credit purchases can now use custom currencies.
    • Credit-only flat-fee and usage-based charges now support custom currencies.
  • Bug Fixes
    • Invoice detailed lines now consistently use the parent invoice line’s currency when shown via the API.
    • Removed currency mismatch validation during billing adjustments/rating subtraction.
  • Chores / Maintenance
    • Detailed-line currency is now treated as optional (database constraint updated), with related validation and equality logic adjusted accordingly.

Greptile Summary

This PR adds custom-currency support to selected credit charge flows. The main changes are:

  • Allow custom currencies for promotional credit purchases.
  • Allow custom currencies for credits-only flat-fee and usage-based charges.
  • Derive detailed-line currency from the parent charge or invoice line.
  • Make legacy detailed-line currency columns nullable.
  • Add lifecycle, persistence, rating, and migration coverage.

Confidence Score: 5/5

This looks safe to merge.

  • The updated guards preserve rejection for unsupported settlement modes.
  • Detailed-line currency is consistently derived from its parent.
  • No separate blocking issue was found in the changed paths.

Important Files Changed

Filename Overview
openmeter/billing/charges/creditpurchase/service/create.go Allows custom currencies for promotional credit purchases while retaining the guard for other settlement types.
openmeter/billing/charges/flatfee/service/create.go Allows custom currencies for credits-only flat-fee charges.
openmeter/billing/charges/usagebased/service/create.go Allows custom currencies for credits-only usage-based charges.
openmeter/billing/adapter/stdinvoicelines.go Persists detailed-line currency from the parent invoice line.
openmeter/billing/httpdriver/invoiceline.go Maps detailed-line API currency from the parent standard invoice line.
openmeter/billing/charges/usagebased/service/rating/subtract/subtract.go Removes child-level currency comparison after currency ownership moves to the parent.
tools/migrate/migrations/20260721140844_deprecate_detailed_line_currency.up.sql Makes the deprecated detailed-line currency columns nullable.

Reviews (3): Last reviewed commit: "style: satisfy linter" | Re-trigger Greptile

Context used:

  • Context used - CLAUDE.md (source)
  • Context used - AGENTS.md (source)

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Detailed-line currency is deprecated in models, mappings, validation, and rating. Parent invoice lines now supply currency to output and persistence paths. Promotional and credit-only charges accept custom currencies, with expanded end-to-end tests.

Changes

Detailed-line currency deprecation

Layer / File(s) Summary
Detailed-line contract and persistence
openmeter/billing/models/stddetailedline/*, tools/migrate/migrations/*
Removes currency from the standard detailed-line model and builder contract, relaxes schema nullability, and updates database migrations.
Parent currency mapping and invoice output
openmeter/billing/adapter/*, openmeter/billing/httpdriver/invoiceline.go, openmeter/billing/service/invoicecalc/details.go, openmeter/billing/stdinvoiceline.go
Stops deriving currency from detailed lines and passes parent-line currency through invoice persistence and API mapping.
Usage-based conversion and rating
openmeter/billing/charges/usagebased/*, openmeter/billing/charges/usagebased/service/rating/*
Removes currency from usage-based detailed-line construction and deletes currency-consistency validation during subtraction.
Credit-only custom-currency charge flows
openmeter/billing/charges/{creditpurchase,flatfee,usagebased}/..., openmeter/billing/charges/service/*_test.go
Allows custom currencies for promotional or credit-only settlements and adds coverage for persisted flat-fee, usage-based, and credit-purchase flows.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: release-note/feature

Suggested reviewers: chrisgacsal, tothandras

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: custom-currency support for credits-only charges.
✨ 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/credits-only

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.

Base automatically changed from chore/add-custom-currency-support to main July 21, 2026 14:36
Comment thread openmeter/billing/charges/creditpurchase/service/create.go
Comment thread openmeter/billing/charges/flatfee/service/create.go
Comment thread openmeter/billing/charges/usagebased/service/create.go
@turip
turip marked this pull request as ready for review July 21, 2026 15:07
@turip
turip requested a review from a team as a code owner July 21, 2026 15:07
@turip
turip force-pushed the feat/credits-only branch from 4abeb7f to 1f895c6 Compare July 21, 2026 15:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@tools/migrate/migrations/20260721140844_deprecate_detailed_line_currency.down.sql`:
- Around line 1-6: Make the down migration rollback-safe by handling existing
NULL currency values before restoring NOT NULL on the detailed-line tables.
Backfill each table’s NULL currency from its corresponding parent line or
charge, or add a clear preflight that aborts with recovery guidance, then
regenerate the migration using Atlas.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9f619195-ebd4-4769-99c9-98afbda2888d

📥 Commits

Reviewing files that changed from the base of the PR and between ced75b6 and 1f895c6.

⛔ Files ignored due to path filters (20)
  • openmeter/ent/db/billingstandardinvoicedetailedline.go is excluded by !**/ent/db/**
  • openmeter/ent/db/billingstandardinvoicedetailedline/billingstandardinvoicedetailedline.go is excluded by !**/ent/db/**
  • openmeter/ent/db/billingstandardinvoicedetailedline/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/billingstandardinvoicedetailedline_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/billingstandardinvoicedetailedline_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeflatfeerundetailedline.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeflatfeerundetailedline/chargeflatfeerundetailedline.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeflatfeerundetailedline/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeflatfeerundetailedline_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeflatfeerundetailedline_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeusagebasedrundetailedline.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeusagebasedrundetailedline/chargeusagebasedrundetailedline.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeusagebasedrundetailedline/where.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeusagebasedrundetailedline_create.go is excluded by !**/ent/db/**
  • openmeter/ent/db/chargeusagebasedrundetailedline_update.go is excluded by !**/ent/db/**
  • openmeter/ent/db/entmixinaccessor.go is excluded by !**/ent/db/**
  • openmeter/ent/db/migrate/schema.go is excluded by !**/ent/db/**
  • openmeter/ent/db/mutation.go is excluded by !**/ent/db/**
  • openmeter/ent/db/runtime.go is excluded by !**/ent/db/**
  • tools/migrate/migrations/atlas.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (32)
  • openmeter/billing/adapter/stdinvoicelinemapper.go
  • openmeter/billing/adapter/stdinvoicelines.go
  • openmeter/billing/charges/creditpurchase/service/create.go
  • openmeter/billing/charges/flatfee/adapter/detailedline_test.go
  • openmeter/billing/charges/flatfee/service/create.go
  • openmeter/billing/charges/service/base_test.go
  • openmeter/billing/charges/service/creditpurchase_test.go
  • openmeter/billing/charges/service/handlers_test.go
  • openmeter/billing/charges/service/invoicable_test.go
  • openmeter/billing/charges/usagebased/adapter/detailedline_test.go
  • openmeter/billing/charges/usagebased/detailedline.go
  • openmeter/billing/charges/usagebased/service/create.go
  • openmeter/billing/charges/usagebased/service/linemapper_test.go
  • openmeter/billing/charges/usagebased/service/rating/delta/engine.go
  • openmeter/billing/charges/usagebased/service/rating/delta/engine_test.go
  • openmeter/billing/charges/usagebased/service/rating/periodpreserving/engine.go
  • openmeter/billing/charges/usagebased/service/rating/service_test.go
  • openmeter/billing/charges/usagebased/service/rating/subtract/subtract.go
  • openmeter/billing/charges/usagebased/service/rating/subtract/subtract_test.go
  • openmeter/billing/httpdriver/invoiceline.go
  • openmeter/billing/invoicedetailedline_test.go
  • openmeter/billing/models/stddetailedline/create.go
  • openmeter/billing/models/stddetailedline/derived.gen.go
  • openmeter/billing/models/stddetailedline/mapping.go
  • openmeter/billing/models/stddetailedline/mixin.go
  • openmeter/billing/models/stddetailedline/model.go
  • openmeter/billing/service/invoicecalc/details.go
  • openmeter/billing/stdinvoiceline.go
  • openmeter/billing/stdinvoiceline_test.go
  • test/billing/adapter_test.go
  • tools/migrate/migrations/20260721140844_deprecate_detailed_line_currency.down.sql
  • tools/migrate/migrations/20260721140844_deprecate_detailed_line_currency.up.sql
💤 Files with no reviewable changes (20)
  • openmeter/billing/models/stddetailedline/derived.gen.go
  • openmeter/billing/stdinvoiceline.go
  • openmeter/billing/models/stddetailedline/mapping.go
  • openmeter/billing/charges/usagebased/service/rating/delta/engine.go
  • openmeter/billing/invoicedetailedline_test.go
  • openmeter/billing/models/stddetailedline/create.go
  • openmeter/billing/charges/usagebased/adapter/detailedline_test.go
  • openmeter/billing/charges/usagebased/service/linemapper_test.go
  • openmeter/billing/charges/usagebased/service/rating/subtract/subtract.go
  • openmeter/billing/stdinvoiceline_test.go
  • openmeter/billing/charges/usagebased/service/rating/delta/engine_test.go
  • openmeter/billing/charges/flatfee/adapter/detailedline_test.go
  • openmeter/billing/adapter/stdinvoicelinemapper.go
  • test/billing/adapter_test.go
  • openmeter/billing/models/stddetailedline/model.go
  • openmeter/billing/charges/usagebased/service/rating/periodpreserving/engine.go
  • openmeter/billing/charges/usagebased/service/rating/service_test.go
  • openmeter/billing/service/invoicecalc/details.go
  • openmeter/billing/charges/usagebased/service/rating/subtract/subtract_test.go
  • openmeter/billing/charges/usagebased/detailedline.go

@gergely-kurucz-konghq
gergely-kurucz-konghq merged commit b368460 into main Jul 21, 2026
27 checks passed
@gergely-kurucz-konghq
gergely-kurucz-konghq deleted the feat/credits-only branch July 21, 2026 16:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/billing kind/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants