-
-
Notifications
You must be signed in to change notification settings - Fork 662
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add GoCardless integration for COMMERZBANK_COBADEFF #537
base: master
Are you sure you want to change the base?
Add GoCardless integration for COMMERZBANK_COBADEFF #537
Conversation
WalkthroughThe pull request introduces a new bank module for Commerzbank (COBADEFF) to the existing banking integration system. The changes include adding a new bank entity to the bank factory, creating a comprehensive module for handling Commerzbank-specific banking operations, and implementing corresponding unit tests. The module provides detailed methods for normalizing account and transaction data, including specialized handling of transaction remittance information and balance calculations. A type definition update in the TypeScript types file allows for more flexible creditor account information representation. The implementation follows the existing pattern of bank-specific modules, adding support for a new financial institution while maintaining the overall structure and approach of the existing codebase. The changes are focused on extending the system's capabilities to handle Commerzbank transactions with precise data normalization techniques. Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/app-gocardless/banks/commerzbank_cobadeff.js (1)
25-50
: Keyword fix approach
Appending a comma and space before the found keyword could lead to repeated commas in some edge cases (e.g., if the text already contains partial keywords). Keep track to ensure repeated replacements do not produce unexpected spacing.src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js (2)
5-34
: Test coverage looks solid
The first test scenario verifies that unstructured remittance information is correctly formatted, combining multiline data into one string. Ensure you also verify what happens ifremittanceInformationUnstructuredArray
orcreditorName
is missing.Do you want me to open a new issue to discuss adding negative or missing-data tests?
74-108
: Removing 'NOTPROVIDED'
The test verifies correct removal of placeholders like'NOTPROVIDED'
. This is a good approach to keep the final data clean. Confirm that other placeholders or formatting gotchas are similarly addressed in the code.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
upcoming-release-notes/537.md
is excluded by!**/*.md
📒 Files selected for processing (4)
src/app-gocardless/bank-factory.js
(2 hunks)src/app-gocardless/banks/commerzbank_cobadeff.js
(1 hunks)src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js
(1 hunks)src/app-gocardless/gocardless-node.types.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Build Docker image (alpine)
🔇 Additional comments (6)
src/app-gocardless/banks/commerzbank_cobadeff.js (2)
1-2
: Import clarity check
These imports look good and appear necessary for the fallback integration and utility functions. No issues identified.
51-61
: Careful payee removal
When removing the payee name fromremittanceInformationUnstructured
, consider that partial matches of the payee name might also get stripped inadvertently. If the payee includes shorter words, they might be matched incorrectly.src/app-gocardless/bank-factory.js (2)
10-10
: New module import
Good job adding the new import statement forCommerzbankCobadeff
. This is consistent with the existing pattern for other bank modules.
48-48
: Bank array registration
RegisteringCommerzbankCobadeff
in thebanks
array ensures the factory will properly identify and use it when given the institution ID. Looks great!src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js (1)
36-72
: Split keyword repair
This test effectively checks the partial keyword merging logic. Good coverage. Keep in mind that the logic inkeywords.forEach
may break with unforeseen edge cases or if the user’s data includes unusual bracketed or special characters.src/app-gocardless/gocardless-node.types.ts (1)
359-363
: Optional IBAN structure
AllowingcreditorAccount
to be a string or an object with a possibleiban
is flexible and aligns well with the new Commerzbank integration. If you expect other fields (e.g., BIC) in the future, consider a more generalized type.
calculateStartingBalance(sortedTransactions = [], balances = []) { | ||
const currentBalance = balances.find( | ||
(balance) => 'expected' === balance.balanceType, | ||
); | ||
|
||
return sortedTransactions.reduce((total, trans) => { | ||
return total - amountToInteger(trans.transactionAmount.amount); | ||
}, amountToInteger(currentBalance.balanceAmount.amount)); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for empty balances
array
When calling calculateStartingBalance
, if balances
is empty or lacks an 'expected'
entry, currentBalance
could be undefined
. Consider returning 0 or an error if no suitable balanceType
is found.
calculateStartingBalance(sortedTransactions = [], balances = []) {
const currentBalance = balances.find(
(balance) => 'expected' === balance.balanceType,
);
+ if (!currentBalance) {
+ // Decide on fallback or throw error
+ return 0;
+ }
return sortedTransactions.reduce((total, trans) => {
return total - amountToInteger(trans.transactionAmount.amount);
}, amountToInteger(currentBalance.balanceAmount.amount));
},
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
calculateStartingBalance(sortedTransactions = [], balances = []) { | |
const currentBalance = balances.find( | |
(balance) => 'expected' === balance.balanceType, | |
); | |
return sortedTransactions.reduce((total, trans) => { | |
return total - amountToInteger(trans.transactionAmount.amount); | |
}, amountToInteger(currentBalance.balanceAmount.amount)); | |
}, | |
calculateStartingBalance(sortedTransactions = [], balances = []) { | |
const currentBalance = balances.find( | |
(balance) => 'expected' === balance.balanceType, | |
); | |
if (!currentBalance) { | |
// Decide on fallback or throw error | |
return 0; | |
} | |
return sortedTransactions.reduce((total, trans) => { | |
return total - amountToInteger(trans.transactionAmount.amount); | |
}, amountToInteger(currentBalance.balanceAmount.amount)); | |
}, |
normalizeAccount(account) { | ||
return { | ||
account_id: account.id, | ||
institution: account.institution, | ||
mask: account.iban.slice(-4), | ||
iban: account.iban, | ||
name: [account.name, printIban(account)].join(' '), | ||
official_name: account.product, | ||
type: 'checking', | ||
}; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Based on the evidence gathered, I can now provide the final response:
Add safeguard for missing IBAN property in normalizeAccount
The codebase shows that:
- The
printIban
utility already handles missing IBAN gracefully by returning an empty string - There's a test case in
integration-bank.spec.js
that explicitly tests withiban: undefined
- Multiple bank integrations use the same IBAN-dependent pattern
The current implementation needs safeguarding in two places:
mask: account.iban?.slice(-4) ?? ''
iban: account.iban ?? ''
🔗 Analysis chain
Ensure robustness for missing account.iban
The normalizeAccount
function assumes an iban
property is present on the account
. If the bank feed or fallback code potentially returns an account
object without an iban
, this could cause errors. Consider safe-guarding it, for example:
+// Example safeguard, if `account.iban` might be undefined
+iban: account.iban || '',
Let me verify if there are any cases where account
objects might be missing the iban
property by analyzing the codebase.
Let me search for how the account objects are constructed and any test cases that might reveal the behavior.
Let me check the specific test file for Commerzbank and the utility function that handles IBAN printing.
🏁 Scripts executed
The following scripts were executed for the analysis:
Error: No shell scripts found
Script:
#!/bin/bash
# Search for references to account.iban to understand its usage
rg "account\.iban" -B 2 -A 2
# Search for places where account objects are created/returned that might feed into normalizeAccount
ast-grep --pattern 'account = { $$$, iban: $_, $$$}'
# Search for any test files related to this bank integration
fd -g "*commerzbank*test*"
Length of output: 9005
Script:
#!/bin/bash
# Search for test files and fixtures related to bank accounts
fd -e test.js -e spec.js
# Search for account object construction patterns
ast-grep --pattern 'const account = {$$$}'
# Look for any error handling related to IBAN
rg -i "iban.*undefined|missing.*iban" -B 2 -A 2
Length of output: 1977
Script:
#!/bin/bash
# Check the Commerzbank test file
cat src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js
# Check the printIban utility implementation
cat src/app-gocardless/utils.js
Length of output: 5599
normalizeAccount(account) { | ||
return { | ||
account_id: account.id, | ||
institution: account.institution, | ||
mask: account.iban.slice(-4), | ||
iban: account.iban, | ||
name: [account.name, printIban(account)].join(' '), | ||
official_name: account.product, | ||
type: 'checking', | ||
}; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is the same as in the fallback you could remove this and rely on the fallback
normalizeAccount(account) { | |
return { | |
account_id: account.id, | |
institution: account.institution, | |
mask: account.iban.slice(-4), | |
iban: account.iban, | |
name: [account.name, printIban(account)].join(' '), | |
official_name: account.product, | |
type: 'checking', | |
}; | |
}, |
keywords.forEach((keyword) => { | ||
transaction.remittanceInformationUnstructured = | ||
transaction.remittanceInformationUnstructured.replace( | ||
RegExp(keyword.split('').join('\\s*'), 'gi'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RegExp(keyword.split('').join('\\s*'), 'gi'), | |
// There can be spaces inbetween keywords | |
RegExp(keyword.split('').join('\\s*'), 'gi'), |
/** | ||
* For COMMERZBANK_COBADEFF we don't know what balance was | ||
* after each transaction so we have to calculate it by getting | ||
* current balance from the account and subtract all the transactions | ||
* | ||
* As a current balance we use `expected` balance type because it | ||
* corresponds to the current running balance, whereas `interimAvailable` | ||
* holds the remaining credit limit. | ||
*/ | ||
calculateStartingBalance(sortedTransactions = [], balances = []) { | ||
const currentBalance = balances.find( | ||
(balance) => 'expected' === balance.balanceType, | ||
); | ||
|
||
return sortedTransactions.reduce((total, trans) => { | ||
return total - amountToInteger(trans.transactionAmount.amount); | ||
}, amountToInteger(currentBalance.balanceAmount.amount)); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could also just use the fallback?
Seems fine 👍 |
creditorAccount?: | ||
| string | ||
| { | ||
iban?: string; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it happens, this can just be an object. It was wrongly typed before.
creditorAccount?: | |
| string | |
| { | |
iban?: string; | |
}; | |
creditorAccount?: { | |
iban: string; | |
}; |
Add GoCardless integration for COMMERZBANK_COBADEFF, with a bunch of cleanup for remittance information that will become the notes. The source data for this bank is a bit messy to format unfortunately.
Question to the reviewer: Is the implementation of the optional
iban
property forcreditorAccount
correct/clean? Not a dev, sorry.