refactor(ledger): correct settlement accounting#4236
Conversation
📝 WalkthroughWalkthroughThis PR refactors the ledger system's customer receivable payment templates by renaming Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
openmeter/ledger/transactions/customer.go (1)
187-228: Tiny nit: error messages could specify which receivable bucket failed.The
authorizedReceivablelookup wraps with"failed to get authorized receivable sub-account"inAuthorizeCustomerReceivablePaymentTemplate(line 283), which is great — but thereclookup here at line 199 (for the authorized receivable) and the open-receivable lookup at line 292 inAuthorizeCustomerReceivablePaymentTemplateboth still use the generic"failed to get receivable sub-account". Aligning the wording would make production debugging a smidge nicer.♻️ Suggested error message tweaks
@@ openmeter/ledger/transactions/customer.go rec, err := customerAccounts.ReceivableAccount.GetSubAccountForRoute(ctx, ledger.CustomerReceivableRouteParams{ Currency: t.Currency, CostBasis: t.CostBasis, TransactionAuthorizationStatus: ledger.TransactionAuthorizationStatusAuthorized, }) if err != nil { - return nil, fmt.Errorf("failed to get receivable sub-account: %w", err) + return nil, fmt.Errorf("failed to get authorized receivable sub-account: %w", err) }@@ openmeter/ledger/transactions/customer.go (AuthorizeCustomerReceivablePaymentTemplate.resolve) openReceivable, err := customerAccounts.ReceivableAccount.GetSubAccountForRoute(ctx, ledger.CustomerReceivableRouteParams{ Currency: t.Currency, CostBasis: t.CostBasis, TransactionAuthorizationStatus: ledger.TransactionAuthorizationStatusOpen, }) if err != nil { - return nil, fmt.Errorf("failed to get receivable sub-account: %w", err) + return nil, fmt.Errorf("failed to get open receivable sub-account: %w", err) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openmeter/ledger/transactions/customer.go` around lines 187 - 228, The error string for the receivable sub-account lookup in SettleCustomerReceivableFromPaymentTemplate.resolve is too generic; update the fmt.Errorf call that wraps the error from rec (the call to customerAccounts.ReceivableAccount.GetSubAccountForRoute) to say "failed to get authorized receivable sub-account: %w" (or equivalent) so it matches the wording used by AuthorizeCustomerReceivablePaymentTemplate; also scan AuthorizeCustomerReceivablePaymentTemplate (and its authorizedReceivable/openReceivable lookups) and make the error messages consistent (use "authorized receivable" for the authorized lookup and "open receivable" for the open lookup) to aid debugging.openmeter/ledger/transactions/legacy.go (2)
20-25: Optional: tag both types with// Deprecated:so IDEs/linters can nudge accidental new uses.Since these are explicitly archived for annotation replay only, a
// Deprecated:line in the doc comment plays nicely withstaticcheck/IDE warnings and makes the archived status hard to miss.♻️ Optional Deprecated marker
// FundCustomerReceivableTemplate is an archived template name kept for // persisted ledger annotations. ... +// +// Deprecated: use AuthorizeCustomerReceivablePaymentTemplate (and +// SettleCustomerReceivableFromPaymentTemplate for the cash-movement leg) in +// new code; this type exists only to keep persisted annotations resolvable. type FundCustomerReceivableTemplate struct {// SettleCustomerReceivablePaymentTemplate is an archived template name kept for // persisted ledger annotations. ... +// +// Deprecated: use SettleCustomerReceivableFromPaymentTemplate in new code; +// this type exists only to keep persisted annotations resolvable. type SettleCustomerReceivablePaymentTemplate struct {Also applies to: 108-113
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openmeter/ledger/transactions/legacy.go` around lines 20 - 25, Add a deprecation doc comment to the archived types so linters/IDEs warn on accidental use: add a comment line starting with "// Deprecated:" above the type declarations for FundCustomerReceivableTemplate and the other archived type at lines ~108-113 (referencing their type names) indicating they are archived for annotation replay only; ensure the comment sits immediately above the type keyword so staticcheck/IDEs pick up the deprecation marker.
15-25: Tiny doc nit: the "should use X instead" pointers might trip up future readers.The way these are wired:
FundCustomerReceivableTemplatewas the authorize stage (inOnPaymentAuthorized); its lifecycle replacement isAuthorizeCustomerReceivablePaymentTemplate.SettleCustomerReceivablePaymentTemplatewas the settle stage (inOnPaymentSettled); its lifecycle replacement isSettleCustomerReceivableFromPaymentTemplate.But the comments cross these — pointing
Fund...atSettleFrom...andSettlePayment...atAuthorize...— which seems to map by "behavioral similarity" (Fund did wash→authorized, like SettleFrom now does) rather than by adapter call-site replacement. Worse,SettlePayment.resolvedoes authorized→open while the newAuthorizedoes open→authorized (literally inverse), so anyone migrating an old call site by following this pointer would book the wrong direction.If the intent is "what to use in new code at the same lifecycle position," I'd suggest swapping the targets and noting the behavior shift. Something like:
📝 Suggested doc tweak
-// FundCustomerReceivableTemplate is an archived template name kept for -// persisted ledger annotations. New payment flows should use -// SettleCustomerReceivableFromPaymentTemplate. -// -// Original semantics: funds the authorized receivable sub-account from wash. +// FundCustomerReceivableTemplate is an archived template name kept for +// persisted ledger annotations. New payment-authorized flows should use +// AuthorizeCustomerReceivablePaymentTemplate; the wash→authorized cash +// movement that used to happen here has been deferred to +// SettleCustomerReceivableFromPaymentTemplate. +// +// Original semantics: funds the authorized receivable sub-account from wash.-// SettleCustomerReceivablePaymentTemplate is an archived template name kept for -// persisted ledger annotations. New payment flows should use -// AuthorizeCustomerReceivablePaymentTemplate. -// -// Original semantics: moves authorized receivable staging into the open -// receivable route. +// SettleCustomerReceivablePaymentTemplate is an archived template name kept +// for persisted ledger annotations. New payment-settled flows should use +// SettleCustomerReceivableFromPaymentTemplate, which now performs the actual +// wash→authorized cash movement instead of the legacy authorized→open shuffle. +// +// Original semantics: moves authorized receivable staging into the open +// receivable route.Also applies to: 102-113
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@openmeter/ledger/transactions/legacy.go` around lines 15 - 25, The doc comment on FundCustomerReceivableTemplate incorrectly points to SettleCustomerReceivableFromPaymentTemplate; update the pointer targets so the lifecycle replacements map by call-site lifecycle: point FundCustomerReceivableTemplate (authorize-stage) to AuthorizeCustomerReceivablePaymentTemplate and point SettleCustomerReceivablePaymentTemplate (settle-stage) to SettleCustomerReceivableFromPaymentTemplate; also add a short note near each struct (FundCustomerReceivableTemplate and SettleCustomerReceivablePaymentTemplate) explaining that the new templates have different directional behavior (e.g., authorize→open vs. open→authorized) so callers should verify semantics when migrating from OnPaymentAuthorized / OnPaymentSettled and from SettlePayment.resolve.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@openmeter/ledger/transactions/customer.go`:
- Around line 187-228: The error string for the receivable sub-account lookup in
SettleCustomerReceivableFromPaymentTemplate.resolve is too generic; update the
fmt.Errorf call that wraps the error from rec (the call to
customerAccounts.ReceivableAccount.GetSubAccountForRoute) to say "failed to get
authorized receivable sub-account: %w" (or equivalent) so it matches the wording
used by AuthorizeCustomerReceivablePaymentTemplate; also scan
AuthorizeCustomerReceivablePaymentTemplate (and its
authorizedReceivable/openReceivable lookups) and make the error messages
consistent (use "authorized receivable" for the authorized lookup and "open
receivable" for the open lookup) to aid debugging.
In `@openmeter/ledger/transactions/legacy.go`:
- Around line 20-25: Add a deprecation doc comment to the archived types so
linters/IDEs warn on accidental use: add a comment line starting with "//
Deprecated:" above the type declarations for FundCustomerReceivableTemplate and
the other archived type at lines ~108-113 (referencing their type names)
indicating they are archived for annotation replay only; ensure the comment sits
immediately above the type keyword so staticcheck/IDEs pick up the deprecation
marker.
- Around line 15-25: The doc comment on FundCustomerReceivableTemplate
incorrectly points to SettleCustomerReceivableFromPaymentTemplate; update the
pointer targets so the lifecycle replacements map by call-site lifecycle: point
FundCustomerReceivableTemplate (authorize-stage) to
AuthorizeCustomerReceivablePaymentTemplate and point
SettleCustomerReceivablePaymentTemplate (settle-stage) to
SettleCustomerReceivableFromPaymentTemplate; also add a short note near each
struct (FundCustomerReceivableTemplate and
SettleCustomerReceivablePaymentTemplate) explaining that the new templates have
different directional behavior (e.g., authorize→open vs. open→authorized) so
callers should verify semantics when migrating from OnPaymentAuthorized /
OnPaymentSettled and from SettlePayment.resolve.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 38622c2a-0a9e-4340-bad0-1ed8c831afe2
📒 Files selected for processing (15)
openmeter/ledger/chargeadapter/creditpurchase.goopenmeter/ledger/chargeadapter/creditpurchase_test.goopenmeter/ledger/chargeadapter/flatfee.goopenmeter/ledger/chargeadapter/flatfee_test.goopenmeter/ledger/chargeadapter/usagebased.goopenmeter/ledger/chargeadapter/usagebased_test.goopenmeter/ledger/customerbalance/testenv_test.goopenmeter/ledger/routingrules/routingrules_test.goopenmeter/ledger/transactions/correction.goopenmeter/ledger/transactions/correction_test.goopenmeter/ledger/transactions/customer.goopenmeter/ledger/transactions/customer_test.goopenmeter/ledger/transactions/legacy.goopenmeter/ledger/transactions/testenv_test.gotest/credits/sanity_test.go
Overview
Notes for reviewer
Summary by CodeRabbit
Release Notes
Improvements
Chores