feat(customcurrencies): support resolving costbases#4772
Conversation
📝 WalkthroughWalkthroughAdds end-to-end cost-basis support for flat-fee and usage-based charges, including typed intents and states, currency lookup APIs, database persistence, lifecycle resolution, adapter mapping, service wiring, and comprehensive tests. ChangesCost-basis domain and currency resolution
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
|
@greptile-apps please review this PR. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
pkg/currencyx/currency.go (1)
197-199: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueConsider guarding
GetFiatCode()against a nil receiver.
Validate()on*FiatCurrencyexplicitly checks forf == nil, butGetFiatCode()dereferencesf.defdirectly. Every call site we can see validates first, so this isn't an active bug today, but it's an easy defensive win in case a future caller skips validation.🛡️ Optional defensive guard
func (f *FiatCurrency) GetFiatCode() FiatCode { + if f == nil || f.def == nil { + return "" + } return FiatCode(f.def.ISOCode) }🤖 Prompt for 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. In `@pkg/currencyx/currency.go` around lines 197 - 199, Update FiatCurrency.GetFiatCode to handle a nil receiver before dereferencing f.def, returning the appropriate zero or invalid FiatCode value for nil while preserving the existing ISOCode conversion for non-nil receivers.openmeter/ent/schema/charges.go (1)
330-335: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win
currency_cost_basis_idcould use.Immutable()like its sibling fields.Per
costbasis.Create/Set(model.go),currency_cost_basis_idis only ever written once, at creation time for pinned mode — it's never touched again.mode,fiat_currency,currency_id, andmanual_rateall get the same "set-once" treatment and are marked.Immutable(), but this field isn't. Locking it down would statically prevent a future update path from accidentally mutating the pinned reference.🔒 Proposed fix
field.String("currency_cost_basis_id"). Optional(). Nillable(). + Immutable(). SchemaType(map[string]string{ dialect.Postgres: "char(26)", }),🤖 Prompt for 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. In `@openmeter/ent/schema/charges.go` around lines 330 - 335, Update the currency_cost_basis_id field definition in the charges schema to include Immutable(), matching the set-once treatment of mode, fiat_currency, currency_id, and manual_rate while preserving its existing optional, nillable, and PostgreSQL type configuration.openmeter/billing/charges/usagebased/service/service.go (1)
6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueNo change needed for this import.
testingis used for the*testing.Tguard inSetEnableCustomCurrency, and this pattern already exists in the mirroredflatfeeservice, so changing it for maintainability would be lower priority.🤖 Prompt for 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. In `@openmeter/billing/charges/usagebased/service/service.go` at line 6, Leave the testing import unchanged; SetEnableCustomCurrency uses testing.T, and its existing pattern matches the mirrored flatfee service.
🤖 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 `@openmeter/billing/charges/flatfee/service/service.go`:
- Around line 86-93: Initialize the service’s custom-currency capability during
New using a production configuration or feature-setting input, instead of
relying on the testing-only setter. Update the service config and constructor
wiring around service and enableCustomCurrency so Create permits supported
custom-currency credit-then-invoice charges in production while preserving the
disabled behavior when the setting is not enabled.
In `@openmeter/billing/charges/service/usagebased_costbasis_test.go`:
- Around line 253-293: Add an immediate defer clock.UnFreeze() after the second
clock.FreezeTime(activationAt) call in the test setup, alongside the existing
freeze for servicePeriodFrom, so each freeze is paired with its own cleanup.
---
Nitpick comments:
In `@openmeter/billing/charges/usagebased/service/service.go`:
- Line 6: Leave the testing import unchanged; SetEnableCustomCurrency uses
testing.T, and its existing pattern matches the mirrored flatfee service.
In `@openmeter/ent/schema/charges.go`:
- Around line 330-335: Update the currency_cost_basis_id field definition in the
charges schema to include Immutable(), matching the set-once treatment of mode,
fiat_currency, currency_id, and manual_rate while preserving its existing
optional, nillable, and PostgreSQL type configuration.
In `@pkg/currencyx/currency.go`:
- Around line 197-199: Update FiatCurrency.GetFiatCode to handle a nil receiver
before dereferencing f.def, returning the appropriate zero or invalid FiatCode
value for nil while preserving the existing ISOCode conversion for non-nil
receivers.
🪄 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: 54e3cfdb-9414-43ca-8c40-6dc0fd0b41e1
⛔ Files ignored due to path filters (50)
openmeter/ent/db/chargecreditpurchase.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase/chargecreditpurchase.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis/chargecreditpurchasecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_delete.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_update.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee/chargeflatfee.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis/chargeflatfeecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_delete.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_update.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased/chargeusagebased.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis/chargeusagebasedcostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_delete.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_update.gois excluded by!**/ent/db/**openmeter/ent/db/client.gois excluded by!**/ent/db/**openmeter/ent/db/cursor.gois excluded by!**/ent/db/**openmeter/ent/db/ent.gois excluded by!**/ent/db/**openmeter/ent/db/entmixinaccessor.gois excluded by!**/ent/db/**openmeter/ent/db/expose.gois excluded by!**/ent/db/**openmeter/ent/db/hook/hook.gois excluded by!**/ent/db/**openmeter/ent/db/migrate/schema.gois excluded by!**/ent/db/**openmeter/ent/db/mutation.gois excluded by!**/ent/db/**openmeter/ent/db/paginate.gois excluded by!**/ent/db/**openmeter/ent/db/predicate/predicate.gois excluded by!**/ent/db/**openmeter/ent/db/runtime.gois excluded by!**/ent/db/**openmeter/ent/db/setorclear.gois excluded by!**/ent/db/**openmeter/ent/db/tx.gois excluded by!**/ent/db/**tools/migrate/migrations/atlas.sumis excluded by!**/*.sum,!**/*.sum
📒 Files selected for processing (56)
app/common/billing.goapp/common/charges.gocmd/billing-worker/wire_gen.gocmd/jobs/internal/wire_gen.gocmd/server/wire_gen.goopenmeter/billing/charges/flatfee/adapter.goopenmeter/billing/charges/flatfee/adapter/charge.goopenmeter/billing/charges/flatfee/adapter/costbasis.goopenmeter/billing/charges/flatfee/adapter/intentoverride.goopenmeter/billing/charges/flatfee/adapter/mapper.goopenmeter/billing/charges/flatfee/charge.goopenmeter/billing/charges/flatfee/charge_test.goopenmeter/billing/charges/flatfee/service/create.goopenmeter/billing/charges/flatfee/service/creditheninvoice.goopenmeter/billing/charges/flatfee/service/lineengine.goopenmeter/billing/charges/flatfee/service/service.goopenmeter/billing/charges/models/costbasis/costbasis.goopenmeter/billing/charges/models/costbasis/intent.goopenmeter/billing/charges/models/costbasis/intent_test.goopenmeter/billing/charges/models/costbasis/model.goopenmeter/billing/charges/models/costbasis/resolver.goopenmeter/billing/charges/models/costbasis/state.goopenmeter/billing/charges/service/base_test.goopenmeter/billing/charges/service/flatfee_costbasis_test.goopenmeter/billing/charges/service/invoicable_test.goopenmeter/billing/charges/service/usagebased_costbasis_test.goopenmeter/billing/charges/testutils/service.goopenmeter/billing/charges/usagebased/adapter.goopenmeter/billing/charges/usagebased/adapter/charge.goopenmeter/billing/charges/usagebased/adapter/costbasis.goopenmeter/billing/charges/usagebased/adapter/intentoverride.goopenmeter/billing/charges/usagebased/adapter/intentoverride_test.goopenmeter/billing/charges/usagebased/adapter/mapper.goopenmeter/billing/charges/usagebased/charge.goopenmeter/billing/charges/usagebased/charge_test.goopenmeter/billing/charges/usagebased/service.goopenmeter/billing/charges/usagebased/service/create.goopenmeter/billing/charges/usagebased/service/creditheninvoice.goopenmeter/billing/charges/usagebased/service/service.goopenmeter/billing/charges/usagebased/service/statemachine.goopenmeter/billing/charges/usagebased/service/triggers.goopenmeter/currencies/adapter/currencies.goopenmeter/currencies/adapter/currencies_test.goopenmeter/currencies/repository.goopenmeter/currencies/service.goopenmeter/currencies/service/service.goopenmeter/ent/schema/charges.goopenmeter/ent/schema/chargescreditpurchase.goopenmeter/ent/schema/chargesflatfee.goopenmeter/ent/schema/chargesusagebased.goopenmeter/ledger/customerbalance/testenv_test.goopenmeter/server/server_test.gopkg/currencyx/code.gopkg/currencyx/currency.gotools/migrate/migrations/20260722145858_add_charge_cost_basis.down.sqltools/migrate/migrations/20260722145858_add_charge_cost_basis.up.sql
💤 Files with no reviewable changes (1)
- openmeter/billing/charges/usagebased/adapter/intentoverride_test.go
|
Too many files changed for review. ( Bypass the limit by tagging |
|
Bot review follow-up on the non-actionable notes:
|
2b61068 to
b1bb8a7
Compare
There was a problem hiding this comment.
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 `@openmeter/billing/charges/models/costbasis/intent.go`:
- Around line 30-35: Update Mode.Validate to collect its invalid-mode validation
failure in an errs accumulator and return
models.NewNillableGenericValidationError(errors.Join(errs...)), matching the
validator contract used elsewhere in the file; preserve nil validation for valid
modes.
🪄 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 Plus
Run ID: d53e450b-8e17-4e85-bb81-7c0e9665ce34
⛔ Files ignored due to path filters (50)
openmeter/ent/db/chargecreditpurchase.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase/chargecreditpurchase.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchase_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis/chargecreditpurchasecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_delete.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargecreditpurchasecostbasis_update.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee/chargeflatfee.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfee_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis/chargeflatfeecostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_delete.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeflatfeecostbasis_update.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased/chargeusagebased.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebased_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis/chargeusagebasedcostbasis.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis/where.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_create.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_delete.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_query.gois excluded by!**/ent/db/**openmeter/ent/db/chargeusagebasedcostbasis_update.gois excluded by!**/ent/db/**openmeter/ent/db/client.gois excluded by!**/ent/db/**openmeter/ent/db/cursor.gois excluded by!**/ent/db/**openmeter/ent/db/ent.gois excluded by!**/ent/db/**openmeter/ent/db/entmixinaccessor.gois excluded by!**/ent/db/**openmeter/ent/db/expose.gois excluded by!**/ent/db/**openmeter/ent/db/hook/hook.gois excluded by!**/ent/db/**openmeter/ent/db/migrate/schema.gois excluded by!**/ent/db/**openmeter/ent/db/mutation.gois excluded by!**/ent/db/**openmeter/ent/db/paginate.gois excluded by!**/ent/db/**openmeter/ent/db/predicate/predicate.gois excluded by!**/ent/db/**openmeter/ent/db/runtime.gois excluded by!**/ent/db/**openmeter/ent/db/setorclear.gois excluded by!**/ent/db/**openmeter/ent/db/tx.gois excluded by!**/ent/db/**tools/migrate/migrations/atlas.sumis excluded by!**/*.sum,!**/*.sum
📒 Files selected for processing (56)
app/common/billing.goapp/common/charges.gocmd/billing-worker/wire_gen.gocmd/jobs/internal/wire_gen.gocmd/server/wire_gen.goopenmeter/billing/charges/flatfee/adapter.goopenmeter/billing/charges/flatfee/adapter/charge.goopenmeter/billing/charges/flatfee/adapter/costbasis.goopenmeter/billing/charges/flatfee/adapter/intentoverride.goopenmeter/billing/charges/flatfee/adapter/mapper.goopenmeter/billing/charges/flatfee/charge.goopenmeter/billing/charges/flatfee/charge_test.goopenmeter/billing/charges/flatfee/service/create.goopenmeter/billing/charges/flatfee/service/creditheninvoice.goopenmeter/billing/charges/flatfee/service/lineengine.goopenmeter/billing/charges/flatfee/service/service.goopenmeter/billing/charges/models/costbasis/costbasis.goopenmeter/billing/charges/models/costbasis/intent.goopenmeter/billing/charges/models/costbasis/intent_test.goopenmeter/billing/charges/models/costbasis/model.goopenmeter/billing/charges/models/costbasis/resolver.goopenmeter/billing/charges/models/costbasis/state.goopenmeter/billing/charges/service/base_test.goopenmeter/billing/charges/service/flatfee_costbasis_test.goopenmeter/billing/charges/service/invoicable_test.goopenmeter/billing/charges/service/usagebased_costbasis_test.goopenmeter/billing/charges/testutils/service.goopenmeter/billing/charges/usagebased/adapter.goopenmeter/billing/charges/usagebased/adapter/charge.goopenmeter/billing/charges/usagebased/adapter/costbasis.goopenmeter/billing/charges/usagebased/adapter/intentoverride.goopenmeter/billing/charges/usagebased/adapter/intentoverride_test.goopenmeter/billing/charges/usagebased/adapter/mapper.goopenmeter/billing/charges/usagebased/charge.goopenmeter/billing/charges/usagebased/charge_test.goopenmeter/billing/charges/usagebased/service.goopenmeter/billing/charges/usagebased/service/create.goopenmeter/billing/charges/usagebased/service/creditheninvoice.goopenmeter/billing/charges/usagebased/service/service.goopenmeter/billing/charges/usagebased/service/statemachine.goopenmeter/billing/charges/usagebased/service/triggers.goopenmeter/currencies/adapter/currencies.goopenmeter/currencies/adapter/currencies_test.goopenmeter/currencies/repository.goopenmeter/currencies/service.goopenmeter/currencies/service/service.goopenmeter/ent/schema/charges.goopenmeter/ent/schema/chargescreditpurchase.goopenmeter/ent/schema/chargesflatfee.goopenmeter/ent/schema/chargesusagebased.goopenmeter/ledger/customerbalance/testenv_test.goopenmeter/server/server_test.gopkg/currencyx/code.gopkg/currencyx/currency.gotools/migrate/migrations/20260722145858_add_charge_cost_basis.down.sqltools/migrate/migrations/20260722145858_add_charge_cost_basis.up.sql
💤 Files with no reviewable changes (1)
- openmeter/billing/charges/usagebased/adapter/intentoverride_test.go
🚧 Files skipped from review as they are similar to previous changes (51)
- cmd/billing-worker/wire_gen.go
- openmeter/server/server_test.go
- openmeter/billing/charges/models/costbasis/costbasis.go
- app/common/billing.go
- pkg/currencyx/currency.go
- openmeter/billing/charges/models/costbasis/state.go
- openmeter/billing/charges/models/costbasis/intent_test.go
- openmeter/ledger/customerbalance/testenv_test.go
- openmeter/currencies/repository.go
- openmeter/billing/charges/flatfee/service/lineengine.go
- cmd/jobs/internal/wire_gen.go
- openmeter/billing/charges/usagebased/service/creditheninvoice.go
- openmeter/currencies/service.go
- openmeter/billing/charges/service/invoicable_test.go
- openmeter/billing/charges/service/base_test.go
- cmd/server/wire_gen.go
- openmeter/billing/charges/usagebased/service.go
- openmeter/billing/charges/usagebased/adapter.go
- openmeter/billing/charges/usagebased/service/statemachine.go
- pkg/currencyx/code.go
- openmeter/currencies/adapter/currencies_test.go
- openmeter/ent/schema/chargesusagebased.go
- openmeter/billing/charges/flatfee/adapter.go
- openmeter/billing/charges/flatfee/adapter/intentoverride.go
- openmeter/currencies/service/service.go
- openmeter/billing/charges/usagebased/service/service.go
- app/common/charges.go
- openmeter/billing/charges/flatfee/service/create.go
- openmeter/billing/charges/flatfee/adapter/mapper.go
- openmeter/billing/charges/flatfee/charge_test.go
- openmeter/billing/charges/usagebased/adapter/intentoverride.go
- openmeter/ent/schema/chargescreditpurchase.go
- openmeter/billing/charges/usagebased/service/triggers.go
- openmeter/ent/schema/charges.go
- openmeter/billing/charges/usagebased/adapter/costbasis.go
- openmeter/billing/charges/usagebased/adapter/mapper.go
- openmeter/billing/charges/flatfee/adapter/charge.go
- openmeter/billing/charges/models/costbasis/resolver.go
- openmeter/billing/charges/flatfee/service/service.go
- openmeter/billing/charges/flatfee/service/creditheninvoice.go
- openmeter/billing/charges/usagebased/adapter/charge.go
- openmeter/currencies/adapter/currencies.go
- openmeter/ent/schema/chargesflatfee.go
- openmeter/billing/charges/flatfee/adapter/costbasis.go
- openmeter/billing/charges/models/costbasis/model.go
- openmeter/billing/charges/testutils/service.go
- openmeter/billing/charges/usagebased/charge.go
- openmeter/billing/charges/flatfee/charge.go
- openmeter/billing/charges/service/flatfee_costbasis_test.go
- openmeter/billing/charges/usagebased/charge_test.go
- openmeter/billing/charges/service/usagebased_costbasis_test.go
Summary
Custom-currency charges need a stable cost basis before their value can be applied consistently. This change adds that resolution flow for flat-fee and usage-based charges.
Subscriptions will follow the same approach, so charge resolution establishes the behavior they will depend on.
Behavior
Validation
make lint-go-fastmake test-nocache: 6,272 tests passed and 9 skipped; the only failure was the acknowledged Svix integration test because the local Svix service was unavailable on port 8071.Summary by CodeRabbit
New Features
Bug Fixes
Greptile Summary
This PR adds cost-basis resolution for custom-currency charges. The main changes are:
Confidence Score: 4/5
The flat-fee manual attachment path needs a cost-basis guard before merging.
openmeter/billing/charges/flatfee/service/lineengine.go
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Create custom-currency charge] --> B{Cost-basis mode} B -->|Manual or pinned| C[Resolve at creation] B -->|Dynamic| D[Persist unresolved intent] D --> E[Enter active state] E --> F[Resolve at service-period start] F --> G[Persist first resolved value] G --> H[Create invoice realization] D -. Manual flat-fee attachment .-> HPrompt To Fix All With AI
Reviews (1): Last reviewed commit: "feat(customcurrencies): support resolvin..." | Re-trigger Greptile
Context used (3)