feat(ledger): validate currency rounding - #4342
Conversation
📝 WalkthroughWalkthroughThe PR enforces that ledger entry amounts are rounded to their posting currency's configured precision. A new internal validator checks each entry's amount against its currency's decimal places, returning a detailed error with the original amount and properly-rounded value when validation fails. Tests cover USD and JPY to verify correct acceptance and rejection of amounts at precision boundaries. ChangesAmount Precision Validation
🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 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)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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 (2)
openmeter/ledger/validations.go (2)
69-74: 💤 Low valueHeads up:
ErrCurrencyInvalidbranch is uncovered and shaped differently from sibling errors.Two small notes on this branch:
- The neighbouring failure modes inside
ValidateEntryInputwrap inner errors asErrEntryInvalidwith areasonattr (see lines 43–47), but here you returnErrCurrencyInvaliddirectly. Not wrong, just a touch inconsistent — callers handling validation issues uniformly may be surprised.- There's no test exercising this path (e.g., an unknown/empty currency). Easy to add and would lock in the contract.
🤖 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/ledger/validations.go` around lines 69 - 74, The ErrCurrencyInvalid return in ValidateEntryInput is inconsistent with sibling error handling: instead of returning ErrCurrencyInvalid directly with Attributes, wrap the underlying currency parse error similarly to the ErrEntryInvalid pattern (include a "reason" attribute) or normalize the sibling errors to use ErrCurrencyInvalid with matching attrs; update the return in ValidateEntryInput (the branch that checks currency and currently returns ErrCurrencyInvalid.WithAttrs(models.Attributes{...})) to include a "reason" attr (or wrap via ErrEntryInvalid.WithAttrs({"reason": err, "currency": currency})), and add a unit test covering an unknown/empty currency to assert the chosen error shape and attributes.
66-87: ⚡ Quick winThe
Route().Route()chain is safe but verbose — consider a helper method for clarity.The nil-safety concern here is actually not an issue: both
PostingAddress.Route()andSubAccountRoute.Route()return value types (not pointers), so they can't be nil. Plus,ValidateAddressalready guards against a nilPostingAddressbefore this function runs.That said, the chain is awkward to read and appears throughout the codebase. A small helper like
PostingAddress.GetRoute()that returns the decodedRoutedirectly would improve readability without changing behavior.🤖 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/ledger/validations.go` around lines 66 - 87, The Route().Route() call chain in validateEntryAmountPrecision (and other places using EntryInput.PostingAddress().Route().Route()) is verbose—add a helper method like PostingAddress.GetRoute() that returns the decoded Route value (the existing decoded type returned by SubAccountRoute.Route()) so callers can use entry.PostingAddress().GetRoute().Currency; implement GetRoute() on the PostingAddress type to perform the current Route() then Route() calls internally, update validateEntryAmountPrecision to use PostingAddress.GetRoute(), and replace other occurrences across the codebase (keeping existing behavior and nil-safety ensured by ValidateAddress).
🤖 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.
Nitpick comments:
In `@openmeter/ledger/validations.go`:
- Around line 69-74: The ErrCurrencyInvalid return in ValidateEntryInput is
inconsistent with sibling error handling: instead of returning
ErrCurrencyInvalid directly with Attributes, wrap the underlying currency parse
error similarly to the ErrEntryInvalid pattern (include a "reason" attribute) or
normalize the sibling errors to use ErrCurrencyInvalid with matching attrs;
update the return in ValidateEntryInput (the branch that checks currency and
currently returns ErrCurrencyInvalid.WithAttrs(models.Attributes{...})) to
include a "reason" attr (or wrap via ErrEntryInvalid.WithAttrs({"reason": err,
"currency": currency})), and add a unit test covering an unknown/empty currency
to assert the chosen error shape and attributes.
- Around line 66-87: The Route().Route() call chain in
validateEntryAmountPrecision (and other places using
EntryInput.PostingAddress().Route().Route()) is verbose—add a helper method like
PostingAddress.GetRoute() that returns the decoded Route value (the existing
decoded type returned by SubAccountRoute.Route()) so callers can use
entry.PostingAddress().GetRoute().Currency; implement GetRoute() on the
PostingAddress type to perform the current Route() then Route() calls
internally, update validateEntryAmountPrecision to use
PostingAddress.GetRoute(), and replace other occurrences across the codebase
(keeping existing behavior and nil-safety ensured by ValidateAddress).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e20379b8-35be-435a-833a-3d884804f202
📒 Files selected for processing (2)
openmeter/ledger/validations.goopenmeter/ledger/validations_test.go
summary
Adds ledger validation to reject transaction entry amounts that are not rounded to the posting currency precision.
details
currencyx.Calculator.IsRoundedToPrecisionledger_transaction_amount_invalidtests