From f1964b1e3dd32ed2ab85978f85340bd5307d7ef8 Mon Sep 17 00:00:00 2001 From: MMichotte Date: Mon, 9 Sep 2024 21:39:39 +0200 Subject: [PATCH 1/4] fix: Wrong payeeName used for CBC_CREGBEBB --- src/app-gocardless/bank-factory.js | 2 + src/app-gocardless/banks/cbc_cregbebb.js | 52 +++++++++++++++++++ .../banks/tests/cbc_cregbebb.spec.js | 36 +++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 src/app-gocardless/banks/cbc_cregbebb.js create mode 100644 src/app-gocardless/banks/tests/cbc_cregbebb.spec.js diff --git a/src/app-gocardless/bank-factory.js b/src/app-gocardless/bank-factory.js index 3b36193c0..04aa36ad8 100644 --- a/src/app-gocardless/bank-factory.js +++ b/src/app-gocardless/bank-factory.js @@ -5,6 +5,7 @@ import BankinterBkbkesmm from './banks/bankinter-bkbkesmm.js'; import Belfius from './banks/belfius_gkccbebb.js'; import Berliner_Sparkasse_beladebexxx from './banks/berliner_sparkasse_beladebexxx.js'; import BnpBeGebabebb from './banks/bnp-be-gebabebb.js'; +import CBCcregbebb from './banks/cbc_cregbebb.js'; import DanskeBankDabNO22 from './banks/danskebank-dabno22.js'; import EasybankBawaatww from './banks/easybank-bawaatww.js'; import Fortuneo from './banks/FORTUNEO_FTNOFRP1XXX.js'; @@ -32,6 +33,7 @@ export const banks = [ Belfius, Berliner_Sparkasse_beladebexxx, BnpBeGebabebb, + CBCcregbebb, DanskeBankDabNO22, EasybankBawaatww, Fortuneo, diff --git a/src/app-gocardless/banks/cbc_cregbebb.js b/src/app-gocardless/banks/cbc_cregbebb.js new file mode 100644 index 000000000..2161b291a --- /dev/null +++ b/src/app-gocardless/banks/cbc_cregbebb.js @@ -0,0 +1,52 @@ +import Fallback from './integration-bank.js'; + +/** + * The remittance information contains creditorName, payments method, dates, etc. + * This function makes sure to only extract the creditorName based on the different indicators like "Paiement". + * f.e. ONKART FR Viry Paiement Maestro par Carte de débit CBC 05-09-2024 à 15.43 heures 6703 19XX XXXX X... -> ONKART FR Viry + */ +function extractPayeeName(remittanceInformationUnstructured) { + const indices = [ + remittanceInformationUnstructured.lastIndexOf(' Paiement'), + remittanceInformationUnstructured.lastIndexOf(' Domiciliation'), + remittanceInformationUnstructured.lastIndexOf(' Transfert'), + remittanceInformationUnstructured.lastIndexOf(' Ordre permanent'), + ]; + + const indexForRemoval = Math.max(...indices); + + return indexForRemoval > -1 + ? remittanceInformationUnstructured.substring(0, indexForRemoval) + : remittanceInformationUnstructured; +} + +/** @type {import('./bank.interface.js').IBank} */ +export default { + ...Fallback, + + institutionIds: ['CBC_CREGBEBB'], + + /** + * For negative amounts, the only payee information we have is returned in + * remittanceInformationUnstructured. + */ + normalizeTransaction(transaction, _booked) { + if (Number(transaction.transactionAmount.amount) > 0) { + return { + ...transaction, + payeeName: + transaction.debtorName || + transaction.remittanceInformationUnstructured, + date: transaction.bookingDate || transaction.valueDate, + }; + } + + return { + ...transaction, + payeeName: + transaction.creditorName || + extractPayeeName(transaction.remittanceInformationUnstructured), + date: transaction.bookingDate || transaction.valueDate, + }; + }, +}; diff --git a/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js b/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js new file mode 100644 index 000000000..de22a00ea --- /dev/null +++ b/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js @@ -0,0 +1,36 @@ +import CBCcregbebb from '../cbc_cregbebb.js'; + +describe('cbc_cregbebb', () => { + describe('#normalizeTransaction', () => { + it('returns the remittanceInformationUnstructured as payeeName when the amount is negative', () => { + const transaction = { + remittanceInformationUnstructured: + 'ONKART FR Viry Paiement Maestro par Carte de débit CBC 05-09-2024 à 15.43 heures 6703 19XX XXXX X201 5 JOHN DOE', + transactionAmount: { amount: '-45.00', currency: 'EUR' }, + }; + const normalizedTransaction = CBCcregbebb.normalizeTransaction( + transaction, + true, + ); + expect(normalizedTransaction.payeeName).toEqual( + 'ONKART FR Viry', + ); + }); + + it('returns the debtorName as payeeName when the amount is positive', () => { + const transaction = { + debtorName: 'ONKART FR Viry', + remittanceInformationUnstructured: + 'ONKART FR Viry Paiement Maestro par Carte de débit CBC 05-09-2024 à 15.43 heures 6703 19XX XXXX X201 5 JOHN DOE', + transactionAmount: { amount: '10.99', currency: 'EUR' }, + }; + const normalizedTransaction = CBCcregbebb.normalizeTransaction( + transaction, + true, + ); + expect(normalizedTransaction.payeeName).toEqual( + 'ONKART FR Viry', + ); + }); + }); +}); From 515deec5808e10a6896c884b3fda499bb8bbee78 Mon Sep 17 00:00:00 2001 From: MMichotte Date: Mon, 9 Sep 2024 21:42:06 +0200 Subject: [PATCH 2/4] chore: add release note --- upcoming-release-notes/451.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 upcoming-release-notes/451.md diff --git a/upcoming-release-notes/451.md b/upcoming-release-notes/451.md new file mode 100644 index 000000000..a6b2e9491 --- /dev/null +++ b/upcoming-release-notes/451.md @@ -0,0 +1,6 @@ +--- +category: Bugfix +authors: [MMichotte] +--- + +Fix wrong payeeName used for CBC_CREGBEBB \ No newline at end of file From ec92abffaaa058989299a845233b281fc9952b23 Mon Sep 17 00:00:00 2001 From: MMichotte Date: Mon, 9 Sep 2024 22:24:57 +0200 Subject: [PATCH 3/4] style: fix some linting errors in cbc tests --- src/app-gocardless/banks/tests/cbc_cregbebb.spec.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js b/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js index de22a00ea..4114ac494 100644 --- a/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js +++ b/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js @@ -12,9 +12,7 @@ describe('cbc_cregbebb', () => { transaction, true, ); - expect(normalizedTransaction.payeeName).toEqual( - 'ONKART FR Viry', - ); + expect(normalizedTransaction.payeeName).toEqual('ONKART FR Viry'); }); it('returns the debtorName as payeeName when the amount is positive', () => { @@ -28,9 +26,7 @@ describe('cbc_cregbebb', () => { transaction, true, ); - expect(normalizedTransaction.payeeName).toEqual( - 'ONKART FR Viry', - ); + expect(normalizedTransaction.payeeName).toEqual('ONKART FR Viry'); }); }); }); From 7fd0d97614cb90dfbd5650ad94aff1b808b36c05 Mon Sep 17 00:00:00 2001 From: MMichotte Date: Tue, 10 Sep 2024 20:42:30 +0200 Subject: [PATCH 4/4] refactor: add helper function to improve reusability. Add 'extractPayeeNameFromRemittanceInfo' helper function to prevent code-duplication when adding new bank-specific overrides to properly extract the payeeName from the remittanceInformationUnstructured string. Updated following files to accommodate change: - cbc_cregbebb - kbc_kredbebb --- src/app-gocardless/banks/cbc_cregbebb.js | 26 +++----------- src/app-gocardless/banks/kbc_kredbebb.js | 25 +++---------- .../extract-payeeName-from-remittanceInfo.js | 36 +++++++++++++++++++ 3 files changed, 46 insertions(+), 41 deletions(-) create mode 100644 src/app-gocardless/banks/util/extract-payeeName-from-remittanceInfo.js diff --git a/src/app-gocardless/banks/cbc_cregbebb.js b/src/app-gocardless/banks/cbc_cregbebb.js index 2161b291a..bf881dacf 100644 --- a/src/app-gocardless/banks/cbc_cregbebb.js +++ b/src/app-gocardless/banks/cbc_cregbebb.js @@ -1,25 +1,6 @@ +import { extractPayeeNameFromRemittanceInfo } from './util/extract-payeeName-from-remittanceInfo.js'; import Fallback from './integration-bank.js'; -/** - * The remittance information contains creditorName, payments method, dates, etc. - * This function makes sure to only extract the creditorName based on the different indicators like "Paiement". - * f.e. ONKART FR Viry Paiement Maestro par Carte de débit CBC 05-09-2024 à 15.43 heures 6703 19XX XXXX X... -> ONKART FR Viry - */ -function extractPayeeName(remittanceInformationUnstructured) { - const indices = [ - remittanceInformationUnstructured.lastIndexOf(' Paiement'), - remittanceInformationUnstructured.lastIndexOf(' Domiciliation'), - remittanceInformationUnstructured.lastIndexOf(' Transfert'), - remittanceInformationUnstructured.lastIndexOf(' Ordre permanent'), - ]; - - const indexForRemoval = Math.max(...indices); - - return indexForRemoval > -1 - ? remittanceInformationUnstructured.substring(0, indexForRemoval) - : remittanceInformationUnstructured; -} - /** @type {import('./bank.interface.js').IBank} */ export default { ...Fallback, @@ -45,7 +26,10 @@ export default { ...transaction, payeeName: transaction.creditorName || - extractPayeeName(transaction.remittanceInformationUnstructured), + extractPayeeNameFromRemittanceInfo( + transaction.remittanceInformationUnstructured, + ['Paiement', 'Domiciliation', 'Transfert', 'Ordre permanent'], + ), date: transaction.bookingDate || transaction.valueDate, }; }, diff --git a/src/app-gocardless/banks/kbc_kredbebb.js b/src/app-gocardless/banks/kbc_kredbebb.js index 089c4deca..f2c7a725e 100644 --- a/src/app-gocardless/banks/kbc_kredbebb.js +++ b/src/app-gocardless/banks/kbc_kredbebb.js @@ -1,24 +1,6 @@ +import { extractPayeeNameFromRemittanceInfo } from './util/extract-payeeName-from-remittanceInfo.js'; import Fallback from './integration-bank.js'; -/** - * The remittance information contains creditorName, payments method, dates, etc. - * This function makes sure to only extract the creditorName based on the different indicators like "Betaling met". - * f.e. Proxy Poel BE Gent Betaling met Apple Pay via Maestro 23-08-2024 om 14.03 uur XXXX XXXX XXXX XXXX -> Proxy Poel BE Gent - */ -function extractPayeeName(remittanceInformationUnstructured) { - const indices = [ - remittanceInformationUnstructured.lastIndexOf(' Betaling met'), - remittanceInformationUnstructured.lastIndexOf(' Domiciliëring'), - remittanceInformationUnstructured.lastIndexOf(' Overschrijving'), - ]; - - const indexForRemoval = Math.max(...indices); - - return indexForRemoval > -1 - ? remittanceInformationUnstructured.substring(0, indexForRemoval) - : remittanceInformationUnstructured; -} - /** @type {import('./bank.interface.js').IBank} */ export default { ...Fallback, @@ -44,7 +26,10 @@ export default { ...transaction, payeeName: transaction.creditorName || - extractPayeeName(transaction.remittanceInformationUnstructured), + extractPayeeNameFromRemittanceInfo( + transaction.remittanceInformationUnstructured, + ['Betaling met', 'Domiciliëring', 'Overschrijving'], + ), date: transaction.bookingDate || transaction.valueDate, }; }, diff --git a/src/app-gocardless/banks/util/extract-payeeName-from-remittanceInfo.js b/src/app-gocardless/banks/util/extract-payeeName-from-remittanceInfo.js new file mode 100644 index 000000000..4dcb7fa2d --- /dev/null +++ b/src/app-gocardless/banks/util/extract-payeeName-from-remittanceInfo.js @@ -0,0 +1,36 @@ +/** +/** + * Extracts the payee name from the unstructured remittance information string based on pattern detection. + * + * This function scans the `remittanceInformationUnstructured` string for the presence of + * any of the specified patterns and removes the substring from the position of the last + * occurrence of the most relevant pattern. If no patterns are found, it returns the original string. + * + * @param {string} [remittanceInformationUnstructured=''] - The unstructured remittance information from which to extract the payee name. + * @param {string[]} [patterns=[]] - An array of patterns to look for within the remittance information. + * These patterns are used to identify and remove unwanted parts of the remittance information. + * @returns {string} - The extracted payee name, cleaned of any matched patterns, or the original + * remittance information if no patterns are found. + * + * @example + * const remittanceInfo = 'John Doe Paiement Maestro par Carte de débit CBC 05-09-2024 à 15.43 heures 6703 19XX XXXX X...'; + * const patterns = ['Paiement', 'Domiciliation', 'Transfert', 'Ordre permanent']; + * const payeeName = extractPayeeNameFromRemittanceInfo(remittanceInfo, patterns); // --> 'John Doe' + */ +export function extractPayeeNameFromRemittanceInfo( + remittanceInformationUnstructured, + patterns, +) { + if (!remittanceInformationUnstructured || !patterns.length) { + return remittanceInformationUnstructured; + } + + const indexForRemoval = patterns.reduce((maxIndex, pattern) => { + const index = remittanceInformationUnstructured.lastIndexOf(pattern); + return index > maxIndex ? index : maxIndex; + }, -1); + + return indexForRemoval > -1 + ? remittanceInformationUnstructured.substring(0, indexForRemoval).trim() + : remittanceInformationUnstructured; +}