@actual-app/sync-server 25.5.0 → 25.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/{app.js → build/app.js} +4 -5
  2. package/build/bin/actual-server.js +101 -0
  3. package/build/migrations/1694360000000-create-folders.js +21 -0
  4. package/{migrations → build/migrations}/1694360479680-create-account-db.js +2 -4
  5. package/{migrations → build/migrations}/1694362247011-create-secret-table.js +2 -4
  6. package/build/migrations/1702667624000-rename-nordigen-secrets.js +9 -0
  7. package/{migrations → build/migrations}/1718889148000-openid.js +4 -10
  8. package/{migrations → build/migrations}/1719409568000-multiuser.js +10 -26
  9. package/build/src/account-db.js +182 -0
  10. package/build/src/accounts/openid.js +287 -0
  11. package/build/src/accounts/password.js +98 -0
  12. package/build/src/app-account.js +125 -0
  13. package/build/src/app-admin.js +317 -0
  14. package/build/src/app-admin.test.js +303 -0
  15. package/build/src/app-gocardless/app-gocardless.js +193 -0
  16. package/build/src/app-gocardless/bank-factory.js +84 -0
  17. package/build/src/app-gocardless/banks/abanca_caglesmm.js +17 -0
  18. package/build/src/app-gocardless/banks/abnamro_abnanl2a.js +37 -0
  19. package/build/src/app-gocardless/banks/american_express_aesudef1.js +32 -0
  20. package/build/src/app-gocardless/banks/bancsabadell_bsabesbbb.js +22 -0
  21. package/build/src/app-gocardless/banks/bank.interface.js +1 -0
  22. package/build/src/app-gocardless/banks/bank_of_ireland_b365_bofiie2d.js +25 -0
  23. package/build/src/app-gocardless/banks/bankinter_bkbkesmm.js +18 -0
  24. package/build/src/app-gocardless/banks/belfius_gkccbebb.js +13 -0
  25. package/build/src/app-gocardless/banks/berliner_sparkasse_beladebexxx.js +48 -0
  26. package/build/src/app-gocardless/banks/bnp_be_gebabebb.js +64 -0
  27. package/build/src/app-gocardless/banks/boursobank_bousfrppxxx.js +73 -0
  28. package/build/src/app-gocardless/banks/cbc_cregbebb.js +27 -0
  29. package/build/src/app-gocardless/banks/commerzbank_cobadeff.js +43 -0
  30. package/build/src/app-gocardless/banks/danskebank_dabno22.js +26 -0
  31. package/build/src/app-gocardless/banks/direkt_heladef1822.js +13 -0
  32. package/build/src/app-gocardless/banks/easybank_bawaatww.js +42 -0
  33. package/build/src/app-gocardless/banks/entercard_swednokk.js +28 -0
  34. package/build/src/app-gocardless/banks/fortuneo_ftnofrp1xxx.js +34 -0
  35. package/build/src/app-gocardless/banks/hype_hyeeit22.js +63 -0
  36. package/build/src/app-gocardless/banks/ing_ingbrobu.js +56 -0
  37. package/build/src/app-gocardless/banks/ing_ingddeff.js +34 -0
  38. package/build/src/app-gocardless/banks/ing_pl_ingbplpw.js +29 -0
  39. package/build/src/app-gocardless/banks/integration-bank.js +78 -0
  40. package/build/src/app-gocardless/banks/isybank_itbbitmm.js +13 -0
  41. package/build/src/app-gocardless/banks/kbc_kredbebb.js +26 -0
  42. package/build/src/app-gocardless/banks/lhv-lhvbee22.js +24 -0
  43. package/build/src/app-gocardless/banks/mbank_retail_brexplpw.js +41 -0
  44. package/build/src/app-gocardless/banks/nationwide_naiagb21.js +32 -0
  45. package/build/src/app-gocardless/banks/nbg_ethngraaxxx.js +39 -0
  46. package/build/src/app-gocardless/banks/norwegian_xx_norwnok1.js +61 -0
  47. package/build/src/app-gocardless/banks/revolut_revolt21.js +20 -0
  48. package/build/src/app-gocardless/banks/sandboxfinance_sfin0000.js +21 -0
  49. package/build/src/app-gocardless/banks/seb_kort_bank_ab.js +63 -0
  50. package/build/src/app-gocardless/banks/seb_privat.js +19 -0
  51. package/build/src/app-gocardless/banks/sparnord_spnodk22.js +19 -0
  52. package/build/src/app-gocardless/banks/spk_karlsruhe_karsde66.js +48 -0
  53. package/build/src/app-gocardless/banks/spk_marburg_biedenkopf_heladef1mar.js +25 -0
  54. package/build/src/app-gocardless/banks/spk_worms_alzey_ried_malade51wor.js +14 -0
  55. package/build/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js +36 -0
  56. package/build/src/app-gocardless/banks/swedbank_habalv22.js +30 -0
  57. package/build/src/app-gocardless/banks/tests/abanca_caglesmm.spec.js +17 -0
  58. package/build/src/app-gocardless/banks/tests/abnamro_abnanl2a.spec.js +45 -0
  59. package/build/src/app-gocardless/banks/tests/bancsabadell_bsabesbbb.spec.js +41 -0
  60. package/build/src/app-gocardless/banks/tests/belfius_gkccbebb.spec.js +16 -0
  61. package/build/src/app-gocardless/banks/tests/boursobank_bousfrppxxx.spec.js +102 -0
  62. package/build/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js +24 -0
  63. package/build/src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js +105 -0
  64. package/build/src/app-gocardless/banks/tests/easybank_bawaatww.spec.js +36 -0
  65. package/build/src/app-gocardless/banks/tests/fortuneo_ftnofrp1xxx.spec.js +159 -0
  66. package/build/src/app-gocardless/banks/tests/ing_ingddeff.spec.js +267 -0
  67. package/build/src/app-gocardless/banks/tests/ing_pl_ingbplpw.spec.js +186 -0
  68. package/build/src/app-gocardless/banks/tests/integration_bank.spec.js +127 -0
  69. package/build/src/app-gocardless/banks/tests/kbc_kredbebb.spec.js +24 -0
  70. package/build/src/app-gocardless/banks/tests/lhv-lhvbee22.spec.js +50 -0
  71. package/build/src/app-gocardless/banks/tests/mbank_retail_brexplpw.spec.js +156 -0
  72. package/build/src/app-gocardless/banks/tests/nationwide_naiagb21.spec.js +64 -0
  73. package/build/src/app-gocardless/banks/tests/nbg_ethngraaxxx.spec.js +36 -0
  74. package/build/src/app-gocardless/banks/tests/revolut_revolt21.spec.js +30 -0
  75. package/build/src/app-gocardless/banks/tests/sandboxfinance_sfin0000.spec.js +112 -0
  76. package/build/src/app-gocardless/banks/tests/spk_marburg_biedenkopf_heladef1mar.spec.js +214 -0
  77. package/build/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js +60 -0
  78. package/build/src/app-gocardless/banks/tests/swedbank_habalv22.spec.js +45 -0
  79. package/build/src/app-gocardless/banks/tests/virgin_nrnbgb22.spec.js +36 -0
  80. package/{src → build/src}/app-gocardless/banks/util/escape-regexp.js +1 -1
  81. package/{src → build/src}/app-gocardless/banks/util/extract-payeeName-from-remittanceInfo.js +11 -16
  82. package/build/src/app-gocardless/banks/virgin_nrnbgb22.js +31 -0
  83. package/build/src/app-gocardless/errors.js +67 -0
  84. package/build/src/app-gocardless/gocardless-node.types.js +1 -0
  85. package/build/src/app-gocardless/gocardless.types.js +1 -0
  86. package/build/src/app-gocardless/services/gocardless-service.js +504 -0
  87. package/build/src/app-gocardless/services/tests/fixtures.js +165 -0
  88. package/build/src/app-gocardless/services/tests/gocardless-service.spec.js +387 -0
  89. package/build/src/app-gocardless/tests/bank-factory.spec.js +13 -0
  90. package/build/src/app-gocardless/tests/utils.spec.js +158 -0
  91. package/build/src/app-gocardless/util/handle-error.js +15 -0
  92. package/build/src/app-gocardless/utils.js +41 -0
  93. package/build/src/app-openid.js +83 -0
  94. package/build/src/app-pluggyai/app-pluggyai.js +164 -0
  95. package/build/src/app-pluggyai/pluggyai-service.js +97 -0
  96. package/build/src/app-secrets.js +48 -0
  97. package/build/src/app-simplefin/app-simplefin.js +335 -0
  98. package/build/src/app-sync/errors.js +12 -0
  99. package/build/src/app-sync/services/files-service.js +158 -0
  100. package/build/src/app-sync/tests/services/files-service.test.js +192 -0
  101. package/build/src/app-sync/validation.js +65 -0
  102. package/build/src/app-sync.js +302 -0
  103. package/build/src/app-sync.test.js +655 -0
  104. package/build/src/app.js +138 -0
  105. package/build/src/config-types.js +1 -0
  106. package/build/src/db.js +50 -0
  107. package/build/src/load-config.js +274 -0
  108. package/build/src/migrations.js +23 -0
  109. package/build/src/scripts/disable-openid.js +31 -0
  110. package/build/src/scripts/enable-openid.js +36 -0
  111. package/build/src/scripts/health-check.js +16 -0
  112. package/build/src/scripts/reset-password.js +40 -0
  113. package/build/src/scripts/run-migrations.js +6 -0
  114. package/build/src/secrets.test.js +68 -0
  115. package/build/src/services/secrets-service.js +79 -0
  116. package/build/src/services/user-service.js +201 -0
  117. package/build/src/sync-simple.js +68 -0
  118. package/{src → build/src}/util/hash.js +1 -2
  119. package/build/src/util/middlewares.js +49 -0
  120. package/{src → build/src}/util/paths.js +3 -6
  121. package/build/src/util/payee-name.js +37 -0
  122. package/build/src/util/prompt.js +70 -0
  123. package/build/src/util/title/index.js +43 -0
  124. package/build/src/util/title/lower-case.js +90 -0
  125. package/build/src/util/title/specials.js +21 -0
  126. package/build/src/util/validate-user.js +55 -0
  127. package/package.json +32 -36
  128. package/bin/actual-server.js +0 -117
  129. package/migrations/1694360000000-create-folders.js +0 -25
  130. package/migrations/1702667624000-rename-nordigen-secrets.js +0 -19
  131. package/src/account-db.js +0 -239
  132. package/src/accounts/openid.js +0 -368
  133. package/src/accounts/password.js +0 -149
  134. package/src/app-account.js +0 -155
  135. package/src/app-admin.js +0 -410
  136. package/src/app-admin.test.js +0 -381
  137. package/src/app-gocardless/app-gocardless.js +0 -274
  138. package/src/app-gocardless/bank-factory.js +0 -91
  139. package/src/app-gocardless/banks/abanca_caglesmm.js +0 -22
  140. package/src/app-gocardless/banks/abnamro_abnanl2a.js +0 -57
  141. package/src/app-gocardless/banks/american_express_aesudef1.js +0 -40
  142. package/src/app-gocardless/banks/bancsabadell_bsabesbbb.js +0 -31
  143. package/src/app-gocardless/banks/bank.interface.ts +0 -51
  144. package/src/app-gocardless/banks/bank_of_ireland_b365_bofiie2d.js +0 -39
  145. package/src/app-gocardless/banks/bankinter_bkbkesmm.js +0 -24
  146. package/src/app-gocardless/banks/belfius_gkccbebb.js +0 -17
  147. package/src/app-gocardless/banks/berliner_sparkasse_beladebexxx.js +0 -61
  148. package/src/app-gocardless/banks/bnp_be_gebabebb.js +0 -73
  149. package/src/app-gocardless/banks/cbc_cregbebb.js +0 -34
  150. package/src/app-gocardless/banks/commerzbank_cobadeff.js +0 -54
  151. package/src/app-gocardless/banks/danskebank_dabno22.js +0 -39
  152. package/src/app-gocardless/banks/direkt_heladef1822.js +0 -18
  153. package/src/app-gocardless/banks/easybank_bawaatww.js +0 -50
  154. package/src/app-gocardless/banks/entercard_swednokk.js +0 -40
  155. package/src/app-gocardless/banks/fortuneo_ftnofrp1xxx.js +0 -46
  156. package/src/app-gocardless/banks/hype_hyeeit22.js +0 -74
  157. package/src/app-gocardless/banks/ing_ingbrobu.js +0 -70
  158. package/src/app-gocardless/banks/ing_ingddeff.js +0 -47
  159. package/src/app-gocardless/banks/ing_pl_ingbplpw.js +0 -46
  160. package/src/app-gocardless/banks/integration-bank.js +0 -115
  161. package/src/app-gocardless/banks/isybank_itbbitmm.js +0 -18
  162. package/src/app-gocardless/banks/kbc_kredbebb.js +0 -33
  163. package/src/app-gocardless/banks/lhv-lhvbee22.js +0 -36
  164. package/src/app-gocardless/banks/mbank_retail_brexplpw.js +0 -56
  165. package/src/app-gocardless/banks/nationwide_naiagb21.js +0 -46
  166. package/src/app-gocardless/banks/nbg_ethngraaxxx.js +0 -51
  167. package/src/app-gocardless/banks/norwegian_xx_norwnok1.js +0 -74
  168. package/src/app-gocardless/banks/revolut_revolt21.js +0 -37
  169. package/src/app-gocardless/banks/sandboxfinance_sfin0000.js +0 -28
  170. package/src/app-gocardless/banks/seb_kort_bank_ab.js +0 -59
  171. package/src/app-gocardless/banks/seb_privat.js +0 -29
  172. package/src/app-gocardless/banks/sparnord_spnodk22.js +0 -24
  173. package/src/app-gocardless/banks/spk_karlsruhe_karsde66.js +0 -61
  174. package/src/app-gocardless/banks/spk_marburg_biedenkopf_heladef1mar.js +0 -30
  175. package/src/app-gocardless/banks/spk_worms_alzey_ried_malade51wor.js +0 -19
  176. package/src/app-gocardless/banks/ssk_dusseldorf_dussdeddxxx.js +0 -50
  177. package/src/app-gocardless/banks/swedbank_habalv22.js +0 -47
  178. package/src/app-gocardless/banks/tests/abanca_caglesmm.spec.js +0 -21
  179. package/src/app-gocardless/banks/tests/abnamro_abnanl2a.spec.js +0 -61
  180. package/src/app-gocardless/banks/tests/bancsabadell_bsabesbbb.spec.js +0 -53
  181. package/src/app-gocardless/banks/tests/belfius_gkccbebb.spec.js +0 -22
  182. package/src/app-gocardless/banks/tests/cbc_cregbebb.spec.js +0 -34
  183. package/src/app-gocardless/banks/tests/commerzbank_cobadeff.spec.js +0 -133
  184. package/src/app-gocardless/banks/tests/easybank_bawaatww.spec.js +0 -54
  185. package/src/app-gocardless/banks/tests/fortuneo_ftnofrp1xxx.spec.js +0 -206
  186. package/src/app-gocardless/banks/tests/ing_ingddeff.spec.js +0 -302
  187. package/src/app-gocardless/banks/tests/ing_pl_ingbplpw.spec.js +0 -202
  188. package/src/app-gocardless/banks/tests/integration_bank.spec.js +0 -156
  189. package/src/app-gocardless/banks/tests/kbc_kredbebb.spec.js +0 -38
  190. package/src/app-gocardless/banks/tests/lhv-lhvbee22.spec.js +0 -68
  191. package/src/app-gocardless/banks/tests/mbank_retail_brexplpw.spec.js +0 -171
  192. package/src/app-gocardless/banks/tests/nationwide_naiagb21.spec.js +0 -105
  193. package/src/app-gocardless/banks/tests/nbg_ethngraaxxx.spec.js +0 -48
  194. package/src/app-gocardless/banks/tests/revolut_revolt21.spec.js +0 -42
  195. package/src/app-gocardless/banks/tests/sandboxfinance_sfin0000.spec.js +0 -133
  196. package/src/app-gocardless/banks/tests/spk_marburg_biedenkopf_heladef1mar.spec.js +0 -255
  197. package/src/app-gocardless/banks/tests/ssk_dusseldorf_dussdeddxxx.spec.js +0 -100
  198. package/src/app-gocardless/banks/tests/swedbank_habalv22.spec.js +0 -57
  199. package/src/app-gocardless/banks/tests/virgin_nrnbgb22.spec.js +0 -54
  200. package/src/app-gocardless/banks/virgin_nrnbgb22.js +0 -39
  201. package/src/app-gocardless/errors.js +0 -84
  202. package/src/app-gocardless/gocardless-node.types.ts +0 -497
  203. package/src/app-gocardless/gocardless.types.ts +0 -93
  204. package/src/app-gocardless/link.html +0 -18
  205. package/src/app-gocardless/services/gocardless-service.js +0 -620
  206. package/src/app-gocardless/services/tests/fixtures.js +0 -181
  207. package/src/app-gocardless/services/tests/gocardless-service.spec.js +0 -537
  208. package/src/app-gocardless/tests/bank-factory.spec.js +0 -20
  209. package/src/app-gocardless/tests/utils.spec.js +0 -162
  210. package/src/app-gocardless/util/handle-error.js +0 -16
  211. package/src/app-gocardless/utils.js +0 -45
  212. package/src/app-openid.js +0 -108
  213. package/src/app-pluggyai/app-pluggyai.js +0 -215
  214. package/src/app-pluggyai/pluggyai-service.js +0 -120
  215. package/src/app-secrets.js +0 -61
  216. package/src/app-simplefin/app-simplefin.js +0 -405
  217. package/src/app-sync/errors.js +0 -13
  218. package/src/app-sync/services/files-service.js +0 -243
  219. package/src/app-sync/tests/services/files-service.test.js +0 -247
  220. package/src/app-sync/validation.js +0 -77
  221. package/src/app-sync.js +0 -391
  222. package/src/app-sync.test.js +0 -877
  223. package/src/app.js +0 -149
  224. package/src/config-types.ts +0 -44
  225. package/src/db.js +0 -58
  226. package/src/load-config.js +0 -307
  227. package/src/migrations.js +0 -36
  228. package/src/run-migrations.js +0 -8
  229. package/src/scripts/disable-openid.js +0 -44
  230. package/src/scripts/enable-openid.js +0 -53
  231. package/src/scripts/health-check.js +0 -23
  232. package/src/scripts/reset-password.js +0 -51
  233. package/src/secrets.test.js +0 -83
  234. package/src/services/secrets-service.js +0 -94
  235. package/src/services/user-service.js +0 -272
  236. package/src/sync-simple.js +0 -95
  237. package/src/util/middlewares.js +0 -62
  238. package/src/util/payee-name.js +0 -45
  239. package/src/util/prompt.js +0 -88
  240. package/src/util/title/index.js +0 -59
  241. package/src/util/title/lower-case.js +0 -93
  242. package/src/util/title/specials.js +0 -21
  243. package/src/util/validate-user.js +0 -68
  244. /package/{src → build/src}/sql/messages.sql +0 -0
@@ -0,0 +1,43 @@
1
+ import Fallback from './integration-bank.js';
2
+ import { escapeRegExp } from './util/escape-regexp.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['COMMERZBANK_COBADEFF'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ // remittanceInformationUnstructured is limited to 140 chars thus ...
10
+ // ... missing information form remittanceInformationUnstructuredArray ...
11
+ // ... so we recreate it.
12
+ editedTrans.remittanceInformationUnstructured =
13
+ transaction.remittanceInformationUnstructuredArray.join(' ');
14
+ // The limitations of remittanceInformationUnstructuredArray ...
15
+ // ... can result in split keywords. We fix these. Other ...
16
+ // ... splits will need to be fixed by user with rules.
17
+ const keywords = [
18
+ 'End-to-End-Ref.:',
19
+ 'Mandatsref:',
20
+ 'Gläubiger-ID:',
21
+ 'SEPA-BASISLASTSCHRIFT',
22
+ 'Kartenzahlung',
23
+ 'Dauerauftrag',
24
+ ];
25
+ keywords.forEach(keyword => {
26
+ editedTrans.remittanceInformationUnstructured =
27
+ editedTrans.remittanceInformationUnstructured.replace(
28
+ // There can be spaces in keywords
29
+ RegExp(keyword.split('').join('\\s*'), 'gi'), ', ' + keyword + ' ');
30
+ });
31
+ // Clean up remittanceInformation, deduplicate payee (removing slashes ...
32
+ // ... that are added to the remittanceInformation field), and ...
33
+ // ... remove clutter like "End-to-End-Ref.: NOTPROVIDED"
34
+ const payee = escapeRegExp(transaction.creditorName || transaction.debtorName || '');
35
+ editedTrans.remittanceInformationUnstructured =
36
+ editedTrans.remittanceInformationUnstructured
37
+ .replace(/\s*(,)?\s+/g, '$1 ')
38
+ .replace(RegExp(payee.split(' ').join('(/*| )'), 'gi'), ' ')
39
+ .replace(', End-to-End-Ref.: NOTPROVIDED', '')
40
+ .trim();
41
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
42
+ },
43
+ };
@@ -0,0 +1,26 @@
1
+ import { amountToInteger } from '../utils.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['DANSKEBANK_DABANO22'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ /**
10
+ * Danske Bank appends the EndToEndID: NOTPROVIDED to
11
+ * remittanceInformationUnstructured, cluttering the data.
12
+ *
13
+ * We clean thais up by removing any instances of this string from all transactions.
14
+ *
15
+ */
16
+ editedTrans.remittanceInformationUnstructured =
17
+ transaction.remittanceInformationUnstructured.replace('\nEndToEndID: NOTPROVIDED', '');
18
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
19
+ },
20
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
21
+ const currentBalance = balances.find(balance => balance.balanceType === 'interimAvailable');
22
+ return sortedTransactions.reduce((total, trans) => {
23
+ return total - amountToInteger(trans.transactionAmount.amount);
24
+ }, amountToInteger(currentBalance.balanceAmount.amount));
25
+ },
26
+ };
@@ -0,0 +1,13 @@
1
+ import Fallback from './integration-bank.js';
2
+ /** @type {import('./bank.interface.js').IBank} */
3
+ export default {
4
+ ...Fallback,
5
+ institutionIds: ['DIREKT_HELADEF1822'],
6
+ normalizeTransaction(transaction, booked) {
7
+ const editedTrans = { ...transaction };
8
+ editedTrans.remittanceInformationUnstructured =
9
+ transaction.remittanceInformationUnstructured ??
10
+ transaction.remittanceInformationStructured;
11
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
12
+ },
13
+ };
@@ -0,0 +1,42 @@
1
+ import * as d from 'date-fns';
2
+ import { formatPayeeName } from '../../util/payee-name.js';
3
+ import { title } from '../../util/title/index.js';
4
+ import Fallback from './integration-bank.js';
5
+ /** @type {import('./bank.interface.js').IBank} */
6
+ export default {
7
+ ...Fallback,
8
+ institutionIds: ['EASYBANK_BAWAATWW'],
9
+ // If date is same, sort by transactionId
10
+ sortTransactions: (transactions = []) => transactions.sort((a, b) => {
11
+ const diff = +new Date(b.valueDate || b.bookingDate) -
12
+ +new Date(a.valueDate || a.bookingDate);
13
+ if (diff !== 0)
14
+ return diff;
15
+ return parseInt(b.transactionId) - parseInt(a.transactionId);
16
+ }),
17
+ normalizeTransaction(transaction, booked) {
18
+ const editedTrans = { ...transaction };
19
+ let payeeName = formatPayeeName(transaction);
20
+ if (!payeeName)
21
+ payeeName = extractPayeeName(transaction);
22
+ editedTrans.payeeName = payeeName;
23
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
24
+ },
25
+ };
26
+ /**
27
+ * Extracts the payee name from the remittanceInformationStructured
28
+ * @param {import('../gocardless-node.types.js').Transaction} transaction
29
+ */
30
+ function extractPayeeName(transaction) {
31
+ const structured = transaction.remittanceInformationStructured;
32
+ // The payee name is betweeen the transaction timestamp (11.07. 11:36) and the location, that starts with \\
33
+ const regex = /\d{2}\.\d{2}\. \d{2}:\d{2}(.*)\\\\/;
34
+ const matches = structured.match(regex);
35
+ if (matches && matches.length > 1 && matches[1]) {
36
+ return title(matches[1]);
37
+ }
38
+ else {
39
+ // As a fallback if still no payee is found, the whole information is used
40
+ return structured;
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ import { amountToInteger } from '../utils.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['ENTERCARD_SWEDNOKK'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ // GoCardless's Entercard integration returns forex transactions with the
10
+ // foreign amount in `transactionAmount`, but at least the amount actually
11
+ // billed to the account is now available in
12
+ // `remittanceInformationUnstructured`.
13
+ const remittanceInformationUnstructured = transaction.remittanceInformationUnstructured;
14
+ if (remittanceInformationUnstructured.startsWith('billingAmount: ')) {
15
+ transaction.transactionAmount = {
16
+ amount: remittanceInformationUnstructured.substring(15),
17
+ currency: 'SEK',
18
+ };
19
+ }
20
+ editedTrans.date = transaction.valueDate;
21
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
22
+ },
23
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
24
+ return sortedTransactions.reduce((total, trans) => {
25
+ return total - amountToInteger(trans.transactionAmount.amount);
26
+ }, amountToInteger(balances[0]?.balanceAmount?.amount || 0));
27
+ },
28
+ };
@@ -0,0 +1,34 @@
1
+ import { formatPayeeName } from '../../util/payee-name.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['FORTUNEO_FTNOFRP1XXX'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ // Most of the information from the transaction is in the remittanceInformationUnstructuredArray field.
10
+ // We extract the creditor and debtor names from this field.
11
+ // The remittanceInformationUnstructuredArray field usually contain keywords like "Vir" for
12
+ // bank transfers or "Carte 03/06" for card payments, as well as the date.
13
+ // We remove these keywords to get a cleaner payee name.
14
+ const keywordsToRemove = [
15
+ 'VIR INST',
16
+ 'VIR',
17
+ 'PRLV',
18
+ 'ANN CARTE',
19
+ 'CARTE \\d{2}\\/\\d{2}',
20
+ ];
21
+ const details = transaction.remittanceInformationUnstructuredArray.join(' ');
22
+ const amount = transaction.transactionAmount.amount;
23
+ const regex = new RegExp(keywordsToRemove.join('|'), 'g');
24
+ const payeeName = details.replace(regex, '').trim();
25
+ // The amount is negative for outgoing transactions, positive for incoming transactions.
26
+ const isCreditorPayee = parseFloat(amount) < 0;
27
+ // The payee name is the creditor name for outgoing transactions and the debtor name for incoming transactions.
28
+ const creditorName = isCreditorPayee ? payeeName : null;
29
+ const debtorName = isCreditorPayee ? null : payeeName;
30
+ editedTrans.creditorName = creditorName;
31
+ editedTrans.debtorName = debtorName;
32
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
33
+ },
34
+ };
@@ -0,0 +1,63 @@
1
+ import Fallback from './integration-bank.js';
2
+ /** @type {import('./bank.interface.js').IBank} */
3
+ export default {
4
+ ...Fallback,
5
+ institutionIds: ['HYPE_HYEEIT22'],
6
+ normalizeTransaction(transaction, booked) {
7
+ const editedTrans = { ...transaction };
8
+ /** Online card payments - identified by "crd" transaction code
9
+ * always start with PAGAMENTO PRESSO + <payee name>
10
+ */
11
+ if (transaction.proprietaryBankTransactionCode === 'crd') {
12
+ // remove PAGAMENTO PRESSO and set payee name
13
+ editedTrans.debtorName =
14
+ transaction.remittanceInformationUnstructured?.slice('PAGAMENTO PRESSO '.length);
15
+ }
16
+ /**
17
+ * In-app money transfers (p2p) and bank transfers (bon) have remittance info structure like
18
+ * DENARO (INVIATO/RICEVUTO) (A/DA) {payee_name} - {payment_info} (p2p)
19
+ * HAI (INVIATO/RICEVUTO) UN BONIFICO (A/DA) {payee_name} - {payment_info} (bon)
20
+ */
21
+ if (transaction.proprietaryBankTransactionCode === 'p2p' ||
22
+ transaction.proprietaryBankTransactionCode === 'bon') {
23
+ // keep only {payment_info} portion of remittance info
24
+ // NOTE: if {payee_name} contains dashes (unlikely / impossible?), this probably gets bugged!
25
+ const infoIdx = transaction.remittanceInformationUnstructured.indexOf(' - ') + 3;
26
+ editedTrans.remittanceInformationUnstructured =
27
+ infoIdx === -1
28
+ ? transaction.remittanceInformationUnstructured
29
+ : transaction.remittanceInformationUnstructured.slice(infoIdx).trim();
30
+ }
31
+ /**
32
+ * CONVERT ESCAPED UNICODE TO CODEPOINTS
33
+ * p2p payments allow user to write arbitrary unicode strings as messages
34
+ * gocardless reports unicode codepoints as \Uxxxx
35
+ * so it groups them in 4bytes bundles
36
+ * the code below assumes this is always the case
37
+ */
38
+ if (transaction.proprietaryBankTransactionCode === 'p2p') {
39
+ let str = transaction.remittanceInformationUnstructured;
40
+ let idx = str.indexOf('\\U');
41
+ let start_idx = idx;
42
+ let codepoints = [];
43
+ while (idx !== -1) {
44
+ codepoints.push(parseInt(str.slice(idx + 2, idx + 6), 16));
45
+ const next_idx = str.indexOf('\\U', idx + 6);
46
+ if (next_idx === idx + 6) {
47
+ idx = next_idx;
48
+ continue;
49
+ }
50
+ str =
51
+ str.slice(0, start_idx) +
52
+ String.fromCodePoint(...codepoints) +
53
+ str.slice(idx + 6);
54
+ codepoints = [];
55
+ idx = str.indexOf('\\U'); // slight inefficiency?
56
+ start_idx = idx;
57
+ }
58
+ editedTrans.remittanceInformationUnstructured = str;
59
+ }
60
+ editedTrans.date = transaction.valueDate || transaction.bookingDate;
61
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
62
+ },
63
+ };
@@ -0,0 +1,56 @@
1
+ import Fallback from './integration-bank.js';
2
+ /** @type {import('./bank.interface.js').IBank} */
3
+ export default {
4
+ ...Fallback,
5
+ institutionIds: ['ING_INGBROBU'],
6
+ normalizeTransaction(transaction, booked) {
7
+ const editedTrans = { ...transaction };
8
+ //Merchant transactions all have the same transactionId of 'NOTPROVIDED'.
9
+ //For booked transactions, this can be set to the internalTransactionId
10
+ //For pending transactions, this needs to be removed for them to show up in Actual
11
+ //For deduplication to work better, payeeName needs to be standardized
12
+ //and converted from a pending transaction form ("payeeName":"Card no: xxxxxxxxxxxx1111"') to a booked transaction form ("payeeName":"Card no: Xxxx Xxxx Xxxx 1111")
13
+ if (transaction.transactionId === 'NOTPROVIDED') {
14
+ //Some corner case transactions only have the `proprietaryBankTransactionCode` field, this need to be copied to `remittanceInformationUnstructured`
15
+ if (transaction.proprietaryBankTransactionCode &&
16
+ !transaction.remittanceInformationUnstructured) {
17
+ editedTrans.remittanceInformationUnstructured =
18
+ transaction.proprietaryBankTransactionCode;
19
+ }
20
+ if (booked) {
21
+ transaction.transactionId = transaction.internalTransactionId;
22
+ if (transaction.remittanceInformationUnstructured &&
23
+ transaction.remittanceInformationUnstructured
24
+ .toLowerCase()
25
+ .includes('card no:')) {
26
+ editedTrans.creditorName =
27
+ transaction.remittanceInformationUnstructured.split(',')[0];
28
+ //Catch all case for other types of payees
29
+ }
30
+ else {
31
+ editedTrans.creditorName =
32
+ transaction.remittanceInformationUnstructured;
33
+ }
34
+ }
35
+ else {
36
+ transaction.transactionId = null;
37
+ if (transaction.remittanceInformationUnstructured &&
38
+ transaction.remittanceInformationUnstructured
39
+ .toLowerCase()
40
+ .includes('card no:')) {
41
+ editedTrans.creditorName =
42
+ transaction.remittanceInformationUnstructured.replace(/x{4}/g, 'Xxxx ');
43
+ //Catch all case for other types of payees
44
+ }
45
+ else {
46
+ editedTrans.creditorName =
47
+ transaction.remittanceInformationUnstructured;
48
+ }
49
+ //Remove remittanceInformationUnstructured from pending transactions, so the `notes` field remains empty (there is no merchant information)
50
+ //Once booked, the right `notes` (containing the merchant) will be populated
51
+ editedTrans.remittanceInformationUnstructured = null;
52
+ }
53
+ }
54
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
55
+ },
56
+ };
@@ -0,0 +1,34 @@
1
+ import { amountToInteger } from '../utils.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['ING_INGDDEFF'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ const remittanceInformationMatch = /remittanceinformation:(.*)$/.exec(transaction.remittanceInformationUnstructured);
10
+ editedTrans.remittanceInformationUnstructured = remittanceInformationMatch
11
+ ? remittanceInformationMatch[1]
12
+ : transaction.remittanceInformationUnstructured;
13
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
14
+ },
15
+ sortTransactions(transactions = []) {
16
+ return transactions.sort((a, b) => {
17
+ const diff = +new Date(b.valueDate || b.bookingDate) -
18
+ +new Date(a.valueDate || a.bookingDate);
19
+ if (diff)
20
+ return diff;
21
+ const idA = parseInt(a.transactionId);
22
+ const idB = parseInt(b.transactionId);
23
+ if (!isNaN(idA) && !isNaN(idB))
24
+ return idB - idA;
25
+ return 0;
26
+ });
27
+ },
28
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
29
+ const currentBalance = balances.find(balance => 'interimBooked' === balance.balanceType);
30
+ return sortedTransactions.reduce((total, trans) => {
31
+ return total - amountToInteger(trans.transactionAmount.amount);
32
+ }, amountToInteger(currentBalance.balanceAmount.amount));
33
+ },
34
+ };
@@ -0,0 +1,29 @@
1
+ import { amountToInteger } from '../utils.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['ING_PL_INGBPLPW'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ editedTrans.date = transaction.valueDate;
10
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
11
+ },
12
+ sortTransactions(transactions = []) {
13
+ return transactions.sort((a, b) => {
14
+ return (Number(b.transactionId.substr(2)) - Number(a.transactionId.substr(2)));
15
+ });
16
+ },
17
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
18
+ if (sortedTransactions.length) {
19
+ const oldestTransaction = sortedTransactions[sortedTransactions.length - 1];
20
+ const oldestKnownBalance = amountToInteger(oldestTransaction.balanceAfterTransaction.balanceAmount.amount);
21
+ const oldestTransactionAmount = amountToInteger(oldestTransaction.transactionAmount.amount);
22
+ return oldestKnownBalance - oldestTransactionAmount;
23
+ }
24
+ else {
25
+ return amountToInteger(balances.find(balance => 'interimBooked' === balance.balanceType)
26
+ .balanceAmount.amount);
27
+ }
28
+ },
29
+ };
@@ -0,0 +1,78 @@
1
+ import * as d from 'date-fns';
2
+ import { formatPayeeName } from '../../util/payee-name.js';
3
+ import { amountToInteger, printIban, sortByBookingDateOrValueDate, } from '../utils.js';
4
+ const SORTED_BALANCE_TYPE_LIST = [
5
+ 'closingBooked',
6
+ 'expected',
7
+ 'forwardAvailable',
8
+ 'interimAvailable',
9
+ 'interimBooked',
10
+ 'nonInvoiced',
11
+ 'openingBooked',
12
+ ];
13
+ /** @type {import('./bank.interface.js').IBank} */
14
+ export default {
15
+ institutionIds: ['IntegrationBank'],
16
+ normalizeAccount(account) {
17
+ console.debug('Available account properties for new institution integration', { account: JSON.stringify(account) });
18
+ return {
19
+ account_id: account.id,
20
+ institution: account.institution,
21
+ mask: (account?.iban || '0000').slice(-4),
22
+ iban: account?.iban || null,
23
+ name: [
24
+ account.name ?? account.displayName ?? account.product,
25
+ printIban(account),
26
+ account.currency,
27
+ ]
28
+ .filter(Boolean)
29
+ .join(' '),
30
+ official_name: account.product ?? `integration-${account.institution_id}`,
31
+ type: 'checking',
32
+ };
33
+ },
34
+ normalizeTransaction(transaction, _booked, editedTransaction = null) {
35
+ const trans = editedTransaction ?? transaction;
36
+ const date = trans.date ||
37
+ transaction.bookingDate ||
38
+ transaction.bookingDateTime ||
39
+ transaction.valueDate ||
40
+ transaction.valueDateTime;
41
+ // If we couldn't find a valid date field we filter out this transaction
42
+ // and hope that we will import it again once the bank has processed the
43
+ // transaction further.
44
+ if (!date) {
45
+ return null;
46
+ }
47
+ const notes = trans.notes ??
48
+ trans.remittanceInformationUnstructured ??
49
+ trans.remittanceInformationUnstructuredArray?.join(' ');
50
+ transaction.remittanceInformationUnstructuredArrayString =
51
+ transaction.remittanceInformationUnstructuredArray?.join(',');
52
+ transaction.remittanceInformationStructuredArrayString =
53
+ transaction.remittanceInformationStructuredArray?.join(',');
54
+ return {
55
+ ...transaction,
56
+ payeeName: trans.payeeName ?? formatPayeeName(trans),
57
+ date: d.format(d.parseISO(date), 'yyyy-MM-dd'),
58
+ notes,
59
+ };
60
+ },
61
+ sortTransactions(transactions = []) {
62
+ console.debug('Available (first 10) transactions properties for new integration of institution in sortTransactions function', { top10Transactions: JSON.stringify(transactions.slice(0, 10)) });
63
+ return sortByBookingDateOrValueDate(transactions);
64
+ },
65
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
66
+ console.debug('Available (first 10) transactions properties for new integration of institution in calculateStartingBalance function', {
67
+ balances: JSON.stringify(balances),
68
+ top10SortedTransactions: JSON.stringify(sortedTransactions.slice(0, 10)),
69
+ });
70
+ const currentBalance = balances
71
+ .filter(item => SORTED_BALANCE_TYPE_LIST.includes(item.balanceType))
72
+ .sort((a, b) => SORTED_BALANCE_TYPE_LIST.indexOf(a.balanceType) -
73
+ SORTED_BALANCE_TYPE_LIST.indexOf(b.balanceType))[0];
74
+ return sortedTransactions.reduce((total, trans) => {
75
+ return total - amountToInteger(trans.transactionAmount.amount);
76
+ }, amountToInteger(currentBalance?.balanceAmount?.amount || 0));
77
+ },
78
+ };
@@ -0,0 +1,13 @@
1
+ import Fallback from './integration-bank.js';
2
+ /** @type {import('./bank.interface.js').IBank} */
3
+ export default {
4
+ ...Fallback,
5
+ institutionIds: ['ISYBANK_ITBBITMM'],
6
+ // It has been reported that valueDate is more accurate than booking date
7
+ // when it is provided
8
+ normalizeTransaction(transaction, booked) {
9
+ const editedTrans = { ...transaction };
10
+ editedTrans.date = transaction.valueDate ?? transaction.bookingDate;
11
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
12
+ },
13
+ };
@@ -0,0 +1,26 @@
1
+ import Fallback from './integration-bank.js';
2
+ import { extractPayeeNameFromRemittanceInfo } from './util/extract-payeeName-from-remittanceInfo.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['KBC_KREDBEBB'],
7
+ /**
8
+ * For negative amounts, the only payee information we have is returned in
9
+ * remittanceInformationUnstructured.
10
+ */
11
+ normalizeTransaction(transaction, booked) {
12
+ const editedTrans = { ...transaction };
13
+ if (Number(transaction.transactionAmount.amount) > 0) {
14
+ editedTrans.payeeName =
15
+ transaction.debtorName ||
16
+ transaction.remittanceInformationUnstructured ||
17
+ 'undefined';
18
+ }
19
+ else {
20
+ editedTrans.payeeName =
21
+ transaction.creditorName ||
22
+ extractPayeeNameFromRemittanceInfo(transaction.remittanceInformationUnstructured, ['Betaling met', 'Domiciliëring', 'Overschrijving']);
23
+ }
24
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
25
+ },
26
+ };
@@ -0,0 +1,24 @@
1
+ import * as d from 'date-fns';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['LHV_LHVBEE22'],
7
+ normalizeTransaction(transaction, booked) {
8
+ const editedTrans = { ...transaction };
9
+ // extract bookingDate and creditorName for card transactions, e.g.
10
+ // (..1234) 2025-01-02 09:32 CrustumOU\Poordi 3\Tallinn\10156 ESTEST
11
+ // bookingDate: 2025-01-02
12
+ // creditorName: CrustumOU
13
+ const cardTxRegex = /^\(\.\.(\d{4})\) (\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}) (.+)$/g;
14
+ const cardTxMatch = cardTxRegex.exec(transaction?.remittanceInformationUnstructured);
15
+ if (cardTxMatch) {
16
+ const extractedDate = d.parse(cardTxMatch[2], 'yyyy-MM-dd', new Date());
17
+ editedTrans.payeeName = cardTxMatch[4].split('\\')[0].trim();
18
+ if (booked && d.isValid(extractedDate)) {
19
+ editedTrans.date = d.format(extractedDate, 'yyyy-MM-dd');
20
+ }
21
+ }
22
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
23
+ },
24
+ };
@@ -0,0 +1,41 @@
1
+ import { amountToInteger } from '../utils.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['MBANK_RETAIL_BREXPLPW'],
7
+ /**
8
+ * When requesting transaction details for MBANK_RETAIL_BREXPLPW
9
+ * using gocardless API, it seems that bookingDate and valueDate are swapped.
10
+ * valueDate will always come before bookingDate, so as a simple fix,
11
+ * I have overwritten integration-bank.normalizeTransaction() here,
12
+ * swapped dates back (by giving valueDate higher priority) and
13
+ * called parent method with edited transaction as argument
14
+ */
15
+ normalizeTransaction(transaction, booked) {
16
+ const editedTrans = { ...transaction };
17
+ const date = transaction.valueDate ||
18
+ transaction.valueDateTime ||
19
+ transaction.bookingDate ||
20
+ transaction.bookingDateTime;
21
+ editedTrans.date = date;
22
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
23
+ },
24
+ sortTransactions(transactions = []) {
25
+ return transactions.sort((a, b) => Number(b.transactionId) - Number(a.transactionId));
26
+ },
27
+ /**
28
+ * For MBANK_RETAIL_BREXPLPW we don't know what balance was
29
+ * after each transaction so we have to calculate it by getting
30
+ * current balance from the account and subtract all the transactions
31
+ *
32
+ * As a current balance we use `interimBooked` balance type because
33
+ * it includes transaction placed during current day
34
+ */
35
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
36
+ const currentBalance = balances.find(balance => 'interimBooked' === balance.balanceType);
37
+ return sortedTransactions.reduce((total, trans) => {
38
+ return total - amountToInteger(trans.transactionAmount.amount);
39
+ }, amountToInteger(currentBalance.balanceAmount.amount));
40
+ },
41
+ };
@@ -0,0 +1,32 @@
1
+ import Fallback from './integration-bank.js';
2
+ /** @type {import('./bank.interface.js').IBank} */
3
+ export default {
4
+ ...Fallback,
5
+ institutionIds: ['NATIONWIDE_NAIAGB21'],
6
+ normalizeTransaction(transaction, booked) {
7
+ const editedTrans = { ...transaction };
8
+ // Nationwide can sometimes return pending transactions with a date
9
+ // representing the latest a transaction could be booked. This stops
10
+ // actual's deduplication logic from working as it only checks 7 days
11
+ // ahead/behind and the transactionID from Nationwide changes when a
12
+ // transaction is booked
13
+ if (!booked) {
14
+ const useDate = new Date(Math.min(new Date(transaction.bookingDate).getTime(), new Date().getTime()));
15
+ editedTrans.date = useDate.toISOString().slice(0, 10);
16
+ }
17
+ // Nationwide also occasionally returns erroneous transaction_ids
18
+ // that are malformed and can even change after import. This will ignore
19
+ // these ids and unset them. When a correct ID is returned then it will
20
+ // update via the deduplication logic
21
+ const debitCreditRegex = /^00(DEB|CRED)IT.+$/;
22
+ const validLengths = [
23
+ 40, // Nationwide credit cards
24
+ 32, // Nationwide current accounts
25
+ ];
26
+ if (transaction.transactionId?.match(debitCreditRegex) ||
27
+ !validLengths.includes(transaction.transactionId?.length)) {
28
+ transaction.transactionId = null;
29
+ }
30
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
31
+ },
32
+ };
@@ -0,0 +1,39 @@
1
+ import { amountToInteger } from '../utils.js';
2
+ import Fallback from './integration-bank.js';
3
+ /** @type {import('./bank.interface.js').IBank} */
4
+ export default {
5
+ ...Fallback,
6
+ institutionIds: ['NBG_ETHNGRAAXXX'],
7
+ /**
8
+ * Fixes for the pending transactions:
9
+ * - Corrects amount to negative (nbg erroneously omits the minus sign in pending transactions)
10
+ * - Removes prefix 'ΑΓΟΡΑ' from remittance information to align with the booked transaction (necessary for fuzzy matching to work)
11
+ */
12
+ normalizeTransaction(transaction, booked) {
13
+ const editedTrans = { ...transaction };
14
+ if (!transaction.transactionId &&
15
+ transaction.remittanceInformationUnstructured.startsWith('ΑΓΟΡΑ ')) {
16
+ transaction.transactionAmount = {
17
+ amount: '-' + transaction.transactionAmount.amount,
18
+ currency: transaction.transactionAmount.currency,
19
+ };
20
+ editedTrans.remittanceInformationUnstructured =
21
+ transaction.remittanceInformationUnstructured.substring(6);
22
+ }
23
+ return Fallback.normalizeTransaction(transaction, booked, editedTrans);
24
+ },
25
+ /**
26
+ * For NBG_ETHNGRAAXXX we don't know what balance was
27
+ * after each transaction so we have to calculate it by getting
28
+ * current balance from the account and subtract all the transactions
29
+ *
30
+ * As a current balance we use `interimBooked` balance type because
31
+ * it includes transaction placed during current day
32
+ */
33
+ calculateStartingBalance(sortedTransactions = [], balances = []) {
34
+ const currentBalance = balances.find(balance => 'interimAvailable' === balance.balanceType);
35
+ return sortedTransactions.reduce((total, trans) => {
36
+ return total - amountToInteger(trans.transactionAmount.amount);
37
+ }, amountToInteger(currentBalance.balanceAmount.amount));
38
+ },
39
+ };