@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.
- package/@types/loot-core/client/accounts/accountsSlice.d.ts +175 -0
- package/@types/loot-core/client/app/appSlice.d.ts +175 -0
- package/@types/loot-core/client/budgets/budgetsSlice.d.ts +401 -0
- package/@types/loot-core/client/modals/modalsSlice.d.ts +486 -0
- package/@types/loot-core/client/notifications/notificationsSlice.d.ts +47 -0
- package/@types/loot-core/client/platform.d.ts +1 -0
- package/@types/loot-core/client/prefs/prefsSlice.d.ts +186 -0
- package/@types/loot-core/client/queries/queriesSlice.d.ts +692 -0
- package/@types/loot-core/client/redux.d.ts +18546 -0
- package/@types/loot-core/client/store/index.d.ts +133 -0
- package/@types/loot-core/client/users/usersSlice.d.ts +89 -0
- package/@types/loot-core/platform/client/fetch/index.d.ts +1 -10
- package/@types/loot-core/platform/client/undo/index.d.ts +19 -31
- package/@types/loot-core/platform/exceptions/index.d.ts +2 -5
- package/@types/loot-core/platform/server/connection/index.d.ts +0 -3
- package/@types/loot-core/platform/server/fetch/index.d.ts +1 -4
- package/@types/loot-core/platform/server/log/index.d.ts +4 -6
- package/@types/loot-core/server/accounts/app.d.ts +19 -5
- package/@types/loot-core/server/accounts/link.d.ts +6 -1
- package/@types/loot-core/server/admin/app.d.ts +54 -1
- package/@types/loot-core/server/api-models.d.ts +22 -22
- package/@types/loot-core/server/aql/exec.d.ts +1 -1
- package/@types/loot-core/server/aql/schema/index.d.ts +9 -0
- package/@types/loot-core/server/budget/actions.d.ts +6 -5
- package/@types/loot-core/server/budget/app.d.ts +103 -2
- package/@types/loot-core/server/budget/cleanup-template.d.ts +1 -1
- package/@types/loot-core/server/budget/goaltemplates.d.ts +1 -1
- package/@types/loot-core/server/budget/statements.d.ts +2 -2
- package/@types/loot-core/server/budget/template-notes.d.ts +1 -1
- package/@types/loot-core/server/budget/types/templates.d.ts +2 -1
- package/@types/loot-core/server/cloud-storage.d.ts +1 -1
- package/@types/loot-core/server/dashboard/app.d.ts +35 -1
- package/@types/loot-core/server/db/index.d.ts +38 -31
- package/@types/loot-core/server/db/sort.d.ts +1 -1
- package/@types/loot-core/server/encryption-internals.d.ts +5 -5
- package/@types/loot-core/server/encryption-internals.web.d.ts +2 -2
- package/@types/loot-core/server/encryption.d.ts +3 -3
- package/@types/loot-core/server/filters/app.d.ts +10 -1
- package/@types/loot-core/server/main-app.d.ts +1 -1
- package/@types/loot-core/server/models.d.ts +24 -23
- package/@types/loot-core/server/notes/app.d.ts +6 -1
- package/@types/loot-core/server/payees/app.d.ts +48 -0
- package/@types/loot-core/server/preferences/app.d.ts +1 -10
- package/@types/loot-core/server/reports/app.d.ts +9 -1
- package/@types/loot-core/server/rules/app.d.ts +50 -1
- package/@types/loot-core/server/schedules/app.d.ts +25 -2
- package/@types/loot-core/server/schedules/find-schedules.d.ts +1 -1
- package/@types/loot-core/server/server-config.d.ts +1 -0
- package/@types/loot-core/server/sheet.d.ts +1 -1
- package/@types/loot-core/server/spreadsheet/app.d.ts +38 -0
- package/@types/loot-core/server/spreadsheet/graph-data-structure.d.ts +4 -4
- package/@types/loot-core/server/spreadsheet/spreadsheet.d.ts +3 -2
- package/@types/loot-core/server/sync/app.d.ts +38 -0
- package/@types/loot-core/server/sync/make-test-message.d.ts +1 -1
- package/@types/loot-core/server/tools/app.d.ts +13 -1
- package/@types/loot-core/server/transactions/transaction-rules.d.ts +5 -4
- package/@types/loot-core/server/undo.d.ts +1 -1
- package/@types/loot-core/shared/async.d.ts +4 -3
- package/@types/loot-core/shared/locale.d.ts +1 -0
- package/@types/loot-core/shared/months.d.ts +2 -2
- package/@types/loot-core/shared/schedules.d.ts +5 -3
- package/@types/loot-core/shared/util.d.ts +4 -1
- package/@types/loot-core/types/handlers.d.ts +16 -10
- package/@types/loot-core/types/models/account.d.ts +2 -1
- package/@types/loot-core/types/models/bank-sync.d.ts +1 -1
- package/@types/loot-core/types/models/index.d.ts +5 -1
- package/@types/loot-core/types/models/openid.d.ts +2 -1
- package/@types/loot-core/types/models/payee.d.ts +2 -2
- package/@types/loot-core/types/models/pluggyai.d.ts +18 -0
- package/@types/loot-core/types/models/user-access.d.ts +10 -0
- package/@types/loot-core/types/models/user.d.ts +17 -18
- package/@types/loot-core/types/prefs.d.ts +13 -1
- package/@types/loot-core/types/server-handlers.d.ts +0 -99
- package/@types/loot-core/types/util.d.ts +7 -0
- package/dist/app/bundle.api.js +93477 -49658
- package/dist/index.js +17 -7
- package/dist/jest.config.js +0 -2
- package/dist/methods.js +17 -7
- package/dist/migrations/1740506588539_add_last_reconciled_at.sql +5 -0
- package/dist/package.json +8 -8
- package/dist/validateNodeVersion.js +17 -7
- package/package.json +8 -8
- package/@types/loot-core/client/constants.d.ts +0 -21
- package/@types/loot-core/client/state-types/budgets.d.ts +0 -36
- package/@types/loot-core/client/state-types/index.d.ts +0 -27
- package/@types/loot-core/client/state-types/modals.d.ts +0 -392
- package/@types/loot-core/client/state-types/notifications.d.ts +0 -57
- package/@types/loot-core/client/state-types/prefs.d.ts +0 -40
- package/@types/loot-core/client/state-types/user.d.ts +0 -13
- package/@types/loot-core/server/admin/types/handlers.d.ts +0 -43
- package/@types/loot-core/server/budget/types/handlers.d.ts +0 -91
- package/@types/loot-core/server/dashboard/types/handlers.d.ts +0 -24
- package/@types/loot-core/server/filters/types/handlers.d.ts +0 -7
- package/@types/loot-core/server/notes/types/handlers.d.ts +0 -3
- package/@types/loot-core/server/reports/types/handlers.d.ts +0 -6
- package/@types/loot-core/server/rules/types/handlers.d.ts +0 -40
- package/@types/loot-core/server/schedules/types/handlers.d.ts +0 -31
- package/@types/loot-core/server/tools/types/handlers.d.ts +0 -11
- package/@types/loot-core/types/models/userAccess.d.ts +0 -9
- package/dist/methods.test.js +0 -541
- /package/@types/{methods.test.d.ts → loot-core/server/api.test.d.ts} +0 -0
package/dist/methods.test.js
DELETED
|
@@ -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
|
-
});
|
|
File without changes
|