lib-fints 1.4.0 → 1.4.2

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 (273) hide show
  1. package/dist/camtParser.js +18 -9
  2. package/dist/client.js +51 -35
  3. package/dist/config.js +10 -6
  4. package/dist/dataElements/AlphaNumeric.js +1 -1
  5. package/dist/dataElements/DataElement.js +2 -1
  6. package/dist/dataElements/Digits.js +1 -1
  7. package/dist/dataElements/Float.js +1 -1
  8. package/dist/dataElements/Numeric.js +2 -2
  9. package/dist/dataElements/Text.js +1 -1
  10. package/dist/dataGroups/Account.js +1 -1
  11. package/dist/dataGroups/Balance.js +2 -2
  12. package/dist/dataGroups/BankIdentification.js +1 -1
  13. package/dist/dataGroups/DataGroup.js +13 -6
  14. package/dist/dataGroups/InternationalAccount.js +1 -1
  15. package/dist/dataGroups/Money.js +1 -1
  16. package/dist/dataGroups/RefMessage.js +1 -1
  17. package/dist/dataGroups/SepaAccount.js +2 -2
  18. package/dist/dataGroups/SepaAccountParameters.js +2 -2
  19. package/dist/dataGroups/TimeStamp.js +1 -1
  20. package/dist/decoder.js +12 -6
  21. package/dist/dialog.js +33 -19
  22. package/dist/encoder.js +16 -4
  23. package/dist/format.js +2 -2
  24. package/dist/httpClient.js +4 -2
  25. package/dist/index.js +10 -10
  26. package/dist/interactions/balanceInteraction.js +2 -5
  27. package/dist/interactions/creditcardStatementInteraction.js +11 -11
  28. package/dist/interactions/customerInteraction.js +1 -1
  29. package/dist/interactions/endDialogInteraction.js +4 -4
  30. package/dist/interactions/initDialogInteraction.js +23 -20
  31. package/dist/interactions/portfolioInteraction.js +3 -3
  32. package/dist/interactions/sepaAccountInteraction.js +3 -3
  33. package/dist/interactions/statementInteractionCAMT.js +4 -4
  34. package/dist/interactions/statementInteractionMT940.js +4 -4
  35. package/dist/interactions/tanMediaInteraction.js +4 -4
  36. package/dist/message.js +51 -18
  37. package/dist/mt535parser.js +3 -5
  38. package/dist/mt940parser.js +18 -17
  39. package/dist/parser.js +1 -1
  40. package/dist/segment.js +12 -7
  41. package/dist/segmentDefinition.js +5 -2
  42. package/dist/segmentHeader.js +1 -1
  43. package/dist/segments/DIKKU.js +3 -3
  44. package/dist/segments/DKKKU.js +2 -2
  45. package/dist/segments/HIBPA.js +2 -2
  46. package/dist/segments/HICAZ.js +1 -1
  47. package/dist/segments/HICAZS.js +3 -3
  48. package/dist/segments/HIKAZS.js +7 -3
  49. package/dist/segments/HIKIM.js +1 -1
  50. package/dist/segments/HIKOM.js +1 -1
  51. package/dist/segments/HIPINS.js +3 -3
  52. package/dist/segments/HIRMG.js +1 -1
  53. package/dist/segments/HIRMS.js +1 -1
  54. package/dist/segments/HISAL.js +3 -3
  55. package/dist/segments/HISPAS.js +3 -4
  56. package/dist/segments/HISYN.js +1 -1
  57. package/dist/segments/HITAB.js +3 -3
  58. package/dist/segments/HITAN.js +3 -3
  59. package/dist/segments/HITANS.js +3 -3
  60. package/dist/segments/HIUPA.js +2 -2
  61. package/dist/segments/HIUPD.js +8 -4
  62. package/dist/segments/HKCAZ.js +3 -3
  63. package/dist/segments/HKIDN.js +1 -1
  64. package/dist/segments/HKKAZ.js +3 -3
  65. package/dist/segments/HKSAL.js +3 -3
  66. package/dist/segments/HKSPA.js +1 -1
  67. package/dist/segments/HKTAB.js +1 -1
  68. package/dist/segments/HKTAN.js +3 -3
  69. package/dist/segments/HKVVB.js +1 -1
  70. package/dist/segments/HKWPD.js +1 -1
  71. package/dist/segments/HNHBK.js +1 -1
  72. package/dist/segments/HNSHA.js +1 -1
  73. package/dist/segments/HNSHK.js +14 -6
  74. package/dist/segments/HNVSK.js +10 -6
  75. package/dist/segments/registry.js +31 -31
  76. package/dist/tests/HIBPA.test.js +3 -3
  77. package/dist/tests/HICAZS.test.js +2 -2
  78. package/dist/tests/HIPINS.test.js +2 -2
  79. package/dist/tests/HIRMG.test.js +2 -2
  80. package/dist/tests/HITAB.test.js +5 -5
  81. package/dist/tests/HITANS.test.js +2 -2
  82. package/dist/tests/HIUPA.test.js +2 -2
  83. package/dist/tests/HIUPD.test.js +2 -2
  84. package/dist/tests/HIWPD.test.js +2 -2
  85. package/dist/tests/HKCAZ.test.js +3 -3
  86. package/dist/tests/HKIDN.test.js +2 -2
  87. package/dist/tests/HKSAL.test.js +3 -3
  88. package/dist/tests/HKTAN.test.js +4 -4
  89. package/dist/tests/HKWPD.test.js +2 -2
  90. package/dist/tests/HNSHK.test.js +2 -2
  91. package/dist/tests/HNVSK.test.js +2 -2
  92. package/dist/tests/camtParser.test.js +3 -3
  93. package/dist/tests/client.test.js +636 -22
  94. package/dist/tests/datatypes.test.js +1 -1
  95. package/dist/tests/dialog.test.js +21 -14
  96. package/dist/tests/message.test.js +4 -4
  97. package/dist/tests/mt535parser.test.js +1 -3
  98. package/dist/types/accountBalance.d.ts.map +1 -1
  99. package/dist/types/bankAccount.d.ts +2 -2
  100. package/dist/types/bankAccount.d.ts.map +1 -1
  101. package/dist/types/bankAnswer.d.ts.map +1 -1
  102. package/dist/types/bankTransaction.d.ts.map +1 -1
  103. package/dist/types/bankingInformation.d.ts +2 -2
  104. package/dist/types/bankingInformation.d.ts.map +1 -1
  105. package/dist/types/bpd.d.ts +3 -3
  106. package/dist/types/bpd.d.ts.map +1 -1
  107. package/dist/types/camtParser.d.ts +1 -1
  108. package/dist/types/camtParser.d.ts.map +1 -1
  109. package/dist/types/client.d.ts +5 -5
  110. package/dist/types/client.d.ts.map +1 -1
  111. package/dist/types/config.d.ts +4 -4
  112. package/dist/types/config.d.ts.map +1 -1
  113. package/dist/types/creditCardStatement.d.ts.map +1 -1
  114. package/dist/types/dataElements/AlphaNumeric.d.ts.map +1 -1
  115. package/dist/types/dataElements/Amount.d.ts.map +1 -1
  116. package/dist/types/dataElements/Binary.d.ts.map +1 -1
  117. package/dist/types/dataElements/Country.d.ts.map +1 -1
  118. package/dist/types/dataElements/Currency.d.ts.map +1 -1
  119. package/dist/types/dataElements/Dat.d.ts.map +1 -1
  120. package/dist/types/dataElements/DataElement.d.ts +3 -3
  121. package/dist/types/dataElements/DataElement.d.ts.map +1 -1
  122. package/dist/types/dataElements/Digits.d.ts.map +1 -1
  123. package/dist/types/dataElements/Float.d.ts.map +1 -1
  124. package/dist/types/dataElements/Identification.d.ts.map +1 -1
  125. package/dist/types/dataElements/Numeric.d.ts.map +1 -1
  126. package/dist/types/dataElements/Text.d.ts.map +1 -1
  127. package/dist/types/dataElements/Time.d.ts.map +1 -1
  128. package/dist/types/dataElements/YesNo.d.ts.map +1 -1
  129. package/dist/types/dataGroups/Account.d.ts.map +1 -1
  130. package/dist/types/dataGroups/Balance.d.ts +1 -1
  131. package/dist/types/dataGroups/Balance.d.ts.map +1 -1
  132. package/dist/types/dataGroups/BankIdentification.d.ts.map +1 -1
  133. package/dist/types/dataGroups/DataGroup.d.ts +3 -3
  134. package/dist/types/dataGroups/DataGroup.d.ts.map +1 -1
  135. package/dist/types/dataGroups/InternationalAccount.d.ts +1 -1
  136. package/dist/types/dataGroups/InternationalAccount.d.ts.map +1 -1
  137. package/dist/types/dataGroups/Money.d.ts.map +1 -1
  138. package/dist/types/dataGroups/RefMessage.d.ts.map +1 -1
  139. package/dist/types/dataGroups/SepaAccount.d.ts +1 -1
  140. package/dist/types/dataGroups/SepaAccount.d.ts.map +1 -1
  141. package/dist/types/dataGroups/TimeStamp.d.ts.map +1 -1
  142. package/dist/types/decoder.d.ts +2 -2
  143. package/dist/types/decoder.d.ts.map +1 -1
  144. package/dist/types/dialog.d.ts +2 -2
  145. package/dist/types/dialog.d.ts.map +1 -1
  146. package/dist/types/encoder.d.ts +2 -2
  147. package/dist/types/encoder.d.ts.map +1 -1
  148. package/dist/types/httpClient.d.ts +1 -1
  149. package/dist/types/httpClient.d.ts.map +1 -1
  150. package/dist/types/index.d.ts +12 -13
  151. package/dist/types/index.d.ts.map +1 -1
  152. package/dist/types/interactions/balanceInteraction.d.ts +5 -5
  153. package/dist/types/interactions/balanceInteraction.d.ts.map +1 -1
  154. package/dist/types/interactions/creditcardStatementInteraction.d.ts +6 -6
  155. package/dist/types/interactions/creditcardStatementInteraction.d.ts.map +1 -1
  156. package/dist/types/interactions/customerInteraction.d.ts +6 -6
  157. package/dist/types/interactions/customerInteraction.d.ts.map +1 -1
  158. package/dist/types/interactions/endDialogInteraction.d.ts +6 -6
  159. package/dist/types/interactions/endDialogInteraction.d.ts.map +1 -1
  160. package/dist/types/interactions/initDialogInteraction.d.ts +5 -5
  161. package/dist/types/interactions/initDialogInteraction.d.ts.map +1 -1
  162. package/dist/types/interactions/portfolioInteraction.d.ts +5 -5
  163. package/dist/types/interactions/portfolioInteraction.d.ts.map +1 -1
  164. package/dist/types/interactions/sepaAccountInteraction.d.ts +5 -5
  165. package/dist/types/interactions/sepaAccountInteraction.d.ts.map +1 -1
  166. package/dist/types/interactions/statementInteractionCAMT.d.ts +4 -4
  167. package/dist/types/interactions/statementInteractionCAMT.d.ts.map +1 -1
  168. package/dist/types/interactions/statementInteractionMT940.d.ts +4 -4
  169. package/dist/types/interactions/statementInteractionMT940.d.ts.map +1 -1
  170. package/dist/types/interactions/tanMediaInteraction.d.ts +4 -4
  171. package/dist/types/interactions/tanMediaInteraction.d.ts.map +1 -1
  172. package/dist/types/message.d.ts +3 -3
  173. package/dist/types/message.d.ts.map +1 -1
  174. package/dist/types/mt535parser.d.ts +0 -1
  175. package/dist/types/mt535parser.d.ts.map +1 -1
  176. package/dist/types/mt940parser.d.ts +1 -2
  177. package/dist/types/mt940parser.d.ts.map +1 -1
  178. package/dist/types/partedSegment.d.ts +1 -1
  179. package/dist/types/partedSegment.d.ts.map +1 -1
  180. package/dist/types/segment.d.ts +1 -1
  181. package/dist/types/segment.d.ts.map +1 -1
  182. package/dist/types/segmentDefinition.d.ts +2 -2
  183. package/dist/types/segmentDefinition.d.ts.map +1 -1
  184. package/dist/types/segmentHeader.d.ts.map +1 -1
  185. package/dist/types/segments/DIKKU.d.ts +4 -4
  186. package/dist/types/segments/DIKKU.d.ts.map +1 -1
  187. package/dist/types/segments/DKKKU.d.ts +3 -3
  188. package/dist/types/segments/DKKKU.d.ts.map +1 -1
  189. package/dist/types/segments/HIBPA.d.ts +5 -5
  190. package/dist/types/segments/HIBPA.d.ts.map +1 -1
  191. package/dist/types/segments/HICAZ.d.ts +2 -2
  192. package/dist/types/segments/HICAZ.d.ts.map +1 -1
  193. package/dist/types/segments/HICAZS.d.ts +1 -1
  194. package/dist/types/segments/HICAZS.d.ts.map +1 -1
  195. package/dist/types/segments/HIKAZ.d.ts +1 -1
  196. package/dist/types/segments/HIKAZ.d.ts.map +1 -1
  197. package/dist/types/segments/HIKAZS.d.ts +1 -1
  198. package/dist/types/segments/HIKAZS.d.ts.map +1 -1
  199. package/dist/types/segments/HIKIM.d.ts +2 -2
  200. package/dist/types/segments/HIKIM.d.ts.map +1 -1
  201. package/dist/types/segments/HIKOM.d.ts +3 -3
  202. package/dist/types/segments/HIKOM.d.ts.map +1 -1
  203. package/dist/types/segments/HIPINS.d.ts +1 -1
  204. package/dist/types/segments/HIPINS.d.ts.map +1 -1
  205. package/dist/types/segments/HIRMG.d.ts +1 -1
  206. package/dist/types/segments/HIRMG.d.ts.map +1 -1
  207. package/dist/types/segments/HIRMS.d.ts +2 -2
  208. package/dist/types/segments/HIRMS.d.ts.map +1 -1
  209. package/dist/types/segments/HISAL.d.ts +7 -7
  210. package/dist/types/segments/HISAL.d.ts.map +1 -1
  211. package/dist/types/segments/HISPA.d.ts +2 -2
  212. package/dist/types/segments/HISPA.d.ts.map +1 -1
  213. package/dist/types/segments/HISPAS.d.ts +2 -2
  214. package/dist/types/segments/HISPAS.d.ts.map +1 -1
  215. package/dist/types/segments/HISYN.d.ts +2 -2
  216. package/dist/types/segments/HISYN.d.ts.map +1 -1
  217. package/dist/types/segments/HITAB.d.ts +4 -4
  218. package/dist/types/segments/HITAB.d.ts.map +1 -1
  219. package/dist/types/segments/HITAN.d.ts +5 -5
  220. package/dist/types/segments/HITAN.d.ts.map +1 -1
  221. package/dist/types/segments/HITANS.d.ts +2 -2
  222. package/dist/types/segments/HITANS.d.ts.map +1 -1
  223. package/dist/types/segments/HIUPA.d.ts +3 -3
  224. package/dist/types/segments/HIUPA.d.ts.map +1 -1
  225. package/dist/types/segments/HIUPD.d.ts +6 -6
  226. package/dist/types/segments/HIUPD.d.ts.map +1 -1
  227. package/dist/types/segments/HIWPD.d.ts +1 -1
  228. package/dist/types/segments/HIWPD.d.ts.map +1 -1
  229. package/dist/types/segments/HKCAZ.d.ts +5 -5
  230. package/dist/types/segments/HKCAZ.d.ts.map +1 -1
  231. package/dist/types/segments/HKEND.d.ts +1 -1
  232. package/dist/types/segments/HKEND.d.ts.map +1 -1
  233. package/dist/types/segments/HKIDN.d.ts +3 -3
  234. package/dist/types/segments/HKIDN.d.ts.map +1 -1
  235. package/dist/types/segments/HKKAZ.d.ts +5 -5
  236. package/dist/types/segments/HKKAZ.d.ts.map +1 -1
  237. package/dist/types/segments/HKSAL.d.ts +6 -6
  238. package/dist/types/segments/HKSAL.d.ts.map +1 -1
  239. package/dist/types/segments/HKSPA.d.ts +3 -3
  240. package/dist/types/segments/HKSPA.d.ts.map +1 -1
  241. package/dist/types/segments/HKSYN.d.ts +2 -2
  242. package/dist/types/segments/HKSYN.d.ts.map +1 -1
  243. package/dist/types/segments/HKTAB.d.ts +3 -3
  244. package/dist/types/segments/HKTAB.d.ts.map +1 -1
  245. package/dist/types/segments/HKTAN.d.ts +6 -6
  246. package/dist/types/segments/HKTAN.d.ts.map +1 -1
  247. package/dist/types/segments/HKVVB.d.ts +3 -3
  248. package/dist/types/segments/HKVVB.d.ts.map +1 -1
  249. package/dist/types/segments/HKWPD.d.ts +2 -2
  250. package/dist/types/segments/HKWPD.d.ts.map +1 -1
  251. package/dist/types/segments/HNHBK.d.ts +3 -3
  252. package/dist/types/segments/HNHBK.d.ts.map +1 -1
  253. package/dist/types/segments/HNHBS.d.ts +1 -1
  254. package/dist/types/segments/HNHBS.d.ts.map +1 -1
  255. package/dist/types/segments/HNSHA.d.ts +3 -3
  256. package/dist/types/segments/HNSHA.d.ts.map +1 -1
  257. package/dist/types/segments/HNSHK.d.ts +4 -4
  258. package/dist/types/segments/HNSHK.d.ts.map +1 -1
  259. package/dist/types/segments/HNVSD.d.ts +2 -2
  260. package/dist/types/segments/HNVSD.d.ts.map +1 -1
  261. package/dist/types/segments/HNVSK.d.ts +4 -4
  262. package/dist/types/segments/HNVSK.d.ts.map +1 -1
  263. package/dist/types/segments/businessTransactionParameter.d.ts +2 -2
  264. package/dist/types/segments/businessTransactionParameter.d.ts.map +1 -1
  265. package/dist/types/segments/registry.d.ts +1 -1
  266. package/dist/types/segments/registry.d.ts.map +1 -1
  267. package/dist/types/tanMethod.d.ts +1 -1
  268. package/dist/types/tanMethod.d.ts.map +1 -1
  269. package/dist/types/unknownSegment.d.ts +1 -1
  270. package/dist/types/unknownSegment.d.ts.map +1 -1
  271. package/dist/types/upd.d.ts +2 -2
  272. package/dist/types/upd.d.ts.map +1 -1
  273. package/package.json +48 -47
@@ -1,8 +1,101 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { AccountType } from '../bankAccount.js';
2
3
  import { FinTSClient } from '../client.js';
3
- import { Dialog } from '../dialog.js';
4
+ import { Language } from '../codes.js';
4
5
  import { FinTSConfig } from '../config.js';
6
+ import { Dialog } from '../dialog.js';
5
7
  describe('FinTSClient', () => {
8
+ const client = new FinTSClient(FinTSConfig.fromBankingInformation('product', '1.0', {
9
+ systemId: 'SYSTEM01',
10
+ bpd: {
11
+ version: 1,
12
+ url: 'https://bank.example.com/fints',
13
+ countryCode: 280,
14
+ bankId: '10020030',
15
+ bankName: 'Example Bank',
16
+ allowedTransactions: [
17
+ { transId: 'HKSAL', versions: [6, 7], tanRequired: false },
18
+ { transId: 'HKCAZ', versions: [1], tanRequired: false },
19
+ { transId: 'HKKAZ', versions: [6], tanRequired: true },
20
+ { transId: 'HKWPD', versions: [7], tanRequired: true },
21
+ { transId: 'DKKKU', versions: [2], tanRequired: false },
22
+ ],
23
+ maxTransactionsPerMessage: 1,
24
+ supportedLanguages: [Language.German],
25
+ supportedHbciVersions: [300],
26
+ supportedTanMethods: [
27
+ {
28
+ id: 1,
29
+ name: 'ChipTAN',
30
+ version: 1,
31
+ isDecoupled: false,
32
+ activeTanMediaCount: 1,
33
+ activeTanMedia: ['TAN-Generator 123'],
34
+ tanMediaRequirement: 0,
35
+ },
36
+ {
37
+ id: 2,
38
+ name: 'pushTAN',
39
+ version: 1,
40
+ isDecoupled: true,
41
+ activeTanMediaCount: 1,
42
+ activeTanMedia: ['Mobile App'],
43
+ tanMediaRequirement: 1,
44
+ },
45
+ ],
46
+ availableTanMethodIds: [1, 2],
47
+ },
48
+ upd: {
49
+ version: 1,
50
+ usage: 0,
51
+ bankAccounts: [
52
+ {
53
+ accountNumber: '1234567890',
54
+ bank: {
55
+ bankId: '10020030',
56
+ country: 280,
57
+ },
58
+ iban: 'DE89370400440532013000',
59
+ customerId: 'customer1',
60
+ accountType: AccountType.CheckingAccount,
61
+ currency: 'EUR',
62
+ holder1: 'Test User',
63
+ allowedTransactions: [
64
+ { transId: 'HKSAL', numSignatures: 1 },
65
+ { transId: 'HKCAZ', numSignatures: 1 },
66
+ { transId: 'HKKAZ', numSignatures: 1 },
67
+ ],
68
+ },
69
+ {
70
+ accountNumber: '9876543210',
71
+ bank: {
72
+ bankId: '10020030',
73
+ country: 280,
74
+ },
75
+ iban: 'DE89370400440532013001',
76
+ customerId: 'customer1',
77
+ accountType: AccountType.SecuritiesAccount,
78
+ currency: 'EUR',
79
+ holder1: 'Test User',
80
+ allowedTransactions: [{ transId: 'HKWPD', numSignatures: 1 }],
81
+ },
82
+ {
83
+ accountNumber: '1111222233',
84
+ bank: {
85
+ bankId: '10020030',
86
+ country: 280,
87
+ },
88
+ iban: 'DE89370400440532013002',
89
+ customerId: 'customer1',
90
+ accountType: AccountType.CreditCardAccount,
91
+ currency: 'EUR',
92
+ holder1: 'Test User',
93
+ allowedTransactions: [{ transId: 'DKKKU', numSignatures: 1 }],
94
+ },
95
+ ],
96
+ },
97
+ bankMessages: [],
98
+ }));
6
99
  let dialogStartMock;
7
100
  let dialogContinueMock;
8
101
  beforeEach(() => {
@@ -13,26 +106,547 @@ describe('FinTSClient', () => {
13
106
  dialogStartMock.mockRestore();
14
107
  dialogContinueMock.mockRestore();
15
108
  });
16
- it('sends a message', async () => {
17
- const client = new FinTSClient(FinTSConfig.forFirstTimeUse('product', '1.0', 'http://localhost', '12030000', 'user'));
18
- dialogStartMock.mockResolvedValueOnce(new Map([
19
- [
20
- 'HKIDN',
21
- {
22
- dialogId: 'DIALOG1',
23
- success: true,
24
- requiresTan: false,
25
- bankingInformationUpdated: true,
26
- bankingInformation: { systemId: 'SYSTEM01', bankMessages: [] },
27
- bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
28
- },
29
- ],
30
- ]));
31
- const response = await client.synchronize();
32
- expect(response.success).toBe(true);
33
- expect(response.requiresTan).toBe(false);
34
- expect(response.bankingInformation).toBeDefined();
35
- expect(dialogStartMock).toHaveBeenCalledOnce();
36
- expect(dialogContinueMock).toHaveBeenCalledTimes(0);
109
+ describe('getAccountBalance', () => {
110
+ it('returns balance response when no TAN is required', async () => {
111
+ dialogStartMock.mockResolvedValueOnce(new Map([
112
+ [
113
+ 'HKIDN',
114
+ {
115
+ dialogId: 'DIALOG1',
116
+ success: true,
117
+ requiresTan: false,
118
+ bankingInformationUpdated: false,
119
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
120
+ },
121
+ ],
122
+ [
123
+ 'HKSAL',
124
+ {
125
+ dialogId: 'DIALOG1',
126
+ success: true,
127
+ requiresTan: false,
128
+ bankingInformationUpdated: false,
129
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
130
+ balance: { date: new Date('2025-12-23'), currency: 'EUR', balance: 1000.0 },
131
+ },
132
+ ],
133
+ [
134
+ 'HKEND',
135
+ {
136
+ dialogId: 'DIALOG1',
137
+ success: true,
138
+ requiresTan: false,
139
+ bankingInformationUpdated: false,
140
+ bankAnswers: [{ code: 100, text: 'Dialog beendet' }],
141
+ },
142
+ ],
143
+ ]));
144
+ const response = (await client.getAccountBalance('1234567890'));
145
+ expect(response.success).toBe(true);
146
+ expect(response.requiresTan).toBe(false);
147
+ expect(response.balance).toBeDefined();
148
+ expect(dialogStartMock).toHaveBeenCalledOnce();
149
+ expect(dialogContinueMock).toHaveBeenCalledTimes(0);
150
+ });
151
+ it('returns init dialog response when TAN is required', async () => {
152
+ dialogStartMock.mockResolvedValueOnce(new Map([
153
+ [
154
+ 'HKIDN',
155
+ {
156
+ dialogId: 'DIALOG1',
157
+ success: true,
158
+ requiresTan: true,
159
+ tanReference: 'TANREF123',
160
+ tanChallenge: 'Bitte geben Sie Ihre TAN ein.',
161
+ bankingInformationUpdated: false,
162
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
163
+ },
164
+ ],
165
+ ]));
166
+ const response = (await client.getAccountBalance('1234567890'));
167
+ expect(response.success).toBe(true);
168
+ expect(response.requiresTan).toBe(true);
169
+ expect(response.tanReference).toBe('TANREF123');
170
+ expect(dialogStartMock).toHaveBeenCalledOnce();
171
+ expect(dialogContinueMock).toHaveBeenCalledTimes(0);
172
+ });
173
+ });
174
+ describe('getAccountBalanceWithTan', () => {
175
+ it('returns balance response when TAN is provided', async () => {
176
+ dialogContinueMock.mockResolvedValueOnce(new Map([
177
+ [
178
+ 'HKSAL',
179
+ {
180
+ dialogId: 'DIALOG1',
181
+ success: true,
182
+ requiresTan: false,
183
+ bankingInformationUpdated: false,
184
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
185
+ balance: { date: new Date('2025-12-23'), currency: 'EUR', balance: 2500.0 },
186
+ },
187
+ ],
188
+ [
189
+ 'HKEND',
190
+ {
191
+ dialogId: 'DIALOG1',
192
+ success: true,
193
+ requiresTan: false,
194
+ bankingInformationUpdated: false,
195
+ bankAnswers: [{ code: 100, text: 'Dialog beendet' }],
196
+ },
197
+ ],
198
+ ]));
199
+ const response = (await client.getAccountBalanceWithTan('TANREF123', '123456'));
200
+ expect(response.success).toBe(true);
201
+ expect(response.requiresTan).toBe(false);
202
+ expect(response.balance).toBeDefined();
203
+ expect(response.balance?.balance).toBe(2500.0);
204
+ expect(dialogContinueMock).toHaveBeenCalledWith('TANREF123', '123456');
205
+ });
206
+ });
207
+ describe('synchronize', () => {
208
+ it('returns synchronization response when no TAN is required', async () => {
209
+ dialogStartMock.mockResolvedValueOnce(new Map([
210
+ [
211
+ 'HKIDN',
212
+ {
213
+ dialogId: 'DIALOG1',
214
+ success: true,
215
+ requiresTan: false,
216
+ bankingInformationUpdated: true,
217
+ bankAnswers: [{ code: 20, text: 'Synchronisierung erfolgreich' }],
218
+ },
219
+ ],
220
+ [
221
+ 'HKEND',
222
+ {
223
+ dialogId: 'DIALOG1',
224
+ success: true,
225
+ requiresTan: false,
226
+ bankingInformationUpdated: false,
227
+ bankAnswers: [{ code: 100, text: 'Dialog beendet' }],
228
+ },
229
+ ],
230
+ ]));
231
+ const response = await client.synchronize();
232
+ expect(response.success).toBe(true);
233
+ expect(response.requiresTan).toBe(false);
234
+ expect(response.bankingInformationUpdated).toBe(true);
235
+ expect(dialogStartMock).toHaveBeenCalledOnce();
236
+ });
237
+ it('returns sync response requiring TAN', async () => {
238
+ dialogStartMock.mockResolvedValueOnce(new Map([
239
+ [
240
+ 'HKIDN',
241
+ {
242
+ dialogId: 'DIALOG1',
243
+ success: true,
244
+ requiresTan: true,
245
+ tanReference: 'SYNCTAN123',
246
+ tanChallenge: 'TAN für Synchronisation eingeben.',
247
+ bankingInformationUpdated: false,
248
+ bankAnswers: [{ code: 3955, text: 'TAN erforderlich' }],
249
+ },
250
+ ],
251
+ ]));
252
+ const response = await client.synchronize();
253
+ expect(response.success).toBe(true);
254
+ expect(response.requiresTan).toBe(true);
255
+ expect(response.tanReference).toBe('SYNCTAN123');
256
+ expect(response.tanChallenge).toBe('TAN für Synchronisation eingeben.');
257
+ });
258
+ });
259
+ describe('synchronizeWithTan', () => {
260
+ it('completes synchronization with TAN', async () => {
261
+ dialogContinueMock.mockResolvedValueOnce(new Map([
262
+ [
263
+ 'HKIDN',
264
+ {
265
+ dialogId: 'DIALOG1',
266
+ success: true,
267
+ requiresTan: false,
268
+ bankingInformationUpdated: true,
269
+ bankAnswers: [{ code: 20, text: 'Synchronisierung erfolgreich' }],
270
+ },
271
+ ],
272
+ [
273
+ 'HKEND',
274
+ {
275
+ dialogId: 'DIALOG1',
276
+ success: true,
277
+ requiresTan: false,
278
+ bankingInformationUpdated: false,
279
+ bankAnswers: [{ code: 100, text: 'Dialog beendet' }],
280
+ },
281
+ ],
282
+ ]));
283
+ const response = await client.synchronizeWithTan('SYNCTAN123', '789012');
284
+ expect(response.success).toBe(true);
285
+ expect(response.requiresTan).toBe(false);
286
+ expect(response.bankingInformationUpdated).toBe(true);
287
+ expect(dialogContinueMock).toHaveBeenCalledWith('SYNCTAN123', '789012');
288
+ });
289
+ });
290
+ describe('getAccountStatements', () => {
291
+ it('fetches statements using CAMT format when available and preferred', async () => {
292
+ dialogStartMock.mockResolvedValueOnce(new Map([
293
+ [
294
+ 'HKIDN',
295
+ {
296
+ dialogId: 'DIALOG1',
297
+ success: true,
298
+ requiresTan: false,
299
+ bankingInformationUpdated: false,
300
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
301
+ },
302
+ ],
303
+ [
304
+ 'HKCAZ',
305
+ {
306
+ dialogId: 'DIALOG1',
307
+ success: true,
308
+ requiresTan: false,
309
+ bankingInformationUpdated: false,
310
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
311
+ statements: [
312
+ {
313
+ account: '1234567890',
314
+ transactions: [],
315
+ openingBalance: { date: new Date('2025-12-01'), currency: 'EUR', value: 500.0 },
316
+ closingBalance: { date: new Date('2025-12-23'), currency: 'EUR', value: 1500.0 },
317
+ },
318
+ ],
319
+ },
320
+ ],
321
+ [
322
+ 'HKEND',
323
+ {
324
+ dialogId: 'DIALOG1',
325
+ success: true,
326
+ requiresTan: false,
327
+ bankingInformationUpdated: false,
328
+ bankAnswers: [{ code: 100, text: 'Dialog beendet' }],
329
+ },
330
+ ],
331
+ ]));
332
+ const response = (await client.getAccountStatements('1234567890'));
333
+ expect(response.success).toBe(true);
334
+ expect(response.statements).toBeDefined();
335
+ expect(response.statements?.length).toBe(1);
336
+ expect(response.statements?.[0].account).toBe('1234567890');
337
+ });
338
+ it('throws error when account does not support statements', async () => {
339
+ await expect(client.getAccountStatements('9999999999')).rejects.toThrow('Account 9999999999 not found in UPD');
340
+ });
341
+ it('uses MT940 when preferCamt is false', async () => {
342
+ dialogStartMock.mockResolvedValueOnce(new Map([
343
+ [
344
+ 'HKIDN',
345
+ {
346
+ dialogId: 'DIALOG1',
347
+ success: true,
348
+ requiresTan: false,
349
+ bankingInformationUpdated: false,
350
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
351
+ },
352
+ ],
353
+ [
354
+ 'HKKAZ',
355
+ {
356
+ dialogId: 'DIALOG1',
357
+ success: true,
358
+ requiresTan: false,
359
+ bankingInformationUpdated: false,
360
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
361
+ statements: [
362
+ {
363
+ account: '1234567890',
364
+ transactions: [],
365
+ openingBalance: { date: new Date('2025-12-01'), currency: 'EUR', value: 500.0 },
366
+ closingBalance: { date: new Date('2025-12-23'), currency: 'EUR', value: 1500.0 },
367
+ },
368
+ ],
369
+ },
370
+ ],
371
+ [
372
+ 'HKEND',
373
+ {
374
+ dialogId: 'DIALOG1',
375
+ success: true,
376
+ requiresTan: false,
377
+ bankingInformationUpdated: false,
378
+ bankAnswers: [{ code: 100, text: 'Dialog beendet' }],
379
+ },
380
+ ],
381
+ ]));
382
+ const response = (await client.getAccountStatements('1234567890', undefined, undefined, false));
383
+ expect(response.success).toBe(true);
384
+ expect(response.statements).toBeDefined();
385
+ expect(response.statements?.length).toBe(1);
386
+ expect(response.statements?.[0].account).toBe('1234567890');
387
+ });
388
+ });
389
+ describe('getAccountStatementsWithTan', () => {
390
+ it('continues statement fetching with TAN', async () => {
391
+ dialogContinueMock.mockResolvedValueOnce(new Map([
392
+ [
393
+ 'HKCAZ',
394
+ {
395
+ dialogId: 'DIALOG1',
396
+ success: true,
397
+ requiresTan: false,
398
+ bankingInformationUpdated: false,
399
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
400
+ statements: [
401
+ {
402
+ account: '1234567890',
403
+ transactions: [],
404
+ openingBalance: { date: new Date('2025-12-01'), currency: 'EUR', value: 500.0 },
405
+ closingBalance: { date: new Date('2025-12-23'), currency: 'EUR', value: 1500.0 },
406
+ },
407
+ ],
408
+ },
409
+ ],
410
+ ]));
411
+ const response = (await client.getAccountStatementsWithTan('STATEMENTTAN123', '456789'));
412
+ expect(response.success).toBe(true);
413
+ expect(response.statements).toBeDefined();
414
+ expect(dialogContinueMock).toHaveBeenCalledWith('STATEMENTTAN123', '456789');
415
+ });
416
+ });
417
+ describe('getPortfolio', () => {
418
+ it('fetches portfolio information', async () => {
419
+ dialogStartMock.mockResolvedValueOnce(new Map([
420
+ [
421
+ 'HKIDN',
422
+ {
423
+ dialogId: 'DIALOG1',
424
+ success: true,
425
+ requiresTan: false,
426
+ bankingInformationUpdated: false,
427
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
428
+ },
429
+ ],
430
+ [
431
+ 'HKWPD',
432
+ {
433
+ dialogId: 'DIALOG1',
434
+ success: true,
435
+ requiresTan: false,
436
+ bankingInformationUpdated: false,
437
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
438
+ portfolioStatement: {
439
+ currency: 'EUR',
440
+ holdings: [
441
+ {
442
+ isin: 'DE0001234567',
443
+ price: 25.5,
444
+ currency: 'EUR',
445
+ },
446
+ ],
447
+ totalValue: 2550.0,
448
+ },
449
+ },
450
+ ],
451
+ ]));
452
+ const response = (await client.getPortfolio('9876543210'));
453
+ expect(response.success).toBe(true);
454
+ expect(response.portfolioStatement?.holdings).toBeDefined();
455
+ expect(response.portfolioStatement?.holdings.length).toBe(1);
456
+ expect(response.portfolioStatement?.totalValue).toBe(2550.0);
457
+ });
458
+ it('fetches portfolio with optional parameters', async () => {
459
+ dialogStartMock.mockResolvedValueOnce(new Map([
460
+ [
461
+ 'HKIDN',
462
+ {
463
+ dialogId: 'DIALOG1',
464
+ success: true,
465
+ requiresTan: false,
466
+ bankingInformationUpdated: false,
467
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
468
+ },
469
+ ],
470
+ [
471
+ 'HKWPD',
472
+ {
473
+ dialogId: 'DIALOG1',
474
+ success: true,
475
+ requiresTan: false,
476
+ bankingInformationUpdated: false,
477
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
478
+ portfolioStatement: {
479
+ currency: 'EUR',
480
+ holdings: [
481
+ {
482
+ isin: 'DE0001234567',
483
+ price: 25.5,
484
+ },
485
+ ],
486
+ totalValue: 1000.0,
487
+ },
488
+ },
489
+ ],
490
+ ]));
491
+ const response = (await client.getPortfolio('9876543210', 'EUR', '1', 10));
492
+ expect(response.success).toBe(true);
493
+ expect(response.portfolioStatement?.holdings).toBeDefined();
494
+ expect(response.portfolioStatement?.holdings.length).toBe(1);
495
+ expect(response.portfolioStatement?.holdings[0].isin).toBe('DE0001234567');
496
+ });
497
+ });
498
+ describe('getPortfolioWithTan', () => {
499
+ it('continues portfolio fetching with TAN', async () => {
500
+ dialogContinueMock.mockResolvedValueOnce(new Map([
501
+ [
502
+ 'HKWPD',
503
+ {
504
+ dialogId: 'DIALOG1',
505
+ success: true,
506
+ requiresTan: false,
507
+ bankingInformationUpdated: false,
508
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
509
+ portfolioStatement: {
510
+ currency: 'EUR',
511
+ holdings: [],
512
+ },
513
+ },
514
+ ],
515
+ ]));
516
+ const response = (await client.getPortfolioWithTan('PORTFOLIOTAN123', '987654'));
517
+ expect(response.success).toBe(true);
518
+ expect(response.portfolioStatement).toBeDefined();
519
+ expect(dialogContinueMock).toHaveBeenCalledWith('PORTFOLIOTAN123', '987654');
520
+ });
521
+ });
522
+ describe('getCreditCardStatements', () => {
523
+ it('fetches credit card statements', async () => {
524
+ dialogStartMock.mockResolvedValueOnce(new Map([
525
+ [
526
+ 'HKIDN',
527
+ {
528
+ dialogId: 'DIALOG1',
529
+ success: true,
530
+ requiresTan: false,
531
+ bankingInformationUpdated: false,
532
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
533
+ },
534
+ ],
535
+ [
536
+ 'DKKKU',
537
+ {
538
+ dialogId: 'DIALOG1',
539
+ success: true,
540
+ requiresTan: false,
541
+ bankingInformationUpdated: false,
542
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
543
+ statements: [
544
+ {
545
+ openingBalance: { date: new Date('2025-12-01'), currency: 'EUR', value: 0.0 },
546
+ closingBalance: { date: new Date('2025-12-23'), currency: 'EUR', value: -150.0 },
547
+ transactions: [],
548
+ },
549
+ ],
550
+ },
551
+ ],
552
+ ]));
553
+ const response = (await client.getCreditCardStatements('1111222233'));
554
+ expect(response.success).toBe(true);
555
+ expect(response.statements).toBeDefined();
556
+ expect(response.statements?.length).toBe(1);
557
+ expect(response.statements?.[0].closingBalance?.value).toBe(-150.0);
558
+ });
559
+ });
560
+ describe('getCreditCardStatementsWithTan', () => {
561
+ it('continues credit card statement fetching with TAN', async () => {
562
+ dialogContinueMock.mockResolvedValueOnce(new Map([
563
+ [
564
+ 'DKKKU',
565
+ {
566
+ dialogId: 'DIALOG1',
567
+ success: true,
568
+ requiresTan: false,
569
+ bankingInformationUpdated: false,
570
+ bankAnswers: [{ code: 20, text: 'Auftrag ausgeführt' }],
571
+ statements: [],
572
+ },
573
+ ],
574
+ ]));
575
+ const response = (await client.getCreditCardStatementsWithTan('CCTAN123', '111222'));
576
+ expect(response.success).toBe(true);
577
+ expect(response.statements).toBeDefined();
578
+ expect(dialogContinueMock).toHaveBeenCalledWith('CCTAN123', '111222');
579
+ });
580
+ });
581
+ describe('capability checks', () => {
582
+ describe('canGetAccountBalance', () => {
583
+ it('returns true for general capability when bank supports it', () => {
584
+ expect(client.canGetAccountBalance()).toBe(true);
585
+ });
586
+ it('returns true for specific account that supports balance checking', () => {
587
+ expect(client.canGetAccountBalance('1234567890')).toBe(true);
588
+ });
589
+ it('returns false for account that does not support balance checking', () => {
590
+ expect(client.canGetAccountBalance('9876543210')).toBe(false);
591
+ });
592
+ });
593
+ describe('canGetAccountStatements', () => {
594
+ it('returns true for general capability when bank supports it', () => {
595
+ expect(client.canGetAccountStatements()).toBe(true);
596
+ });
597
+ it('returns true for account that supports statements', () => {
598
+ expect(client.canGetAccountStatements('1234567890')).toBe(true);
599
+ });
600
+ it('returns false for account that does not support statements', () => {
601
+ expect(client.canGetAccountStatements('1111222233')).toBe(false);
602
+ });
603
+ });
604
+ describe('canGetPortfolio', () => {
605
+ it('returns true for general capability when bank supports it', () => {
606
+ expect(client.canGetPortfolio()).toBe(true);
607
+ });
608
+ it('returns true for depot account', () => {
609
+ expect(client.canGetPortfolio('9876543210')).toBe(true);
610
+ });
611
+ it('returns false for non-depot account', () => {
612
+ expect(client.canGetPortfolio('1234567890')).toBe(false);
613
+ });
614
+ });
615
+ describe('canGetCreditCardStatements', () => {
616
+ it('returns true for general capability when bank supports it', () => {
617
+ expect(client.canGetCreditCardStatements()).toBe(true);
618
+ });
619
+ it('returns true for credit card account', () => {
620
+ expect(client.canGetCreditCardStatements('1111222233')).toBe(true);
621
+ });
622
+ it('returns false for non-credit card account', () => {
623
+ expect(client.canGetCreditCardStatements('1234567890')).toBe(false);
624
+ });
625
+ });
626
+ });
627
+ describe('TAN method and media selection', () => {
628
+ describe('selectTanMethod', () => {
629
+ it('selects TAN method by ID and returns the method', () => {
630
+ const tanMethod = client.selectTanMethod(2);
631
+ expect(tanMethod).toBeDefined();
632
+ expect(tanMethod.id).toBe(2);
633
+ expect(tanMethod.name).toBe('pushTAN');
634
+ expect(client.config.selectedTanMethod).toBe(tanMethod);
635
+ });
636
+ it('throws error for invalid TAN method ID', () => {
637
+ expect(() => client.selectTanMethod(999)).toThrow();
638
+ });
639
+ });
640
+ describe('selectTanMedia', () => {
641
+ it('selects TAN media by name', () => {
642
+ // First select a TAN method that has TAN media
643
+ client.selectTanMethod(1);
644
+ expect(() => client.selectTanMedia('TAN-Generator 123')).not.toThrow();
645
+ });
646
+ it('throws error for invalid TAN media name', () => {
647
+ client.selectTanMethod(1);
648
+ expect(() => client.selectTanMedia('Invalid Media')).toThrow();
649
+ });
650
+ });
37
651
  });
38
652
  });
@@ -1,4 +1,4 @@
1
- import { describe, it, expect } from 'vitest';
1
+ import { describe, expect, it } from 'vitest';
2
2
  import { BankIdentification } from '../dataGroups/BankIdentification.js';
3
3
  describe('BankIdentification', () => {
4
4
  it('encodes correctly', () => {