Skip to content

Conversation

@laouji
Copy link
Contributor

@laouji laouji commented Jul 30, 2025

Fixes: PMNT-135

@laouji laouji requested a review from a team as a code owner July 30, 2025 09:02
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 30, 2025

Walkthrough

This change removes the internal currency package and all its usages, replacing all imports with the external github.com/formancehq/go-libs/v3/currency library. Associated test files and utilities for currency formatting, precision, and amount conversion are deleted. Dependency injection annotations in the API module are also updated for clarity.

Changes

Cohort / File(s) Change Summary
Remove internal currency utilities and tests
internal/connectors/plugins/currency/amount.go, internal/connectors/plugins/currency/amount_test.go, internal/connectors/plugins/currency/currency.go
Deleted internal currency conversion and formatting utilities, along with all related unit tests.
Replace internal currency imports with external library
internal/api/validation/checkers.go, internal/connectors/plugins/public/.../*.go, internal/connectors/plugins/public/.../payments_test.go (all plugin submodules)
Replaced all imports of the internal currency package with the external github.com/formancehq/go-libs/v3/currency library. No other logic changes.
Dependency injection annotation update
internal/api/module.go
Updated fx.Provide and fx.Invoke calls to use explicit parameter/result tagging for the chi.Mux router with Fx's dependency injection.

Sequence Diagram(s)

Not applicable: No new features or control flow changes introduced.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15 minutes

Assessment against linked issues

Objective Addressed Explanation
Start using go-libs currency package and remove internal duplication (PMNT-135)

Assessment against linked issues: Out-of-scope changes

No out-of-scope changes found.

Possibly related PRs

Poem

A bunny hopped through fields of code,
Replacing old with new bestowed.
Currency tools, now slim and neat,
Go-libs brings a tidy feat.
Internal bits, we bid adieu—
The garden’s fresh, the sky is blue!
🐇💸

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b57ebe and 8fdcb4e.

⛔ Files ignored due to path filters (2)
  • go.mod is excluded by !**/*.mod
  • go.sum is excluded by !**/*.sum, !**/*.sum
📒 Files selected for processing (1)
  • tools/connector-template/template/currencies.gotpl (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tools/connector-template/template/currencies.gotpl
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: Dirty
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch PMNT-135

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link

codecov bot commented Jul 30, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 69.55%. Comparing base (113ba97) to head (8fdcb4e).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #500      +/-   ##
==========================================
- Coverage   69.55%   69.55%   -0.01%     
==========================================
  Files         628      626       -2     
  Lines       32401    32302      -99     
==========================================
- Hits        22536    22467      -69     
+ Misses       8620     8590      -30     
  Partials     1245     1245              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

go.mod Outdated
github.com/adyen/adyen-go-api-library/v7 v7.3.1
github.com/bombsimon/logrusr/v3 v3.1.0
github.com/formancehq/go-libs/v3 v3.0.0
github.com/formancehq/go-libs/v3 v3.0.1-0.20250730083246-96260bc6aaa5
Copy link
Contributor

Choose a reason for hiding this comment

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

should we do a release for go libs instead? Not sure 🤷
I'll have the same problem in not too long, so maybe not worth it yet?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh this explains why it started to complain in my PR. dependabot downgraded go-libs 😨

2dc7011

) *chi.Mux {
return NewRouter(backend, info, healthController, a, debug, versions...)
}, fx.ParamTags(``, ``, ``, ``, `group:"apiVersions"`))),
}, fx.ParamTags(``, ``, ``, ``, `group:"apiVersions"`), fx.ResultTags(`name:"apiRouter"`))),
Copy link
Contributor

Choose a reason for hiding this comment

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

can we do it the other way around -- make sure any router provided by go-libs are only for the go-libs stuff?
Probably wishful thinking, but it'd make the lib less "intrusive"
I also don't get why it's a problem just now 😂

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't fully understand the fx magic either... I'll make a separate PR in go-libs to add annotations to the profiling module that was interferring.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

I approved it; can we see if it works as we expect in payment (i.e. without the annotation)
We can keep the annotation regardless, I guess it wouldn't hurt, but I'm curious if that annotation is "use only if matching" or more of a "best attempt"

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (4)
internal/connectors/plugins/public/stripe/create_transfers.go (1)

40-42: Potential loss of precision when down-casting big.Int to int64

pi.Amount.Int64() truncates if the value exceeds math.MaxInt64, silently corrupting large-value transfers.

-Amount:         pi.Amount.Int64(),
+// Reject amounts that cannot fit in int64 to avoid silent truncation
+if !pi.Amount.IsInt64() {
+    return models.PSPPayment{}, errorsutils.NewWrappedError(
+        fmt.Errorf("amount %s exceeds int64", pi.Amount.String()),
+        models.ErrInvalidRequest,
+    )
+}
+Amount: pi.Amount.Int64(),
internal/connectors/plugins/public/currencycloud/transfers.go (1)

72-80: Silent “unsupported currency” case returns success – this is a bug

translateTransferToPayment returns (models.PSPPayment{}, nil) when the currency isn’t in supportedCurrenciesWithDecimal.
Callers will treat this as a successful conversion yet get an empty payment object.

Apply something like:

-	precision, ok := supportedCurrenciesWithDecimal[from.Currency]
-	if !ok {
-		return models.PSPPayment{}, nil
-	}
+	precision, ok := supportedCurrenciesWithDecimal[from.Currency]
+	if !ok {
+		return models.PSPPayment{}, fmt.Errorf("unsupported currency: %s", from.Currency)
+	}

Remember to add fmt to the import list. This pattern appears in payouts.go too—fix both spots.

internal/connectors/plugins/public/currencycloud/payouts.go (1)

74-80: Same silent failure case as in transfers – needs fixing

Returning (models.PSPPayment{}, nil) on an unknown currency hides an error.

Replicate the guard suggested for transfers.go, e.g.:

-	precision, ok := supportedCurrenciesWithDecimal[from.Currency]
-	if !ok {
-		return models.PSPPayment{}, nil
-	}
+	precision, ok := supportedCurrenciesWithDecimal[from.Currency]
+	if !ok {
+		return models.PSPPayment{}, fmt.Errorf("unsupported currency: %s", from.Currency)
+	}
internal/connectors/plugins/public/wise/payments.go (1)

66-70: Potential slice panic when fewer results than PageSize

payments = payments[:req.PageSize] (and the same for paymentIDs) will panic if len(payments) < req.PageSize.
Guard the length before slicing.

-if !needMore {
-    payments = payments[:req.PageSize]
-    paymentIDs = paymentIDs[:req.PageSize]
+if !needMore && len(payments) >= req.PageSize {
+    payments = payments[:req.PageSize]
+    paymentIDs = paymentIDs[:req.PageSize]
 }
♻️ Duplicate comments (10)
internal/connectors/plugins/public/stripe/payments.go (1)

11-11: Same FormatAsset concern applies here

This file also relies heavily on currency.FormatAsset. Please ensure the verification suggested in the Stripe balances review passes for the whole codebase.

internal/connectors/plugins/public/increase/payouts.go (1)

11-11: Same FormatAsset concern applies here

Build will fail if the function is missing or its signature changed in the external library. Covered by the earlier verification step.

internal/connectors/plugins/public/stripe/create_payouts.go (2)

40-42: Repeated int64 cast – apply same guard

The payout path repeats the big.Intint64 cast. Guard against overflow exactly as suggested for transfers to keep behaviour consistent.


23-29: Confirm helper availability

Again, validate that GetCurrencyAndPrecisionFromAsset exists in go-libs/v3.

internal/connectors/plugins/public/bankingcircle/balances.go (1)

9-9: Same API-parity concern as noted for Moneycorp

internal/connectors/plugins/public/stripe/accounts.go (1)

8-8: Same API-parity concern as noted for Moneycorp

internal/connectors/plugins/public/bankingcircle/transfers.go (1)

8-8: Same API-parity concern as noted for Moneycorp

internal/connectors/plugins/public/generic/balances.go (1)

9-9: Same API-parity concern as noted for Moneycorp

internal/connectors/plugins/public/bankingcircle/currencies.go (1)

3-31: Import migration is fine – decimals still sourced from ISO 4217

No further action. Same comment as in generic/currencies.go regarding pinning the dependency applies here.

internal/connectors/plugins/public/increase/currencies.go (1)

3-3: LGTM – import path updated

Same note as earlier about ensuring go-libs/v3 version is controlled.

🧹 Nitpick comments (8)
internal/connectors/plugins/public/atlar/balances.go (1)

8-8: Import switch OK, but map duplication worth reconsidering

Good to see the move to the shared library.
Now that go-libs/v3/currency owns currency metadata, the local supportedCurrenciesWithDecimal map is redundant and a future divergence hazard. Prefer using the library’s source of truth (e.g., currency.PrecisionByCode) throughout.

internal/connectors/plugins/public/wise/balances.go (1)

47-50: Error message could be more informative

Wrapping the error from GetAmountWithPrecisionFromString with context (currency code & value) would ease debugging.

-amount, err := currency.GetAmountWithPrecisionFromString(balance.Amount.Value.String(), precision)
+amountStr := balance.Amount.Value.String()
+amount, err := currency.GetAmountWithPrecisionFromString(amountStr, precision)
+if err != nil {
+    return models.FetchNextBalancesResponse{}, fmt.Errorf(
+        "parsing Wise amount %s (currency %s, precision %d): %w",
+        amountStr, balance.Amount.Currency, precision, err)
+}
internal/connectors/plugins/public/modulr/payouts.go (1)

9-9: Possible dead code: duplicated precision map

Even after switching to go-libs, every conversion still passes the local
supportedCurrenciesWithDecimal map.
go-libs ships its own precision registry; keeping both tables increases the
risk of divergence.

Consider deleting the local map and calling the simple helpers:

- curr, precision, err := currency.GetCurrencyAndPrecisionFromAsset(supportedCurrenciesWithDecimal, pi.Asset)
+ curr, precision, err := currency.GetCurrencyAndPrecision(pi.Asset)

(and similar for FormatAsset, GetAmountWithPrecisionFromString, …).

Cleaner code and one single source of truth for currency metadata.

Also applies to: 20-34, 77-88

internal/connectors/plugins/public/modulr/transfers.go (1)

9-9: Same duplication comment as in payouts.go

All precision/format helpers still delegate to the hand-rolled
supportedCurrenciesWithDecimal instead of leveraging go-libs’ internal
registry. Re-using the built-in helpers would shrink the codebase and remove
a maintenance hotspot.

Also applies to: 20-34, 80-83, 90-90

internal/connectors/plugins/public/column/payments.go (1)

12-12: Nil-safe asset pointer

currency.FormatAsset returns an empty string when the code is unknown; this
would still be wrapped in pointer.For(""), giving a non-nil pointer to an
empty asset and polluting downstream analytics.
You might want to guard the call or return nil when the asset is not
recognised.

Also applies to: 88-90

internal/connectors/plugins/public/generic/payments.go (1)

58-60: Minor readability nit – index with updatedAts directly

updatedAts[len(payments)-1] works because both slices are kept in sync, but using the slice’s own length is clearer and future-proof if their sizes ever diverge.

-    newState.LastUpdatedAtFrom = updatedAts[len(payments)-1]
+    newState.LastUpdatedAtFrom = updatedAts[len(updatedAts)-1]
internal/connectors/plugins/public/currencycloud/currencies.go (1)

7-36: Consider deferring to the library’s precision map instead of duplicating values

supportedCurrenciesWithDecimal copies entries straight from currency.ISO4217Currencies. If you only want a subset, keeping a slice of allowed codes and looking them up in the library map on-demand removes duplication and maintenance effort.

Optional refactor:

var supportedCurrencies = []string{
    "AUD", "CAD", "CZK", /* … */
}

func precision(code string) (int, bool) {
    for _, c := range supportedCurrencies {
        if c == code {
            p, ok := currency.ISO4217Currencies[code]
            return p, ok
        }
    }
    return 0, false
}
internal/connectors/plugins/public/column/accounts.go (1)

65-68: Off-by-one guard may over-fetch

if len(accounts) > pageSize { break } stops only when the slice length is greater than pageSize; it allows one extra element before breaking.
If the intention is to cap at exactly pageSize, change the condition to >=.

- if len(accounts) > pageSize {
+ if len(accounts) >= pageSize {

@laouji laouji added this pull request to the merge queue Jul 30, 2025
Merged via the queue into main with commit 6d43a24 Jul 30, 2025
9 checks passed
@laouji laouji deleted the PMNT-135 branch July 30, 2025 11:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants