@actual-app/api 25.3.0 → 25.4.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 (101) hide show
  1. package/@types/loot-core/client/accounts/accountsSlice.d.ts +175 -0
  2. package/@types/loot-core/client/app/appSlice.d.ts +175 -0
  3. package/@types/loot-core/client/budgets/budgetsSlice.d.ts +401 -0
  4. package/@types/loot-core/client/modals/modalsSlice.d.ts +486 -0
  5. package/@types/loot-core/client/notifications/notificationsSlice.d.ts +47 -0
  6. package/@types/loot-core/client/platform.d.ts +1 -0
  7. package/@types/loot-core/client/prefs/prefsSlice.d.ts +186 -0
  8. package/@types/loot-core/client/queries/queriesSlice.d.ts +692 -0
  9. package/@types/loot-core/client/redux.d.ts +18546 -0
  10. package/@types/loot-core/client/store/index.d.ts +133 -0
  11. package/@types/loot-core/client/users/usersSlice.d.ts +89 -0
  12. package/@types/loot-core/platform/client/fetch/index.d.ts +1 -10
  13. package/@types/loot-core/platform/client/undo/index.d.ts +19 -31
  14. package/@types/loot-core/platform/exceptions/index.d.ts +2 -5
  15. package/@types/loot-core/platform/server/connection/index.d.ts +0 -3
  16. package/@types/loot-core/platform/server/fetch/index.d.ts +1 -4
  17. package/@types/loot-core/platform/server/log/index.d.ts +4 -6
  18. package/@types/loot-core/server/accounts/app.d.ts +19 -5
  19. package/@types/loot-core/server/accounts/link.d.ts +6 -1
  20. package/@types/loot-core/server/admin/app.d.ts +54 -1
  21. package/@types/loot-core/server/api-models.d.ts +22 -22
  22. package/@types/loot-core/server/aql/exec.d.ts +1 -1
  23. package/@types/loot-core/server/aql/schema/index.d.ts +9 -0
  24. package/@types/loot-core/server/budget/actions.d.ts +6 -5
  25. package/@types/loot-core/server/budget/app.d.ts +103 -2
  26. package/@types/loot-core/server/budget/cleanup-template.d.ts +1 -1
  27. package/@types/loot-core/server/budget/goaltemplates.d.ts +1 -1
  28. package/@types/loot-core/server/budget/statements.d.ts +2 -2
  29. package/@types/loot-core/server/budget/template-notes.d.ts +1 -1
  30. package/@types/loot-core/server/budget/types/templates.d.ts +2 -1
  31. package/@types/loot-core/server/cloud-storage.d.ts +1 -1
  32. package/@types/loot-core/server/dashboard/app.d.ts +35 -1
  33. package/@types/loot-core/server/db/index.d.ts +38 -31
  34. package/@types/loot-core/server/db/sort.d.ts +1 -1
  35. package/@types/loot-core/server/encryption-internals.d.ts +5 -5
  36. package/@types/loot-core/server/encryption-internals.web.d.ts +2 -2
  37. package/@types/loot-core/server/encryption.d.ts +3 -3
  38. package/@types/loot-core/server/filters/app.d.ts +10 -1
  39. package/@types/loot-core/server/main-app.d.ts +1 -1
  40. package/@types/loot-core/server/models.d.ts +24 -23
  41. package/@types/loot-core/server/notes/app.d.ts +6 -1
  42. package/@types/loot-core/server/payees/app.d.ts +48 -0
  43. package/@types/loot-core/server/preferences/app.d.ts +1 -10
  44. package/@types/loot-core/server/reports/app.d.ts +9 -1
  45. package/@types/loot-core/server/rules/app.d.ts +50 -1
  46. package/@types/loot-core/server/schedules/app.d.ts +25 -2
  47. package/@types/loot-core/server/schedules/find-schedules.d.ts +1 -1
  48. package/@types/loot-core/server/server-config.d.ts +1 -0
  49. package/@types/loot-core/server/sheet.d.ts +1 -1
  50. package/@types/loot-core/server/spreadsheet/app.d.ts +38 -0
  51. package/@types/loot-core/server/spreadsheet/graph-data-structure.d.ts +4 -4
  52. package/@types/loot-core/server/spreadsheet/spreadsheet.d.ts +3 -2
  53. package/@types/loot-core/server/sync/app.d.ts +38 -0
  54. package/@types/loot-core/server/sync/make-test-message.d.ts +1 -1
  55. package/@types/loot-core/server/tools/app.d.ts +13 -1
  56. package/@types/loot-core/server/transactions/transaction-rules.d.ts +5 -4
  57. package/@types/loot-core/server/undo.d.ts +1 -1
  58. package/@types/loot-core/shared/async.d.ts +4 -3
  59. package/@types/loot-core/shared/locale.d.ts +1 -0
  60. package/@types/loot-core/shared/months.d.ts +2 -2
  61. package/@types/loot-core/shared/schedules.d.ts +5 -3
  62. package/@types/loot-core/shared/util.d.ts +4 -1
  63. package/@types/loot-core/types/handlers.d.ts +16 -10
  64. package/@types/loot-core/types/models/account.d.ts +2 -1
  65. package/@types/loot-core/types/models/bank-sync.d.ts +1 -1
  66. package/@types/loot-core/types/models/index.d.ts +5 -1
  67. package/@types/loot-core/types/models/openid.d.ts +2 -1
  68. package/@types/loot-core/types/models/payee.d.ts +2 -2
  69. package/@types/loot-core/types/models/pluggyai.d.ts +18 -0
  70. package/@types/loot-core/types/models/user-access.d.ts +10 -0
  71. package/@types/loot-core/types/models/user.d.ts +17 -18
  72. package/@types/loot-core/types/prefs.d.ts +13 -1
  73. package/@types/loot-core/types/server-handlers.d.ts +0 -99
  74. package/@types/loot-core/types/util.d.ts +7 -0
  75. package/dist/app/bundle.api.js +93477 -49658
  76. package/dist/index.js +17 -7
  77. package/dist/jest.config.js +0 -2
  78. package/dist/methods.js +17 -7
  79. package/dist/migrations/1740506588539_add_last_reconciled_at.sql +5 -0
  80. package/dist/package.json +8 -8
  81. package/dist/validateNodeVersion.js +17 -7
  82. package/package.json +8 -8
  83. package/@types/loot-core/client/constants.d.ts +0 -21
  84. package/@types/loot-core/client/state-types/budgets.d.ts +0 -36
  85. package/@types/loot-core/client/state-types/index.d.ts +0 -27
  86. package/@types/loot-core/client/state-types/modals.d.ts +0 -392
  87. package/@types/loot-core/client/state-types/notifications.d.ts +0 -57
  88. package/@types/loot-core/client/state-types/prefs.d.ts +0 -40
  89. package/@types/loot-core/client/state-types/user.d.ts +0 -13
  90. package/@types/loot-core/server/admin/types/handlers.d.ts +0 -43
  91. package/@types/loot-core/server/budget/types/handlers.d.ts +0 -91
  92. package/@types/loot-core/server/dashboard/types/handlers.d.ts +0 -24
  93. package/@types/loot-core/server/filters/types/handlers.d.ts +0 -7
  94. package/@types/loot-core/server/notes/types/handlers.d.ts +0 -3
  95. package/@types/loot-core/server/reports/types/handlers.d.ts +0 -6
  96. package/@types/loot-core/server/rules/types/handlers.d.ts +0 -40
  97. package/@types/loot-core/server/schedules/types/handlers.d.ts +0 -31
  98. package/@types/loot-core/server/tools/types/handlers.d.ts +0 -11
  99. package/@types/loot-core/types/models/userAccess.d.ts +0 -9
  100. package/dist/methods.test.js +0 -541
  101. /package/@types/{methods.test.d.ts → loot-core/server/api.test.d.ts} +0 -0
@@ -1,541 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- // @ts-strict-ignore
27
- const fs = __importStar(require("fs/promises"));
28
- const path = __importStar(require("path"));
29
- const api = __importStar(require("./index"));
30
- const budgetName = 'test-budget';
31
- beforeEach(async () => {
32
- // we need real datetime if we are going to mix new timestamps with our mock data
33
- global.restoreDateNow();
34
- const budgetPath = path.join(__dirname, '/mocks/budgets/', budgetName);
35
- await fs.rm(budgetPath, { force: true, recursive: true });
36
- await createTestBudget('default-budget-template', budgetName);
37
- await api.init({
38
- dataDir: path.join(__dirname, '/mocks/budgets/'),
39
- });
40
- });
41
- afterEach(async () => {
42
- global.currentMonth = null;
43
- await api.shutdown();
44
- });
45
- async function createTestBudget(templateName, name) {
46
- const templatePath = path.join(__dirname, '/../loot-core/src/mocks/files', templateName);
47
- const budgetPath = path.join(__dirname, '/mocks/budgets/', name);
48
- await fs.mkdir(budgetPath);
49
- await fs.copyFile(path.join(templatePath, 'metadata.json'), path.join(budgetPath, 'metadata.json'));
50
- await fs.copyFile(path.join(templatePath, 'db.sqlite'), path.join(budgetPath, 'db.sqlite'));
51
- }
52
- describe('API setup and teardown', () => {
53
- // apis: loadBudget, getBudgetMonths
54
- test('successfully loads budget', async () => {
55
- await expect(api.loadBudget(budgetName)).resolves.toBeUndefined();
56
- await expect(api.getBudgetMonths()).resolves.toMatchSnapshot();
57
- });
58
- });
59
- describe('API CRUD operations', () => {
60
- beforeEach(async () => {
61
- // load test budget
62
- await api.loadBudget(budgetName);
63
- });
64
- // api: getBudgets
65
- test('getBudgets', async () => {
66
- const budgets = await api.getBudgets();
67
- expect(budgets).toEqual(expect.arrayContaining([
68
- expect.objectContaining({
69
- id: 'test-budget',
70
- name: 'Default Test Db',
71
- }),
72
- ]));
73
- });
74
- // apis: getCategoryGroups, createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
75
- test('CategoryGroups: successfully update category groups', async () => {
76
- const month = '2023-10';
77
- global.currentMonth = month;
78
- // get existing category groups
79
- const groups = await api.getCategoryGroups();
80
- expect(groups).toEqual(expect.arrayContaining([
81
- expect.objectContaining({
82
- hidden: false,
83
- id: 'fc3825fd-b982-4b72-b768-5b30844cf832',
84
- is_income: false,
85
- name: 'Usual Expenses',
86
- }),
87
- expect.objectContaining({
88
- hidden: false,
89
- id: 'a137772f-cf2f-4089-9432-822d2ddc1466',
90
- is_income: false,
91
- name: 'Investments and Savings',
92
- }),
93
- expect.objectContaining({
94
- hidden: false,
95
- id: '2E1F5BDB-209B-43F9-AF2C-3CE28E380C00',
96
- is_income: true,
97
- name: 'Income',
98
- }),
99
- ]));
100
- // create our test category group
101
- const mainGroupId = await api.createCategoryGroup({
102
- name: 'test-group',
103
- });
104
- let budgetMonth = await api.getBudgetMonth(month);
105
- expect(budgetMonth.categoryGroups).toEqual(expect.arrayContaining([
106
- expect.objectContaining({
107
- id: mainGroupId,
108
- }),
109
- ]));
110
- // update group
111
- await api.updateCategoryGroup(mainGroupId, {
112
- name: 'update-tests',
113
- });
114
- budgetMonth = await api.getBudgetMonth(month);
115
- expect(budgetMonth.categoryGroups).toEqual(expect.arrayContaining([
116
- expect.objectContaining({
117
- id: mainGroupId,
118
- }),
119
- ]));
120
- // delete group
121
- await api.deleteCategoryGroup(mainGroupId);
122
- budgetMonth = await api.getBudgetMonth(month);
123
- expect(budgetMonth.categoryGroups).toEqual(expect.arrayContaining([
124
- expect.not.objectContaining({
125
- id: mainGroupId,
126
- }),
127
- ]));
128
- });
129
- // apis: createCategory, getCategories, updateCategory, deleteCategory
130
- test('Categories: successfully update categories', async () => {
131
- const month = '2023-10';
132
- global.currentMonth = month;
133
- // create our test category group
134
- const mainGroupId = await api.createCategoryGroup({
135
- name: 'test-group',
136
- });
137
- const secondaryGroupId = await api.createCategoryGroup({
138
- name: 'test-secondary-group',
139
- });
140
- const categoryId = await api.createCategory({
141
- name: 'test-budget',
142
- group_id: mainGroupId,
143
- });
144
- const categoryIdHidden = await api.createCategory({
145
- name: 'test-budget-hidden',
146
- group_id: mainGroupId,
147
- hidden: true,
148
- });
149
- let categories = await api.getCategories();
150
- expect(categories).toEqual(expect.arrayContaining([
151
- expect.objectContaining({
152
- id: categoryId,
153
- name: 'test-budget',
154
- hidden: false,
155
- group_id: mainGroupId,
156
- }),
157
- expect.objectContaining({
158
- id: categoryIdHidden,
159
- name: 'test-budget-hidden',
160
- hidden: true,
161
- group_id: mainGroupId,
162
- }),
163
- ]));
164
- // update/move category
165
- await api.updateCategory(categoryId, {
166
- name: 'updated-budget',
167
- group_id: secondaryGroupId,
168
- });
169
- await api.updateCategory(categoryIdHidden, {
170
- name: 'updated-budget-hidden',
171
- group_id: secondaryGroupId,
172
- hidden: false,
173
- });
174
- categories = await api.getCategories();
175
- expect(categories).toEqual(expect.arrayContaining([
176
- expect.objectContaining({
177
- id: categoryId,
178
- name: 'updated-budget',
179
- hidden: false,
180
- group_id: secondaryGroupId,
181
- }),
182
- expect.objectContaining({
183
- id: categoryIdHidden,
184
- name: 'updated-budget-hidden',
185
- hidden: false,
186
- group_id: secondaryGroupId,
187
- }),
188
- ]));
189
- // delete categories
190
- await api.deleteCategory(categoryId);
191
- expect(categories).toEqual(expect.arrayContaining([
192
- expect.not.objectContaining({
193
- id: categoryId,
194
- }),
195
- ]));
196
- });
197
- // apis: setBudgetAmount, setBudgetCarryover, getBudgetMonth
198
- test('Budgets: successfully update budgets', async () => {
199
- const month = '2023-10';
200
- global.currentMonth = month;
201
- // create some new categories to test with
202
- const groupId = await api.createCategoryGroup({
203
- name: 'tests',
204
- });
205
- const categoryId = await api.createCategory({
206
- name: 'test-budget',
207
- group_id: groupId,
208
- });
209
- await api.setBudgetAmount(month, categoryId, 100);
210
- await api.setBudgetCarryover(month, categoryId, true);
211
- const budgetMonth = await api.getBudgetMonth(month);
212
- expect(budgetMonth.categoryGroups).toEqual(expect.arrayContaining([
213
- expect.objectContaining({
214
- id: groupId,
215
- categories: expect.arrayContaining([
216
- expect.objectContaining({
217
- id: categoryId,
218
- budgeted: 100,
219
- carryover: true,
220
- }),
221
- ]),
222
- }),
223
- ]));
224
- });
225
- //apis: createAccount, getAccounts, updateAccount, closeAccount, deleteAccount, reopenAccount, getAccountBalance
226
- test('Accounts: successfully complete account operators', async () => {
227
- const accountId1 = await api.createAccount({ name: 'test-account1', offbudget: true }, 1000);
228
- const accountId2 = await api.createAccount({ name: 'test-account2' }, 0);
229
- let accounts = await api.getAccounts();
230
- // accounts successfully created
231
- expect(accounts).toEqual(expect.arrayContaining([
232
- expect.objectContaining({
233
- id: accountId1,
234
- name: 'test-account1',
235
- offbudget: true,
236
- }),
237
- expect.objectContaining({ id: accountId2, name: 'test-account2' }),
238
- ]));
239
- expect(await api.getAccountBalance(accountId1)).toEqual(1000);
240
- expect(await api.getAccountBalance(accountId2)).toEqual(0);
241
- await api.updateAccount(accountId1, { offbudget: false });
242
- await api.closeAccount(accountId1, accountId2, null);
243
- await api.deleteAccount(accountId2);
244
- // accounts successfully updated, and one of them deleted
245
- accounts = await api.getAccounts();
246
- expect(accounts).toEqual(expect.arrayContaining([
247
- expect.objectContaining({
248
- id: accountId1,
249
- name: 'test-account1',
250
- closed: true,
251
- offbudget: false,
252
- }),
253
- expect.not.objectContaining({ id: accountId2 }),
254
- ]));
255
- await api.reopenAccount(accountId1);
256
- // the non-deleted account is reopened
257
- accounts = await api.getAccounts();
258
- expect(accounts).toEqual(expect.arrayContaining([
259
- expect.objectContaining({
260
- id: accountId1,
261
- name: 'test-account1',
262
- closed: false,
263
- }),
264
- ]));
265
- });
266
- // apis: createPayee, getPayees, updatePayee, deletePayee
267
- test('Payees: successfully update payees', async () => {
268
- const payeeId1 = await api.createPayee({ name: 'test-payee1' });
269
- const payeeId2 = await api.createPayee({ name: 'test-payee2' });
270
- let payees = await api.getPayees();
271
- // payees successfully created
272
- expect(payees).toEqual(expect.arrayContaining([
273
- expect.objectContaining({
274
- id: payeeId1,
275
- name: 'test-payee1',
276
- }),
277
- expect.objectContaining({
278
- id: payeeId2,
279
- name: 'test-payee2',
280
- }),
281
- ]));
282
- await api.updatePayee(payeeId1, { name: 'test-updated-payee' });
283
- await api.deletePayee(payeeId2);
284
- // confirm update and delete were successful
285
- payees = await api.getPayees();
286
- expect(payees).toEqual(expect.arrayContaining([
287
- expect.objectContaining({
288
- id: payeeId1,
289
- name: 'test-updated-payee',
290
- }),
291
- expect.not.objectContaining({
292
- name: 'test-payee1',
293
- }),
294
- expect.not.objectContaining({
295
- id: payeeId2,
296
- }),
297
- ]));
298
- });
299
- // apis: getRules, getPayeeRules, createRule, updateRule, deleteRule
300
- test('Rules: successfully update rules', async () => {
301
- await api.createPayee({ name: 'test-payee' });
302
- await api.createPayee({ name: 'test-payee2' });
303
- // create our test rules
304
- const rule = await api.createRule({
305
- stage: 'pre',
306
- conditionsOp: 'and',
307
- conditions: [
308
- {
309
- field: 'payee',
310
- op: 'is',
311
- value: 'test-payee',
312
- },
313
- ],
314
- actions: [
315
- {
316
- op: 'set',
317
- field: 'category',
318
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
319
- },
320
- ],
321
- });
322
- const rule2 = await api.createRule({
323
- stage: 'pre',
324
- conditionsOp: 'and',
325
- conditions: [
326
- {
327
- field: 'payee',
328
- op: 'is',
329
- value: 'test-payee2',
330
- },
331
- ],
332
- actions: [
333
- {
334
- op: 'set',
335
- field: 'category',
336
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
337
- },
338
- ],
339
- });
340
- // get existing rules
341
- const rules = await api.getRules();
342
- expect(rules).toEqual(expect.arrayContaining([
343
- expect.objectContaining({
344
- actions: expect.arrayContaining([
345
- expect.objectContaining({
346
- field: 'category',
347
- op: 'set',
348
- type: 'id',
349
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
350
- }),
351
- ]),
352
- conditions: expect.arrayContaining([
353
- expect.objectContaining({
354
- field: 'payee',
355
- op: 'is',
356
- type: 'id',
357
- value: 'test-payee2',
358
- }),
359
- ]),
360
- conditionsOp: 'and',
361
- id: rule2.id,
362
- stage: 'pre',
363
- }),
364
- expect.objectContaining({
365
- actions: expect.arrayContaining([
366
- expect.objectContaining({
367
- field: 'category',
368
- op: 'set',
369
- type: 'id',
370
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
371
- }),
372
- ]),
373
- conditions: expect.arrayContaining([
374
- expect.objectContaining({
375
- field: 'payee',
376
- op: 'is',
377
- type: 'id',
378
- value: 'test-payee',
379
- }),
380
- ]),
381
- conditionsOp: 'and',
382
- id: rule.id,
383
- stage: 'pre',
384
- }),
385
- ]));
386
- // get by payee
387
- expect(await api.getPayeeRules('test-payee')).toEqual(expect.arrayContaining([
388
- expect.objectContaining({
389
- actions: expect.arrayContaining([
390
- expect.objectContaining({
391
- field: 'category',
392
- op: 'set',
393
- type: 'id',
394
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
395
- }),
396
- ]),
397
- conditions: expect.arrayContaining([
398
- expect.objectContaining({
399
- field: 'payee',
400
- op: 'is',
401
- type: 'id',
402
- value: 'test-payee',
403
- }),
404
- ]),
405
- conditionsOp: 'and',
406
- id: rule.id,
407
- stage: 'pre',
408
- }),
409
- ]));
410
- expect(await api.getPayeeRules('test-payee2')).toEqual(expect.arrayContaining([
411
- expect.objectContaining({
412
- actions: expect.arrayContaining([
413
- expect.objectContaining({
414
- field: 'category',
415
- op: 'set',
416
- type: 'id',
417
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
418
- }),
419
- ]),
420
- conditions: expect.arrayContaining([
421
- expect.objectContaining({
422
- field: 'payee',
423
- op: 'is',
424
- type: 'id',
425
- value: 'test-payee2',
426
- }),
427
- ]),
428
- conditionsOp: 'and',
429
- id: rule2.id,
430
- stage: 'pre',
431
- }),
432
- ]));
433
- // update one rule
434
- const updatedRule = {
435
- ...rule,
436
- stage: 'post',
437
- conditionsOp: 'or',
438
- };
439
- expect(await api.updateRule(updatedRule)).toEqual(updatedRule);
440
- expect(await api.getRules()).toEqual(expect.arrayContaining([
441
- expect.objectContaining({
442
- actions: expect.arrayContaining([
443
- expect.objectContaining({
444
- field: 'category',
445
- op: 'set',
446
- type: 'id',
447
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
448
- }),
449
- ]),
450
- conditions: expect.arrayContaining([
451
- expect.objectContaining({
452
- field: 'payee',
453
- op: 'is',
454
- type: 'id',
455
- value: 'test-payee',
456
- }),
457
- ]),
458
- conditionsOp: 'or',
459
- id: rule.id,
460
- stage: 'post',
461
- }),
462
- expect.objectContaining({
463
- actions: expect.arrayContaining([
464
- expect.objectContaining({
465
- field: 'category',
466
- op: 'set',
467
- type: 'id',
468
- value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
469
- }),
470
- ]),
471
- conditions: expect.arrayContaining([
472
- expect.objectContaining({
473
- field: 'payee',
474
- op: 'is',
475
- type: 'id',
476
- value: 'test-payee2',
477
- }),
478
- ]),
479
- conditionsOp: 'and',
480
- id: rule2.id,
481
- stage: 'pre',
482
- }),
483
- ]));
484
- // delete rules
485
- await api.deleteRule(rules[1].id);
486
- expect(await api.getRules()).toHaveLength(1);
487
- await api.deleteRule(rules[0].id);
488
- expect(await api.getRules()).toHaveLength(0);
489
- });
490
- // apis: addTransactions, getTransactions, importTransactions, updateTransaction, deleteTransaction
491
- test('Transactions: successfully update transactions', async () => {
492
- const accountId = await api.createAccount({ name: 'test-account' }, 0);
493
- let newTransaction = [
494
- { date: '2023-11-03', imported_id: '11', amount: 100, notes: 'notes' },
495
- { date: '2023-11-03', imported_id: '12', amount: 100, notes: '' },
496
- ];
497
- const addResult = await api.addTransactions(accountId, newTransaction, {
498
- learnCategories: true,
499
- runTransfers: true,
500
- });
501
- expect(addResult).toBe('ok');
502
- expect(await api.getAccountBalance(accountId)).toEqual(200);
503
- expect(await api.getAccountBalance(accountId, new Date(2023, 10, 2))).toEqual(0);
504
- // confirm added transactions exist
505
- let transactions = await api.getTransactions(accountId, '2023-11-01', '2023-11-30');
506
- expect(transactions).toEqual(expect.arrayContaining(newTransaction.map(trans => expect.objectContaining(trans))));
507
- expect(transactions).toHaveLength(2);
508
- newTransaction = [
509
- { date: '2023-12-03', imported_id: '11', amount: 100, notes: 'notes' },
510
- { date: '2023-12-03', imported_id: '12', amount: 100, notes: 'notes' },
511
- { date: '2023-12-03', imported_id: '22', amount: 200, notes: '' },
512
- ];
513
- const reconciled = await api.importTransactions(accountId, newTransaction);
514
- // Expect it to reconcile and to have updated one of the previous transactions
515
- expect(reconciled.added).toHaveLength(1);
516
- expect(reconciled.updated).toHaveLength(1);
517
- // confirm imported transactions exist
518
- transactions = await api.getTransactions(accountId, '2023-12-01', '2023-12-31');
519
- expect(transactions).toEqual(expect.arrayContaining([
520
- expect.objectContaining({ imported_id: '22', amount: 200 }),
521
- ]));
522
- expect(transactions).toHaveLength(1);
523
- // confirm imported transactions update perfomed
524
- transactions = await api.getTransactions(accountId, '2023-11-01', '2023-11-30');
525
- expect(transactions).toEqual(expect.arrayContaining([
526
- expect.objectContaining({ notes: 'notes', amount: 100 }),
527
- ]));
528
- expect(transactions).toHaveLength(2);
529
- const idToUpdate = reconciled.added[0];
530
- const idToDelete = reconciled.updated[0];
531
- await api.updateTransaction(idToUpdate, { amount: 500 });
532
- await api.deleteTransaction(idToDelete);
533
- // confirm updates and deletions work
534
- transactions = await api.getTransactions(accountId, '2023-12-01', '2023-12-31');
535
- expect(transactions).toEqual(expect.arrayContaining([
536
- expect.objectContaining({ id: idToUpdate, amount: 500 }),
537
- expect.not.objectContaining({ id: idToDelete }),
538
- ]));
539
- expect(transactions).toHaveLength(1);
540
- });
541
- });