From ae0faf467f5198653d63936a015d00199aa72e79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20L=C3=B6thberg?= Date: Sun, 14 Apr 2024 18:21:47 +0200 Subject: [PATCH] Allow setting accessValidForDays and maxHistoricalDays per bank (#334) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow setting accessValidForDays per bank This also stops taking `accessValidForDays` from the client since it's hardcoded there anyway and it's simpler to just have these per-bank values in one place. Signed-off-by: Johannes Löthberg * Get the max allowed maxHistoricalDays value from the GoCardless API Signed-off-by: Johannes Löthberg * Upgrade nordigen-node to 1.4.0 Contrary to the claims in the nordigen-node changelog 1.3.0 did *not* fix the missing support for passing in accessValidForDays, so we have to upgrade to 1.4.0 to actually get the fix. Signed-off-by: Johannes Löthberg --------- Signed-off-by: Johannes Löthberg --- package.json | 2 +- src/app-gocardless/app-gocardless.js | 3 +-- src/app-gocardless/bank-factory.js | 22 +++++++++---------- .../banks/american-express-aesudef1.js | 2 ++ src/app-gocardless/banks/bank.interface.ts | 3 +++ src/app-gocardless/banks/belfius_gkccbebb.js | 2 ++ src/app-gocardless/banks/bnp-be-gebabebb.js | 2 ++ .../banks/danskebank-dabno22.js | 2 ++ src/app-gocardless/banks/ing-ingddeff.js | 2 ++ src/app-gocardless/banks/ing-pl-ingbplpw.js | 2 ++ src/app-gocardless/banks/integration-bank.js | 8 +++++++ .../banks/mbank-retail-brexplpw.js | 2 ++ .../banks/norwegian-xx-norwnok1.js | 2 ++ .../banks/sandboxfinance-sfin0000.js | 2 ++ src/app-gocardless/banks/seb-kort-bank-ab.js | 2 ++ src/app-gocardless/banks/seb-privat.js | 12 +++------- src/app-gocardless/banks/sparnord-spnodk22.js | 2 ++ .../spk-marburg-biedenkopf-heladef1mar.js | 2 ++ src/app-gocardless/gocardless.types.ts | 1 - .../services/gocardless-service.js | 9 +++++--- .../services/tests/gocardless-service.spec.js | 2 ++ upcoming-release-notes/334.md | 6 +++++ yarn.lock | 10 ++++----- 23 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 upcoming-release-notes/334.md diff --git a/package.json b/package.json index 9a2368ef9..7871c9641 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "express-response-size": "^0.0.3", "jws": "^4.0.0", "migrate": "^2.0.1", - "nordigen-node": "^1.3.0", + "nordigen-node": "^1.4.0", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/src/app-gocardless/app-gocardless.js b/src/app-gocardless/app-gocardless.js index 5d2fe00e2..36e93842e 100644 --- a/src/app-gocardless/app-gocardless.js +++ b/src/app-gocardless/app-gocardless.js @@ -40,11 +40,10 @@ app.post('/status', async (req, res) => { app.post( '/create-web-token', handleError(async (req, res) => { - const { accessValidForDays, institutionId } = req.body; + const { institutionId } = req.body; const { origin } = req.headers; const { link, requisitionId } = await goCardlessService.createRequisition({ - accessValidForDays, institutionId, host: origin, }); diff --git a/src/app-gocardless/bank-factory.js b/src/app-gocardless/bank-factory.js index dc8a6603c..623230a54 100644 --- a/src/app-gocardless/bank-factory.js +++ b/src/app-gocardless/bank-factory.js @@ -1,32 +1,32 @@ import AmericanExpressAesudef1 from './banks/american-express-aesudef1.js'; +import Belfius from './banks/belfius_gkccbebb.js'; +import BnpBeGebabebb from './banks/bnp-be-gebabebb.js'; +import DanskeBankDabNO22 from './banks/danskebank-dabno22.js'; import IngIngddeff from './banks/ing-ingddeff.js'; import IngPlIngbplpw from './banks/ing-pl-ingbplpw.js'; import IntegrationBank from './banks/integration-bank.js'; import MbankRetailBrexplpw from './banks/mbank-retail-brexplpw.js'; import NorwegianXxNorwnok1 from './banks/norwegian-xx-norwnok1.js'; +import SEBKortBankAB from './banks/seb-kort-bank-ab.js'; +import SEBPrivat from './banks/seb-privat.js'; import SandboxfinanceSfin0000 from './banks/sandboxfinance-sfin0000.js'; -import BnpBeGebabebb from './banks/bnp-be-gebabebb.js'; -import DanskeBankDabNO22 from './banks/danskebank-dabno22.js'; import SparNordSpNoDK22 from './banks/sparnord-spnodk22.js'; -import Belfius from './banks/belfius_gkccbebb.js'; import SpkMarburgBiedenkopfHeladef1mar from './banks/spk-marburg-biedenkopf-heladef1mar.js'; -import SEBPrivat from './banks/seb-privat.js'; -import SEBKortBankAB from './banks/seb-kort-bank-ab.js'; const banks = [ AmericanExpressAesudef1, + Belfius, + BnpBeGebabebb, + DanskeBankDabNO22, IngIngddeff, IngPlIngbplpw, MbankRetailBrexplpw, - SandboxfinanceSfin0000, NorwegianXxNorwnok1, - BnpBeGebabebb, - DanskeBankDabNO22, + SEBKortBankAB, + SEBPrivat, + SandboxfinanceSfin0000, SparNordSpNoDK22, - Belfius, SpkMarburgBiedenkopfHeladef1mar, - SEBPrivat, - SEBKortBankAB, ]; export default (institutionId) => diff --git a/src/app-gocardless/banks/american-express-aesudef1.js b/src/app-gocardless/banks/american-express-aesudef1.js index 2339c5180..23695fc29 100644 --- a/src/app-gocardless/banks/american-express-aesudef1.js +++ b/src/app-gocardless/banks/american-express-aesudef1.js @@ -4,6 +4,8 @@ import { amountToInteger, sortByBookingDateOrValueDate } from '../utils.js'; export default { institutionIds: ['AMERICAN_EXPRESS_AESUDEF1'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/bank.interface.ts b/src/app-gocardless/banks/bank.interface.ts index 777847f38..c59350d61 100644 --- a/src/app-gocardless/banks/bank.interface.ts +++ b/src/app-gocardless/banks/bank.interface.ts @@ -6,6 +6,9 @@ import { Transaction, Balance } from '../gocardless-node.types.js'; export interface IBank { institutionIds: string[]; + + accessValidForDays: number; + /** * Returns normalized object with required data for the frontend */ diff --git a/src/app-gocardless/banks/belfius_gkccbebb.js b/src/app-gocardless/banks/belfius_gkccbebb.js index 488f71327..9bbc8ac10 100644 --- a/src/app-gocardless/banks/belfius_gkccbebb.js +++ b/src/app-gocardless/banks/belfius_gkccbebb.js @@ -4,6 +4,8 @@ import Fallback from './integration-bank.js'; export default { institutionIds: ['BELFIUS_GKCCBEBB'], + accessValidForDays: 180, + normalizeAccount(account) { return Fallback.normalizeAccount(account); }, diff --git a/src/app-gocardless/banks/bnp-be-gebabebb.js b/src/app-gocardless/banks/bnp-be-gebabebb.js index e454d2b72..6e82458de 100644 --- a/src/app-gocardless/banks/bnp-be-gebabebb.js +++ b/src/app-gocardless/banks/bnp-be-gebabebb.js @@ -22,6 +22,8 @@ export default { 'BNP_BE_GEBABEBB', ], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/danskebank-dabno22.js b/src/app-gocardless/banks/danskebank-dabno22.js index 6ed98819c..98f7dc108 100644 --- a/src/app-gocardless/banks/danskebank-dabno22.js +++ b/src/app-gocardless/banks/danskebank-dabno22.js @@ -8,6 +8,8 @@ import { export default { institutionIds: ['DANSKEBANK_DABANO22'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/ing-ingddeff.js b/src/app-gocardless/banks/ing-ingddeff.js index c87b4c59b..ab7db91c8 100644 --- a/src/app-gocardless/banks/ing-ingddeff.js +++ b/src/app-gocardless/banks/ing-ingddeff.js @@ -4,6 +4,8 @@ import { printIban, amountToInteger } from '../utils.js'; export default { institutionIds: ['ING_INGDDEFF'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/ing-pl-ingbplpw.js b/src/app-gocardless/banks/ing-pl-ingbplpw.js index 7e30a868f..f08d889c4 100644 --- a/src/app-gocardless/banks/ing-pl-ingbplpw.js +++ b/src/app-gocardless/banks/ing-pl-ingbplpw.js @@ -4,6 +4,8 @@ import { printIban, amountToInteger } from '../utils.js'; export default { institutionIds: ['ING_PL_INGBPLPW'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/integration-bank.js b/src/app-gocardless/banks/integration-bank.js index 53743d00a..d1bbc077b 100644 --- a/src/app-gocardless/banks/integration-bank.js +++ b/src/app-gocardless/banks/integration-bank.js @@ -18,6 +18,14 @@ const SORTED_BALANCE_TYPE_LIST = [ /** @type {import('./bank.interface.js').IBank} */ export default { institutionIds: ['IntegrationBank'], + + // EEA need to allow at least 180 days now but this doesn't apply to UK + // banks, and it's possible that there are EEA banks which still don't follow + // the new requirements. See: + // - https://nordigen.zendesk.com/hc/en-gb/articles/13239212055581-EEA-180-day-access + // - https://nordigen.zendesk.com/hc/en-gb/articles/6760902653085-Extended-history-and-continuous-access-edge-cases + accessValidForDays: 90, + normalizeAccount(account) { console.log( 'Available account properties for new institution integration', diff --git a/src/app-gocardless/banks/mbank-retail-brexplpw.js b/src/app-gocardless/banks/mbank-retail-brexplpw.js index d388ddf2e..b53168016 100644 --- a/src/app-gocardless/banks/mbank-retail-brexplpw.js +++ b/src/app-gocardless/banks/mbank-retail-brexplpw.js @@ -4,6 +4,8 @@ import { printIban, amountToInteger } from '../utils.js'; export default { institutionIds: ['MBANK_RETAIL_BREXPLPW'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/norwegian-xx-norwnok1.js b/src/app-gocardless/banks/norwegian-xx-norwnok1.js index 45d45dbc4..4d3acdcdb 100644 --- a/src/app-gocardless/banks/norwegian-xx-norwnok1.js +++ b/src/app-gocardless/banks/norwegian-xx-norwnok1.js @@ -15,6 +15,8 @@ export default { 'NORWEGIAN_FI_NORWNOK1', ], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/sandboxfinance-sfin0000.js b/src/app-gocardless/banks/sandboxfinance-sfin0000.js index 5a0bf56bb..5106b882b 100644 --- a/src/app-gocardless/banks/sandboxfinance-sfin0000.js +++ b/src/app-gocardless/banks/sandboxfinance-sfin0000.js @@ -8,6 +8,8 @@ import { export default { institutionIds: ['SANDBOXFINANCE_SFIN0000'], + accessValidForDays: 90, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/seb-kort-bank-ab.js b/src/app-gocardless/banks/seb-kort-bank-ab.js index cc9efbed9..7eae5bc81 100644 --- a/src/app-gocardless/banks/seb-kort-bank-ab.js +++ b/src/app-gocardless/banks/seb-kort-bank-ab.js @@ -8,6 +8,8 @@ import { export default { institutionIds: ['SEB_KORT_AB_SE_SKHSFI21'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/seb-privat.js b/src/app-gocardless/banks/seb-privat.js index a7ac8cd59..fce6b0be3 100644 --- a/src/app-gocardless/banks/seb-privat.js +++ b/src/app-gocardless/banks/seb-privat.js @@ -8,12 +8,10 @@ import { /** @type {import('./bank.interface.js').IBank} */ export default { institutionIds: ['SEB_ESSESESS_PRIVATE'], - normalizeAccount(account) { - console.log( - 'Available account properties for new institution integration', - { account: JSON.stringify(account) }, - ); + accessValidForDays: 180, + + normalizeAccount(account) { return { account_id: account.id, institution: account.institution, @@ -48,10 +46,6 @@ export default { }, sortTransactions(transactions = []) { - console.log( - 'Available (first 10) transactions properties for new integration of institution in sortTransactions function', - { top10Transactions: JSON.stringify(transactions.slice(0, 10)) }, - ); return sortByBookingDateOrValueDate(transactions); }, diff --git a/src/app-gocardless/banks/sparnord-spnodk22.js b/src/app-gocardless/banks/sparnord-spnodk22.js index 5596ba88e..2f1b7a095 100644 --- a/src/app-gocardless/banks/sparnord-spnodk22.js +++ b/src/app-gocardless/banks/sparnord-spnodk22.js @@ -22,6 +22,8 @@ export default { 'ANDELSKASSEN_FALLESKASSEN_FAELDKK1', ], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/banks/spk-marburg-biedenkopf-heladef1mar.js b/src/app-gocardless/banks/spk-marburg-biedenkopf-heladef1mar.js index b582a59a2..70374131d 100644 --- a/src/app-gocardless/banks/spk-marburg-biedenkopf-heladef1mar.js +++ b/src/app-gocardless/banks/spk-marburg-biedenkopf-heladef1mar.js @@ -19,6 +19,8 @@ const SORTED_BALANCE_TYPE_LIST = [ export default { institutionIds: ['SPK_MARBURG_BIEDENKOPF_HELADEF1MAR'], + accessValidForDays: 180, + normalizeAccount(account) { return { account_id: account.id, diff --git a/src/app-gocardless/gocardless.types.ts b/src/app-gocardless/gocardless.types.ts index 4b491f6d6..373749d91 100644 --- a/src/app-gocardless/gocardless.types.ts +++ b/src/app-gocardless/gocardless.types.ts @@ -81,7 +81,6 @@ export type GetTransactionsResponse = { export type CreateRequisitionParams = { institutionId: string; - accessValidForDays: number; /** * Host of your frontend app - on this host you will be redirected after linking with bank diff --git a/src/app-gocardless/services/gocardless-service.js b/src/app-gocardless/services/gocardless-service.js index 7913022db..733d26b6d 100644 --- a/src/app-gocardless/services/gocardless-service.js +++ b/src/app-gocardless/services/gocardless-service.js @@ -257,15 +257,18 @@ export const goCardlessService = { * @throws {ServiceError} * @returns {Promise<{requisitionId, link}>} */ - createRequisition: async ({ institutionId, accessValidForDays, host }) => { + createRequisition: async ({ institutionId, host }) => { await goCardlessService.setToken(); + const institution = await goCardlessService.getInstitution(institutionId); + const bank = BankFactory(institutionId); + const response = await client.initSession({ redirectUrl: host + '/gocardless/link', institutionId, referenceId: uuid.v4(), - accessValidForDays, - maxHistoricalDays: 90, + accessValidForDays: bank.accessValidForDays, + maxHistoricalDays: institution.transaction_total_days, userLanguage: 'en', ssn: null, redirectImmediate: false, diff --git a/src/app-gocardless/services/tests/gocardless-service.spec.js b/src/app-gocardless/services/tests/gocardless-service.spec.js index 351031473..fb89c01cf 100644 --- a/src/app-gocardless/services/tests/gocardless-service.spec.js +++ b/src/app-gocardless/services/tests/gocardless-service.spec.js @@ -242,6 +242,7 @@ describe('goCardlessService', () => { it('calls goCardlessClient and delete requisition', async () => { setTokenSpy.mockResolvedValue(); + getInstitutionSpy.mockResolvedValue(mockInstitution); createRequisitionSpy.mockResolvedValue(mockCreateRequisition); @@ -255,6 +256,7 @@ describe('goCardlessService', () => { it('handle error if status_code present in the response', async () => { setTokenSpy.mockResolvedValue(); + getInstitutionSpy.mockResolvedValue(mockInstitution); createRequisitionSpy.mockResolvedValue(mockUnknownError); diff --git a/upcoming-release-notes/334.md b/upcoming-release-notes/334.md new file mode 100644 index 000000000..db46b50d7 --- /dev/null +++ b/upcoming-release-notes/334.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [kyrias] +--- + +Add support for setting the access validity time per GoCardless bank integration and get the max historical days from the API diff --git a/yarn.lock b/yarn.lock index 255913228..4bc048eba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1639,7 +1639,7 @@ __metadata: jest: "npm:^29.3.1" jws: "npm:^4.0.0" migrate: "npm:^2.0.1" - nordigen-node: "npm:^1.3.0" + nordigen-node: "npm:^1.4.0" prettier: "npm:^2.8.3" supertest: "npm:^6.3.1" typescript: "npm:^4.9.5" @@ -4856,13 +4856,13 @@ __metadata: languageName: node linkType: hard -"nordigen-node@npm:^1.3.0": - version: 1.3.0 - resolution: "nordigen-node@npm:1.3.0" +"nordigen-node@npm:^1.4.0": + version: 1.4.0 + resolution: "nordigen-node@npm:1.4.0" dependencies: axios: "npm:^1.2.1" dotenv: "npm:^10.0.0" - checksum: 033771af257ecf8e36a375b07e10246b08d23b647ef2db737b6efe52a1bcd68f04c88c2aff6790d4cbcd00da0148550247624142a6eea7444d370b2e65f08fc8 + checksum: a04ec90480e4e65b2169d909ac9ea3044f764d59283162420d287a6b229808754dc78c758637724d63c87aa77f2237bc47543f521b0b4057ed3980d6db137e1a languageName: node linkType: hard