@actual-app/api 6.6.0 → 6.7.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/dist/app/bundle.api.js +129 -60
- package/dist/methods.js +5 -1
- package/dist/methods.test.js +29 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/app/bundle.api.js
CHANGED
|
@@ -12051,6 +12051,47 @@
|
|
|
12051
12051
|
}
|
|
12052
12052
|
/***/
|
|
12053
12053
|
}),
|
|
12054
|
+
/***/ "./node_modules/date-fns/esm/differenceInMilliseconds/index.js":
|
|
12055
|
+
/*!*********************************************************************!*\
|
|
12056
|
+
!*** ./node_modules/date-fns/esm/differenceInMilliseconds/index.js ***!
|
|
12057
|
+
\*********************************************************************/
|
|
12058
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
12059
|
+
"use strict";
|
|
12060
|
+
__webpack_require__.r(__webpack_exports__);
|
|
12061
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
12062
|
+
/* harmony export */ "default": () => ( /* binding */differenceInMilliseconds)
|
|
12063
|
+
/* harmony export */
|
|
12064
|
+
});
|
|
12065
|
+
/* harmony import */ var _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../toDate/index.js */ "./node_modules/date-fns/esm/toDate/index.js");
|
|
12066
|
+
/* harmony import */ var _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../_lib/requiredArgs/index.js */ "./node_modules/date-fns/esm/_lib/requiredArgs/index.js");
|
|
12067
|
+
/**
|
|
12068
|
+
* @name differenceInMilliseconds
|
|
12069
|
+
* @category Millisecond Helpers
|
|
12070
|
+
* @summary Get the number of milliseconds between the given dates.
|
|
12071
|
+
*
|
|
12072
|
+
* @description
|
|
12073
|
+
* Get the number of milliseconds between the given dates.
|
|
12074
|
+
*
|
|
12075
|
+
* @param {Date|Number} dateLeft - the later date
|
|
12076
|
+
* @param {Date|Number} dateRight - the earlier date
|
|
12077
|
+
* @returns {Number} the number of milliseconds
|
|
12078
|
+
* @throws {TypeError} 2 arguments required
|
|
12079
|
+
*
|
|
12080
|
+
* @example
|
|
12081
|
+
* // How many milliseconds are between
|
|
12082
|
+
* // 2 July 2014 12:30:20.600 and 2 July 2014 12:30:21.700?
|
|
12083
|
+
* const result = differenceInMilliseconds(
|
|
12084
|
+
* new Date(2014, 6, 2, 12, 30, 21, 700),
|
|
12085
|
+
* new Date(2014, 6, 2, 12, 30, 20, 600)
|
|
12086
|
+
* )
|
|
12087
|
+
* //=> 1100
|
|
12088
|
+
*/
|
|
12089
|
+
function differenceInMilliseconds(dateLeft, dateRight) {
|
|
12090
|
+
(0, _lib_requiredArgs_index_js__WEBPACK_IMPORTED_MODULE_0__["default"])(2, arguments);
|
|
12091
|
+
return (0, _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__["default"])(dateLeft).getTime() - (0, _toDate_index_js__WEBPACK_IMPORTED_MODULE_1__["default"])(dateRight).getTime();
|
|
12092
|
+
}
|
|
12093
|
+
/***/
|
|
12094
|
+
}),
|
|
12054
12095
|
/***/ "./node_modules/date-fns/esm/endOfMonth/index.js":
|
|
12055
12096
|
/*!*******************************************************!*\
|
|
12056
12097
|
!*** ./node_modules/date-fns/esm/endOfMonth/index.js ***!
|
|
@@ -27249,6 +27290,7 @@
|
|
|
27249
27290
|
/* harmony export */ getBudgetMonth: () => ( /* binding */getBudgetMonth),
|
|
27250
27291
|
/* harmony export */ getBudgetMonths: () => ( /* binding */getBudgetMonths),
|
|
27251
27292
|
/* harmony export */ getCategories: () => ( /* binding */getCategories),
|
|
27293
|
+
/* harmony export */ getCategoryGroups: () => ( /* binding */getCategoryGroups),
|
|
27252
27294
|
/* harmony export */ getPayees: () => ( /* binding */getPayees),
|
|
27253
27295
|
/* harmony export */ getTransactions: () => ( /* binding */getTransactions),
|
|
27254
27296
|
/* harmony export */ importTransactions: () => ( /* binding */importTransactions),
|
|
@@ -27660,6 +27702,9 @@
|
|
|
27660
27702
|
id: id
|
|
27661
27703
|
});
|
|
27662
27704
|
}
|
|
27705
|
+
function getCategoryGroups() {
|
|
27706
|
+
return send("api/category-groups-get");
|
|
27707
|
+
}
|
|
27663
27708
|
function createCategoryGroup(group) {
|
|
27664
27709
|
return send("api/category-group-create", {
|
|
27665
27710
|
group: group
|
|
@@ -31564,7 +31609,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
31564
31609
|
errors,
|
|
31565
31610
|
transactions: data.transactions.map((trans) => {
|
|
31566
31611
|
return {
|
|
31567
|
-
amount: trans.amount,
|
|
31612
|
+
amount: Number(trans.amount),
|
|
31568
31613
|
imported_id: trans.fitId,
|
|
31569
31614
|
date: trans.date,
|
|
31570
31615
|
payee_name: trans.name || (useMemoFallback ? trans.memo : null),
|
|
@@ -32559,9 +32604,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32559
32604
|
/* harmony export */ syncExternalAccount: () => ( /* binding */syncExternalAccount)
|
|
32560
32605
|
/* harmony export */
|
|
32561
32606
|
});
|
|
32562
|
-
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/
|
|
32563
|
-
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/
|
|
32564
|
-
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/
|
|
32607
|
+
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/differenceInMilliseconds/index.js");
|
|
32608
|
+
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/parseISO/index.js");
|
|
32609
|
+
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/max/index.js");
|
|
32610
|
+
/* harmony import */ var date_fns__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! date-fns */ "./node_modules/date-fns/esm/format/index.js");
|
|
32565
32611
|
/* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
|
|
32566
32612
|
/* harmony import */ var _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../platform/server/asyncStorage */ "./packages/loot-core/src/platform/server/asyncStorage/index.electron.ts");
|
|
32567
32613
|
/* harmony import */ var _shared_months__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../shared/months */ "./packages/loot-core/src/shared/months.ts");
|
|
@@ -32699,6 +32745,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32699
32745
|
const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.getItem('user-token');
|
|
32700
32746
|
if (!userToken)
|
|
32701
32747
|
return;
|
|
32748
|
+
console.log('Pulling transactions from GoCardless');
|
|
32702
32749
|
const res = await (0, _post__WEBPACK_IMPORTED_MODULE_6__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_7__.getServer)().GOCARDLESS_SERVER + '/transactions', {
|
|
32703
32750
|
userId,
|
|
32704
32751
|
key: userKey,
|
|
@@ -32712,6 +32759,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32712
32759
|
throw BankSyncError(res.error_type, res.error_code);
|
|
32713
32760
|
}
|
|
32714
32761
|
const { transactions: { all }, balances, startingBalance } = res;
|
|
32762
|
+
console.log('Response:', res);
|
|
32715
32763
|
return {
|
|
32716
32764
|
transactions: all,
|
|
32717
32765
|
accountBalance: balances,
|
|
@@ -32722,6 +32770,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32722
32770
|
const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_0__.getItem('user-token');
|
|
32723
32771
|
if (!userToken)
|
|
32724
32772
|
return;
|
|
32773
|
+
console.log('Pulling transactions from SimpleFin');
|
|
32725
32774
|
const res = await (0, _post__WEBPACK_IMPORTED_MODULE_6__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_7__.getServer)().SIMPLEFIN_SERVER + '/transactions', {
|
|
32726
32775
|
accountId: acctId,
|
|
32727
32776
|
startDate: since
|
|
@@ -32732,6 +32781,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32732
32781
|
throw BankSyncError(res.error_type, res.error_code);
|
|
32733
32782
|
}
|
|
32734
32783
|
const { transactions: { all }, balances, startingBalance } = res;
|
|
32784
|
+
console.log('Response:', res);
|
|
32735
32785
|
return {
|
|
32736
32786
|
transactions: all,
|
|
32737
32787
|
accountBalance: balances,
|
|
@@ -32883,6 +32933,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32883
32933
|
});
|
|
32884
32934
|
}
|
|
32885
32935
|
async function reconcileExternalTransactions(acctId, transactions) {
|
|
32936
|
+
console.log('Performing transaction reconciliation');
|
|
32886
32937
|
const hasMatched = new Set();
|
|
32887
32938
|
const updated = [];
|
|
32888
32939
|
const added = [];
|
|
@@ -32919,6 +32970,15 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32919
32970
|
trans.amount || 0,
|
|
32920
32971
|
acctId
|
|
32921
32972
|
]);
|
|
32973
|
+
// Sort the matched transactions according to the distance from the original
|
|
32974
|
+
// transactions date. i.e. if the original transaction is in 21-02-2024 and
|
|
32975
|
+
// the matched transactions are: 20-02-2024, 21-02-2024, 29-02-2024 then
|
|
32976
|
+
// the resulting data-set should be: 21-02-2024, 20-02-2024, 29-02-2024.
|
|
32977
|
+
fuzzyDataset = fuzzyDataset.sort((a, b) => {
|
|
32978
|
+
const aDistance = Math.abs(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](trans.date), date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(a.date))));
|
|
32979
|
+
const bDistance = Math.abs(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](trans.date), date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(b.date))));
|
|
32980
|
+
return aDistance > bDistance ? 1 : -1;
|
|
32981
|
+
});
|
|
32922
32982
|
}
|
|
32923
32983
|
transactionsStep1.push({
|
|
32924
32984
|
payee_name,
|
|
@@ -32949,7 +33009,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
32949
33009
|
});
|
|
32950
33010
|
// The final fuzzy matching pass. This is the lowest fidelity
|
|
32951
33011
|
// matching: it just find the first transaction that hasn't been
|
|
32952
|
-
// matched yet. Remember the
|
|
33012
|
+
// matched yet. Remember the dataset only contains transactions
|
|
32953
33013
|
// around the same date with the same amount.
|
|
32954
33014
|
const transactionsStep3 = transactionsStep2.map((data) => {
|
|
32955
33015
|
if (!data.match && data.fuzzyDataset) {
|
|
@@ -33028,6 +33088,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
33028
33088
|
added,
|
|
33029
33089
|
updated
|
|
33030
33090
|
});
|
|
33091
|
+
console.log('Debug data for the operations:', {
|
|
33092
|
+
transactionsStep1,
|
|
33093
|
+
transactionsStep2,
|
|
33094
|
+
transactionsStep3,
|
|
33095
|
+
added,
|
|
33096
|
+
updated
|
|
33097
|
+
});
|
|
33031
33098
|
return {
|
|
33032
33099
|
added: added.map((trans) => trans.id),
|
|
33033
33100
|
updated: updated.map((trans) => trans.id)
|
|
@@ -33070,6 +33137,15 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
33070
33137
|
trans.amount || 0,
|
|
33071
33138
|
acctId
|
|
33072
33139
|
]);
|
|
33140
|
+
// Sort the matched transactions according to the distance from the original
|
|
33141
|
+
// transactions date. i.e. if the original transaction is in 21-02-2024 and
|
|
33142
|
+
// the matched transactions are: 20-02-2024, 21-02-2024, 29-02-2024 then
|
|
33143
|
+
// the resulting data-set should be: 21-02-2024, 20-02-2024, 29-02-2024.
|
|
33144
|
+
fuzzyDataset = fuzzyDataset.sort((a, b) => {
|
|
33145
|
+
const aDistance = Math.abs(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](trans.date), date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(a.date))));
|
|
33146
|
+
const bDistance = Math.abs(date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](trans.date), date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(b.date))));
|
|
33147
|
+
return aDistance > bDistance ? 1 : -1;
|
|
33148
|
+
});
|
|
33073
33149
|
}
|
|
33074
33150
|
transactionsStep1.push({
|
|
33075
33151
|
payee_name,
|
|
@@ -33100,7 +33176,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
33100
33176
|
});
|
|
33101
33177
|
// The final fuzzy matching pass. This is the lowest fidelity
|
|
33102
33178
|
// matching: it just find the first transaction that hasn't been
|
|
33103
|
-
// matched yet. Remember the
|
|
33179
|
+
// matched yet. Remember the dataset only contains transactions
|
|
33104
33180
|
// around the same date with the same amount.
|
|
33105
33181
|
const transactionsStep3 = transactionsStep2.map((data) => {
|
|
33106
33182
|
if (!data.match && data.fuzzyDataset) {
|
|
@@ -33239,7 +33315,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
33239
33315
|
id
|
|
33240
33316
|
]);
|
|
33241
33317
|
const startingDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.parseDate(_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(startingTransaction.date));
|
|
33242
|
-
const startDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.dayFromDate(
|
|
33318
|
+
const startDate = _shared_months__WEBPACK_IMPORTED_MODULE_1__.dayFromDate(date_fns__WEBPACK_IMPORTED_MODULE_16__["default"]([
|
|
33243
33319
|
// Many GoCardless integrations do not support getting more than 90 days
|
|
33244
33320
|
// worth of data, so make that the earliest possible limit.
|
|
33245
33321
|
_shared_months__WEBPACK_IMPORTED_MODULE_1__.parseDate(_shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay(), 90)),
|
|
@@ -33359,7 +33435,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
33359
33435
|
// Otherwise, download transaction for the last few days if it's an
|
|
33360
33436
|
// on-budget account, or for the past 30 days if off-budget
|
|
33361
33437
|
const startingDay = _shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_1__.currentDay(), acctRow.offbudget === 0 ? 1 : 30);
|
|
33362
|
-
const { transactions } = await downloadTransactions(userId, userKey, acctId, bankId,
|
|
33438
|
+
const { transactions } = await downloadTransactions(userId, userKey, acctId, bankId, date_fns__WEBPACK_IMPORTED_MODULE_17__["default"](date_fns__WEBPACK_IMPORTED_MODULE_15__["default"](startingDay), 'yyyy-MM-dd'));
|
|
33363
33439
|
// We need to add a transaction that represents the starting
|
|
33364
33440
|
// balance for everything to balance out. In order to get balance
|
|
33365
33441
|
// before the first imported transaction, we need to get the
|
|
@@ -35252,6 +35328,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
35252
35328
|
const result = await handlers['get-categories']();
|
|
35253
35329
|
return grouped ? result.grouped.map(_api_models__WEBPACK_IMPORTED_MODULE_8__.categoryGroupModel.toExternal) : result.list.map(_api_models__WEBPACK_IMPORTED_MODULE_8__.categoryModel.toExternal);
|
|
35254
35330
|
};
|
|
35331
|
+
handlers['api/category-groups-get'] = async function () {
|
|
35332
|
+
checkFileOpen();
|
|
35333
|
+
return handlers['get-category-groups']();
|
|
35334
|
+
};
|
|
35255
35335
|
handlers['api/category-group-create'] = withMutation(async function ({ group }) {
|
|
35256
35336
|
checkFileOpen();
|
|
35257
35337
|
return handlers['category-group-create']({
|
|
@@ -38601,38 +38681,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
38601
38681
|
});
|
|
38602
38682
|
}
|
|
38603
38683
|
}
|
|
38604
|
-
//fund rollover categories after non-rollover categories
|
|
38605
|
-
for (let c = 0; c < categories.length; c++) {
|
|
38606
|
-
const category = categories[c];
|
|
38607
|
-
const budgetAvailable = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `to-budget`);
|
|
38608
|
-
const balance = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `leftover-${category.id}`);
|
|
38609
|
-
const budgeted = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `budget-${category.id}`);
|
|
38610
|
-
const to_budget = budgeted + Math.abs(balance);
|
|
38611
|
-
const categoryId = category.id;
|
|
38612
|
-
let carryover = await _db__WEBPACK_IMPORTED_MODULE_1__.first(`SELECT carryover FROM zero_budgets WHERE month = ? and category = ?`, [
|
|
38613
|
-
db_month,
|
|
38614
|
-
categoryId
|
|
38615
|
-
]);
|
|
38616
|
-
if (carryover === null) {
|
|
38617
|
-
carryover = {
|
|
38618
|
-
carryover: 0
|
|
38619
|
-
};
|
|
38620
|
-
}
|
|
38621
|
-
if (balance < 0 && Math.abs(balance) <= budgetAvailable && !category.is_income && carryover.carryover === 1) {
|
|
38622
|
-
await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
|
|
38623
|
-
category: category.id,
|
|
38624
|
-
month,
|
|
38625
|
-
amount: to_budget
|
|
38626
|
-
});
|
|
38627
|
-
}
|
|
38628
|
-
else if (balance < 0 && !category.is_income && carryover.carryover === 1 && Math.abs(balance) > budgetAvailable) {
|
|
38629
|
-
await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setBudget)({
|
|
38630
|
-
category: category.id,
|
|
38631
|
-
month,
|
|
38632
|
-
amount: budgeted + budgetAvailable
|
|
38633
|
-
});
|
|
38634
|
-
}
|
|
38635
|
-
}
|
|
38636
38684
|
const budgetAvailable = await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.getSheetValue)(sheetName, `to-budget`);
|
|
38637
38685
|
if (budgetAvailable <= 0) {
|
|
38638
38686
|
warnings.push('No funds are available to reallocate.');
|
|
@@ -39019,8 +39067,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
39019
39067
|
//in the case of multiple templates per category, schedules may have wrong priority level
|
|
39020
39068
|
const t = await createScheduleList(template, current_month, category);
|
|
39021
39069
|
errors = errors.concat(t.errors);
|
|
39022
|
-
const
|
|
39023
|
-
const
|
|
39070
|
+
const isPayMonthOf = (c) => c.full || c.target_frequency === 'monthly' && c.target_interval === 1 && c.num_months === 0 || c.target_frequency === 'weekly' && c.target_interval >= 0 && c.num_months === 0 || c.target_frequency === 'daily' || (0, _actions__WEBPACK_IMPORTED_MODULE_4__.isReflectBudget)();
|
|
39071
|
+
const t_payMonthOf = t.t.filter(isPayMonthOf);
|
|
39072
|
+
const t_sinking = t.t.filter((c) => !isPayMonthOf(c)).sort((a, b) => a.next_date_string.localeCompare(b.next_date_string));
|
|
39024
39073
|
const totalPayMonthOf = await getPayMonthOfTotal(t_payMonthOf);
|
|
39025
39074
|
const totalSinking = await getSinkingTotal(t_sinking);
|
|
39026
39075
|
const totalSinkingBaseContribution = await getSinkingBaseContributionTotal(t_sinking);
|
|
@@ -39029,7 +39078,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
39029
39078
|
}
|
|
39030
39079
|
else {
|
|
39031
39080
|
const totalSinkingContribution = await getSinkingContributionTotal(t_sinking, remainder, last_month_balance);
|
|
39032
|
-
|
|
39081
|
+
if (t_sinking.length === 0) {
|
|
39082
|
+
to_budget += Math.round(totalPayMonthOf + totalSinkingContribution) - last_month_balance;
|
|
39083
|
+
}
|
|
39084
|
+
else {
|
|
39085
|
+
to_budget += Math.round(totalPayMonthOf + totalSinkingContribution);
|
|
39086
|
+
}
|
|
39033
39087
|
}
|
|
39034
39088
|
}
|
|
39035
39089
|
return {
|
|
@@ -41942,7 +41996,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
41942
41996
|
category: isOffBudget(entityIdMap.get(accountId)) ? null : getCategory(transaction.categoryId),
|
|
41943
41997
|
date: transaction.date,
|
|
41944
41998
|
notes: transaction.memo || null,
|
|
41945
|
-
cleared: transaction.cleared === 'Cleared',
|
|
41999
|
+
cleared: transaction.cleared === 'Cleared' || transaction.cleared === 'Reconciled',
|
|
42000
|
+
reconciled: transaction.cleared === 'Reconciled',
|
|
41946
42001
|
...transferProperties(transaction),
|
|
41947
42002
|
subtransactions: transaction.subTransactions && transaction.subTransactions.map((t) => {
|
|
41948
42003
|
return {
|
|
@@ -42271,6 +42326,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
42271
42326
|
'cleared',
|
|
42272
42327
|
'reconciled'
|
|
42273
42328
|
].includes(transaction.cleared),
|
|
42329
|
+
reconciled: transaction.cleared === 'reconciled',
|
|
42274
42330
|
notes: transaction.memo || null,
|
|
42275
42331
|
imported_id: transaction.import_id || null,
|
|
42276
42332
|
transfer_id: entityIdMap.get(transaction.transfer_transaction_id) || null,
|
|
@@ -42730,6 +42786,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
42730
42786
|
return result;
|
|
42731
42787
|
});
|
|
42732
42788
|
});
|
|
42789
|
+
handlers['get-category-groups'] = async function () {
|
|
42790
|
+
return await _db__WEBPACK_IMPORTED_MODULE_27__.getCategoriesGrouped();
|
|
42791
|
+
};
|
|
42733
42792
|
handlers['category-group-create'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(async function ({ name, isIncome }) {
|
|
42734
42793
|
return (0, _undo__WEBPACK_IMPORTED_MODULE_48__.withUndo)(async () => {
|
|
42735
42794
|
return _db__WEBPACK_IMPORTED_MODULE_27__.insertCategoryGroup({
|
|
@@ -43474,12 +43533,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
43474
43533
|
'user-id',
|
|
43475
43534
|
'user-key'
|
|
43476
43535
|
]);
|
|
43477
|
-
|
|
43536
|
+
const accounts = await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery(`SELECT a.*, b.bank_id as bankId FROM accounts a
|
|
43478
43537
|
LEFT JOIN banks b ON a.bank = b.id
|
|
43479
|
-
WHERE a.tombstone = 0 AND a.closed = 0
|
|
43480
|
-
|
|
43481
|
-
|
|
43482
|
-
}
|
|
43538
|
+
WHERE a.tombstone = 0 AND a.closed = 0 AND a.id = ?`, [
|
|
43539
|
+
id
|
|
43540
|
+
], true);
|
|
43483
43541
|
const errors = [];
|
|
43484
43542
|
let newTransactions = [];
|
|
43485
43543
|
let matchedTransactions = [];
|
|
@@ -43488,7 +43546,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
43488
43546
|
const acct = accounts[i];
|
|
43489
43547
|
if (acct.bankId) {
|
|
43490
43548
|
try {
|
|
43549
|
+
console.group('Bank Sync operation');
|
|
43491
43550
|
const res = await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncExternalAccount(userId, userKey, acct.id, acct.account_id, acct.bankId);
|
|
43551
|
+
console.groupEnd();
|
|
43492
43552
|
const { added, updated } = res;
|
|
43493
43553
|
newTransactions = newTransactions.concat(added);
|
|
43494
43554
|
matchedTransactions = matchedTransactions.concat(updated);
|
|
@@ -49918,6 +49978,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
49918
49978
|
/* harmony export */ deleteTransaction: () => ( /* binding */deleteTransaction),
|
|
49919
49979
|
/* harmony export */ groupTransaction: () => ( /* binding */groupTransaction),
|
|
49920
49980
|
/* harmony export */ isPreviewId: () => ( /* binding */isPreviewId),
|
|
49981
|
+
/* harmony export */ isTemporaryId: () => ( /* binding */isTemporaryId),
|
|
49921
49982
|
/* harmony export */ makeChild: () => ( /* binding */makeChild),
|
|
49922
49983
|
/* harmony export */ realizeTempTransactions: () => ( /* binding */realizeTempTransactions),
|
|
49923
49984
|
/* harmony export */ recalculateSplit: () => ( /* binding */recalculateSplit),
|
|
@@ -49929,7 +49990,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
49929
49990
|
});
|
|
49930
49991
|
/* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
|
|
49931
49992
|
/* harmony import */ var _util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./util */ "./packages/loot-core/src/shared/util.ts");
|
|
49932
|
-
|
|
49993
|
+
function isTemporaryId(id) {
|
|
49994
|
+
return id.indexOf('temp') !== -1;
|
|
49995
|
+
}
|
|
49933
49996
|
function isPreviewId(id) {
|
|
49934
49997
|
return id.indexOf('preview/') !== -1;
|
|
49935
49998
|
}
|
|
@@ -49950,8 +50013,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
49950
50013
|
return {
|
|
49951
50014
|
amount: 0,
|
|
49952
50015
|
...data,
|
|
49953
|
-
payee: data.payee
|
|
49954
|
-
id:
|
|
50016
|
+
payee: 'payee' in data ? data.payee : parent.payee,
|
|
50017
|
+
id: 'id' in data ? data.id : prefix + (0, uuid__WEBPACK_IMPORTED_MODULE_1__["default"])(),
|
|
49955
50018
|
account: parent.account,
|
|
49956
50019
|
date: parent.date,
|
|
49957
50020
|
cleared: parent.cleared != null ? parent.cleared : null,
|
|
@@ -49964,7 +50027,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
49964
50027
|
function recalculateSplit(trans) {
|
|
49965
50028
|
// Calculate the new total of split transactions and make sure
|
|
49966
50029
|
// that it equals the parent amount
|
|
49967
|
-
const total = trans.subtransactions.reduce((acc, t) => acc + num(t.amount), 0);
|
|
50030
|
+
const total = (trans.subtransactions || []).reduce((acc, t) => acc + num(t.amount), 0);
|
|
49968
50031
|
return {
|
|
49969
50032
|
...trans,
|
|
49970
50033
|
error: total === num(trans.amount) ? null : SplitTransactionError(total, trans)
|
|
@@ -50059,7 +50122,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
50059
50122
|
updated: []
|
|
50060
50123
|
};
|
|
50061
50124
|
grouped = {
|
|
50062
|
-
|
|
50125
|
+
...split[0],
|
|
50063
50126
|
_deleted: true
|
|
50064
50127
|
};
|
|
50065
50128
|
transactionsCopy.splice(parentIndex, split.length);
|
|
@@ -50084,7 +50147,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
50084
50147
|
return {
|
|
50085
50148
|
data: transactionsCopy,
|
|
50086
50149
|
newTransaction: grouped || {
|
|
50087
|
-
|
|
50150
|
+
...trans,
|
|
50088
50151
|
_deleted: true
|
|
50089
50152
|
},
|
|
50090
50153
|
diff: (0, _util__WEBPACK_IMPORTED_MODULE_0__.diffItems)([
|
|
@@ -50144,7 +50207,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
50144
50207
|
else if (trans.subtransactions?.length === 1) {
|
|
50145
50208
|
return {
|
|
50146
50209
|
...trans,
|
|
50147
|
-
subtransactions:
|
|
50210
|
+
subtransactions: undefined,
|
|
50148
50211
|
is_parent: false,
|
|
50149
50212
|
error: null
|
|
50150
50213
|
};
|
|
@@ -50181,9 +50244,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
50181
50244
|
});
|
|
50182
50245
|
}
|
|
50183
50246
|
function realizeTempTransactions(transactions) {
|
|
50184
|
-
|
|
50185
|
-
|
|
50186
|
-
...parent,
|
|
50247
|
+
const parent = {
|
|
50248
|
+
...transactions.find((t) => !t.is_child),
|
|
50187
50249
|
id: (0, uuid__WEBPACK_IMPORTED_MODULE_1__["default"])()
|
|
50188
50250
|
};
|
|
50189
50251
|
const children = transactions.filter((t) => t.is_child);
|
|
@@ -50535,7 +50597,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
|
|
|
50535
50597
|
// currencies. We extract out the numbers and just ignore separators.
|
|
50536
50598
|
function looselyParseAmount(amount) {
|
|
50537
50599
|
function safeNumber(v) {
|
|
50538
|
-
|
|
50600
|
+
if (isNaN(v)) {
|
|
50601
|
+
return null;
|
|
50602
|
+
}
|
|
50603
|
+
const value = v * 100;
|
|
50604
|
+
if (value > MAX_SAFE_NUMBER || value < MIN_SAFE_NUMBER) {
|
|
50605
|
+
return null;
|
|
50606
|
+
}
|
|
50607
|
+
return v;
|
|
50539
50608
|
}
|
|
50540
50609
|
function extractNumbers(v) {
|
|
50541
50610
|
return v.replace(/[^0-9-]/g, '');
|
package/dist/methods.js
CHANGED
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.deletePayee = exports.updatePayee = exports.createPayee = exports.getPayees = exports.deleteCategory = exports.updateCategory = exports.createCategory = exports.getCategories = exports.deleteCategoryGroup = exports.updateCategoryGroup = exports.createCategoryGroup = exports.deleteAccount = exports.reopenAccount = exports.closeAccount = exports.updateAccount = exports.createAccount = exports.getAccounts = exports.deleteTransaction = exports.updateTransaction = exports.getTransactions = exports.importTransactions = exports.addTransactions = exports.setBudgetCarryover = exports.setBudgetAmount = exports.getBudgetMonth = exports.getBudgetMonths = exports.runQuery = exports.batchBudgetUpdates = exports.sync = exports.downloadBudget = exports.loadBudget = exports.runImport = exports.q = void 0;
|
|
26
|
+
exports.deletePayee = exports.updatePayee = exports.createPayee = exports.getPayees = exports.deleteCategory = exports.updateCategory = exports.createCategory = exports.getCategories = exports.deleteCategoryGroup = exports.updateCategoryGroup = exports.createCategoryGroup = exports.getCategoryGroups = exports.deleteAccount = exports.reopenAccount = exports.closeAccount = exports.updateAccount = exports.createAccount = exports.getAccounts = exports.deleteTransaction = exports.updateTransaction = exports.getTransactions = exports.importTransactions = exports.addTransactions = exports.setBudgetCarryover = exports.setBudgetAmount = exports.getBudgetMonth = exports.getBudgetMonths = exports.runQuery = exports.batchBudgetUpdates = exports.sync = exports.downloadBudget = exports.loadBudget = exports.runImport = exports.q = void 0;
|
|
27
27
|
const injected = __importStar(require("./injected"));
|
|
28
28
|
var query_1 = require("./app/query");
|
|
29
29
|
Object.defineProperty(exports, "q", { enumerable: true, get: function () { return query_1.q; } });
|
|
@@ -137,6 +137,10 @@ function deleteAccount(id) {
|
|
|
137
137
|
return send('api/account-delete', { id });
|
|
138
138
|
}
|
|
139
139
|
exports.deleteAccount = deleteAccount;
|
|
140
|
+
function getCategoryGroups() {
|
|
141
|
+
return send('api/category-groups-get');
|
|
142
|
+
}
|
|
143
|
+
exports.getCategoryGroups = getCategoryGroups;
|
|
140
144
|
function createCategoryGroup(group) {
|
|
141
145
|
return send('api/category-group-create', { group });
|
|
142
146
|
}
|
package/dist/methods.test.js
CHANGED
|
@@ -61,10 +61,38 @@ describe('API CRUD operations', () => {
|
|
|
61
61
|
// load test budget
|
|
62
62
|
await api.loadBudget(budgetName);
|
|
63
63
|
});
|
|
64
|
-
// apis: createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
|
|
64
|
+
// apis: getCategoryGroups, createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
|
|
65
65
|
test('CategoryGroups: successfully update category groups', async () => {
|
|
66
66
|
const month = '2023-10';
|
|
67
67
|
global.currentMonth = month;
|
|
68
|
+
// get existing category groups
|
|
69
|
+
const groups = await api.getCategoryGroups();
|
|
70
|
+
expect(groups).toEqual(expect.arrayContaining([
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
hidden: 0,
|
|
73
|
+
id: 'fc3825fd-b982-4b72-b768-5b30844cf832',
|
|
74
|
+
is_income: 0,
|
|
75
|
+
name: 'Usual Expenses',
|
|
76
|
+
sort_order: 16384,
|
|
77
|
+
tombstone: 0,
|
|
78
|
+
}),
|
|
79
|
+
expect.objectContaining({
|
|
80
|
+
hidden: 0,
|
|
81
|
+
id: 'a137772f-cf2f-4089-9432-822d2ddc1466',
|
|
82
|
+
is_income: 0,
|
|
83
|
+
name: 'Investments and Savings',
|
|
84
|
+
sort_order: 32768,
|
|
85
|
+
tombstone: 0,
|
|
86
|
+
}),
|
|
87
|
+
expect.objectContaining({
|
|
88
|
+
hidden: 0,
|
|
89
|
+
id: '2E1F5BDB-209B-43F9-AF2C-3CE28E380C00',
|
|
90
|
+
is_income: 1,
|
|
91
|
+
name: 'Income',
|
|
92
|
+
sort_order: 32768,
|
|
93
|
+
tombstone: 0,
|
|
94
|
+
}),
|
|
95
|
+
]));
|
|
68
96
|
// create our test category group
|
|
69
97
|
const mainGroupId = await api.createCategoryGroup({
|
|
70
98
|
name: 'test-group',
|
package/dist/package.json
CHANGED