@actual-app/api 6.8.1 → 6.9.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 (36) hide show
  1. package/@types/loot-core/client/constants.d.ts +1 -0
  2. package/@types/loot-core/client/state-types/modals.d.ts +14 -4
  3. package/@types/loot-core/client/state-types/queries.d.ts +8 -0
  4. package/@types/loot-core/platform/server/sqlite/index.d.ts +3 -3
  5. package/@types/loot-core/server/accounts/sync.d.ts +12 -1
  6. package/@types/loot-core/server/accounts/transactions.d.ts +4 -16
  7. package/@types/loot-core/server/api-models.d.ts +15 -0
  8. package/@types/loot-core/server/aql/schema/index.d.ts +18 -0
  9. package/@types/loot-core/server/budget/actions.d.ts +6 -1
  10. package/@types/loot-core/server/budget/app.d.ts +1 -1
  11. package/@types/loot-core/server/budget/types/handlers.d.ts +5 -0
  12. package/@types/loot-core/server/db/index.d.ts +48 -7
  13. package/@types/loot-core/server/main-app.d.ts +1 -1
  14. package/@types/loot-core/server/migrate/migrations.d.ts +1 -1
  15. package/@types/loot-core/server/post.d.ts +1 -1
  16. package/@types/loot-core/shared/normalisation.d.ts +1 -0
  17. package/@types/loot-core/shared/rules.d.ts +1 -1
  18. package/@types/loot-core/shared/transactions.d.ts +27 -2
  19. package/@types/loot-core/shared/util.d.ts +1 -1
  20. package/@types/loot-core/types/api-handlers.d.ts +15 -0
  21. package/@types/loot-core/types/file.d.ts +2 -0
  22. package/@types/loot-core/types/models/payee.d.ts +1 -0
  23. package/@types/loot-core/types/models/reports.d.ts +26 -0
  24. package/@types/loot-core/types/models/rule.d.ts +2 -1
  25. package/@types/loot-core/types/prefs.d.ts +8 -6
  26. package/@types/loot-core/types/server-handlers.d.ts +9 -2
  27. package/@types/methods.d.ts +4 -0
  28. package/dist/app/bundle.api.js +1156 -613
  29. package/dist/methods.js +17 -1
  30. package/dist/methods.test.js +15 -1
  31. package/dist/migrations/1716359441000_include_current.sql +5 -0
  32. package/dist/migrations/1720310586000_link_transfer_schedules.sql +19 -0
  33. package/dist/migrations/1720664867241_add_payee_favorite.sql +5 -0
  34. package/dist/migrations/1720665000000_goal_context.sql +6 -0
  35. package/dist/package.json +1 -1
  36. package/package.json +1 -1
@@ -23720,17 +23720,21 @@
23720
23720
  /* harmony export */ deleteRule: () => ( /* binding */deleteRule),
23721
23721
  /* harmony export */ deleteTransaction: () => ( /* binding */deleteTransaction),
23722
23722
  /* harmony export */ downloadBudget: () => ( /* binding */downloadBudget),
23723
+ /* harmony export */ getAccountBalance: () => ( /* binding */getAccountBalance),
23723
23724
  /* harmony export */ getAccounts: () => ( /* binding */getAccounts),
23724
23725
  /* harmony export */ getBudgetMonth: () => ( /* binding */getBudgetMonth),
23725
23726
  /* harmony export */ getBudgetMonths: () => ( /* binding */getBudgetMonths),
23727
+ /* harmony export */ getBudgets: () => ( /* binding */getBudgets),
23726
23728
  /* harmony export */ getCategories: () => ( /* binding */getCategories),
23727
23729
  /* harmony export */ getCategoryGroups: () => ( /* binding */getCategoryGroups),
23730
+ /* harmony export */ getCommonPayees: () => ( /* binding */getCommonPayees),
23728
23731
  /* harmony export */ getPayeeRules: () => ( /* binding */getPayeeRules),
23729
23732
  /* harmony export */ getPayees: () => ( /* binding */getPayees),
23730
23733
  /* harmony export */ getRules: () => ( /* binding */getRules),
23731
23734
  /* harmony export */ getTransactions: () => ( /* binding */getTransactions),
23732
23735
  /* harmony export */ importTransactions: () => ( /* binding */importTransactions),
23733
23736
  /* harmony export */ loadBudget: () => ( /* binding */loadBudget),
23737
+ /* harmony export */ mergePayees: () => ( /* binding */mergePayees),
23734
23738
  /* harmony export */ q: () => ( /* reexport safe */_app_query__WEBPACK_IMPORTED_MODULE_1__.q),
23735
23739
  /* harmony export */ reopenAccount: () => ( /* binding */reopenAccount),
23736
23740
  /* harmony export */ runBankSync: () => ( /* binding */runBankSync),
@@ -23983,6 +23987,20 @@
23983
23987
  });
23984
23988
  return _downloadBudget.apply(this, arguments);
23985
23989
  }
23990
+ function getBudgets() {
23991
+ return _getBudgets.apply(this, arguments);
23992
+ }
23993
+ function _getBudgets() {
23994
+ _getBudgets = _async_to_generator(function () {
23995
+ return _ts_generator(this, function (_state) {
23996
+ return [
23997
+ 2,
23998
+ send('api/get-budgets')
23999
+ ];
24000
+ });
24001
+ });
24002
+ return _getBudgets.apply(this, arguments);
24003
+ }
23986
24004
  function sync() {
23987
24005
  return _sync.apply(this, arguments);
23988
24006
  }
@@ -24154,6 +24172,12 @@
24154
24172
  id: id
24155
24173
  });
24156
24174
  }
24175
+ function getAccountBalance(id, cutoff) {
24176
+ return send('api/account-balance', {
24177
+ id: id,
24178
+ cutoff: cutoff
24179
+ });
24180
+ }
24157
24181
  function getCategoryGroups() {
24158
24182
  return send('api/category-groups-get');
24159
24183
  }
@@ -24196,6 +24220,9 @@
24196
24220
  transferCategoryId: transferCategoryId
24197
24221
  });
24198
24222
  }
24223
+ function getCommonPayees() {
24224
+ return send('api/common-payees-get');
24225
+ }
24199
24226
  function getPayees() {
24200
24227
  return send('api/payees-get');
24201
24228
  }
@@ -24215,6 +24242,12 @@
24215
24242
  id: id
24216
24243
  });
24217
24244
  }
24245
+ function mergePayees(targetId, mergeIds) {
24246
+ return send('api/payees-merge', {
24247
+ targetId: targetId,
24248
+ mergeIds: mergeIds
24249
+ });
24250
+ }
24218
24251
  function getRules() {
24219
24252
  return send('api/rules-get');
24220
24253
  }
@@ -24422,18 +24455,17 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24422
24455
  /* harmony import */ var _server_budget_base__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../server/budget/base */ "./packages/loot-core/src/server/budget/base.ts");
24423
24456
  /* harmony import */ var _server_db__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../server/db */ "./packages/loot-core/src/server/db/index.ts");
24424
24457
  /* harmony import */ var _server_mutators__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../server/mutators */ "./packages/loot-core/src/server/mutators.ts");
24425
- /* harmony import */ var _server_prefs__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../server/prefs */ "./packages/loot-core/src/server/prefs.ts");
24426
- /* harmony import */ var _server_sheet__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../server/sheet */ "./packages/loot-core/src/server/sheet.ts");
24427
- /* harmony import */ var _server_sync__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../server/sync */ "./packages/loot-core/src/server/sync/index.ts");
24428
- /* harmony import */ var _shared_months__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../shared/months */ "./packages/loot-core/src/shared/months.ts");
24429
- /* harmony import */ var _shared_query__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../shared/query */ "./packages/loot-core/src/shared/query.ts");
24430
- /* harmony import */ var _random__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./random */ "./packages/loot-core/src/mocks/random.ts");
24458
+ /* harmony import */ var _server_sheet__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../server/sheet */ "./packages/loot-core/src/server/sheet.ts");
24459
+ /* harmony import */ var _server_sync__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../server/sync */ "./packages/loot-core/src/server/sync/index.ts");
24460
+ /* harmony import */ var _shared_months__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../shared/months */ "./packages/loot-core/src/shared/months.ts");
24461
+ /* harmony import */ var _shared_query__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../shared/query */ "./packages/loot-core/src/shared/query.ts");
24462
+ /* harmony import */ var _random__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./random */ "./packages/loot-core/src/mocks/random.ts");
24431
24463
  // @ts-strict-ignore
24432
24464
  function pickRandom(list) {
24433
- return list[Math.floor((0, _random__WEBPACK_IMPORTED_MODULE_11__.random)() * list.length) % list.length];
24465
+ return list[Math.floor((0, _random__WEBPACK_IMPORTED_MODULE_10__.random)() * list.length) % list.length];
24434
24466
  }
24435
24467
  function number(start, end) {
24436
- return start + (end - start) * (0, _random__WEBPACK_IMPORTED_MODULE_11__.random)();
24468
+ return start + (end - start) * (0, _random__WEBPACK_IMPORTED_MODULE_10__.random)();
24437
24469
  }
24438
24470
  function integer(start, end) {
24439
24471
  return Math.round(number(start, end));
@@ -24479,7 +24511,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24479
24511
  const transactions = [];
24480
24512
  for (let i = 0; i < numTransactions; i++) {
24481
24513
  let payee;
24482
- if ((0, _random__WEBPACK_IMPORTED_MODULE_11__.random)() < 0.09) {
24514
+ if ((0, _random__WEBPACK_IMPORTED_MODULE_10__.random)() < 0.09) {
24483
24515
  payee = incomePayee;
24484
24516
  }
24485
24517
  else {
@@ -24497,17 +24529,17 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24497
24529
  amount = integer(50000, 70000);
24498
24530
  }
24499
24531
  else {
24500
- amount = integer(0, (0, _random__WEBPACK_IMPORTED_MODULE_11__.random)() < 0.05 ? -8000 : -700);
24532
+ amount = integer(0, (0, _random__WEBPACK_IMPORTED_MODULE_10__.random)() < 0.05 ? -8000 : -700);
24501
24533
  }
24502
24534
  const transaction = {
24503
24535
  amount,
24504
24536
  payee: payee.id,
24505
24537
  account: account.id,
24506
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), Math.floor(i / 3)),
24538
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), Math.floor(i / 3)),
24507
24539
  category: category.id
24508
24540
  };
24509
24541
  transactions.push(transaction);
24510
- if ((0, _random__WEBPACK_IMPORTED_MODULE_11__.random)() < 0.2) {
24542
+ if ((0, _random__WEBPACK_IMPORTED_MODULE_10__.random)() < 0.2) {
24511
24543
  const a = Math.round(transaction.amount / 3);
24512
24544
  const pick = () => payee === incomePayee ? incomeGroup.categories.find((c) => c.name === 'Income').id : pickRandom(expenseCategories).id;
24513
24545
  transaction.subtransactions = [
@@ -24526,12 +24558,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24526
24558
  ];
24527
24559
  }
24528
24560
  }
24529
- const earliestMonth = _shared_months__WEBPACK_IMPORTED_MODULE_9__.monthFromDate(transactions[transactions.length - 1].date);
24530
- const months = _shared_months__WEBPACK_IMPORTED_MODULE_9__.rangeInclusive(earliestMonth, _shared_months__WEBPACK_IMPORTED_MODULE_9__.currentMonth());
24531
- const currentDay = _shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay();
24561
+ const earliestMonth = _shared_months__WEBPACK_IMPORTED_MODULE_8__.monthFromDate(transactions[transactions.length - 1].date);
24562
+ const months = _shared_months__WEBPACK_IMPORTED_MODULE_8__.rangeInclusive(earliestMonth, _shared_months__WEBPACK_IMPORTED_MODULE_8__.currentMonth());
24563
+ const currentDay = _shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay();
24532
24564
  for (const month of months) {
24533
- let date = _shared_months__WEBPACK_IMPORTED_MODULE_9__.addDays(month, 12);
24534
- if (_shared_months__WEBPACK_IMPORTED_MODULE_9__.isBefore(date, currentDay)) {
24565
+ let date = _shared_months__WEBPACK_IMPORTED_MODULE_8__.addDays(month, 12);
24566
+ if (_shared_months__WEBPACK_IMPORTED_MODULE_8__.isBefore(date, currentDay)) {
24535
24567
  transactions.push({
24536
24568
  amount: -10000,
24537
24569
  payee: billPayees.find((p) => p.name.toLowerCase().includes('power')).id,
@@ -24540,8 +24572,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24540
24572
  category: billCategories.find((c) => c.name === 'Power').id
24541
24573
  });
24542
24574
  }
24543
- date = _shared_months__WEBPACK_IMPORTED_MODULE_9__.addDays(month, 18);
24544
- if (_shared_months__WEBPACK_IMPORTED_MODULE_9__.isBefore(date, currentDay)) {
24575
+ date = _shared_months__WEBPACK_IMPORTED_MODULE_8__.addDays(month, 18);
24576
+ if (_shared_months__WEBPACK_IMPORTED_MODULE_8__.isBefore(date, currentDay)) {
24545
24577
  transactions.push({
24546
24578
  amount: -9000,
24547
24579
  payee: billPayees.find((p) => p.name.toLowerCase().includes('water')).id,
@@ -24550,8 +24582,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24550
24582
  category: billCategories.find((c) => c.name === 'Water').id
24551
24583
  });
24552
24584
  }
24553
- date = _shared_months__WEBPACK_IMPORTED_MODULE_9__.addDays(month, 2);
24554
- if (_shared_months__WEBPACK_IMPORTED_MODULE_9__.isBefore(date, currentDay)) {
24585
+ date = _shared_months__WEBPACK_IMPORTED_MODULE_8__.addDays(month, 2);
24586
+ if (_shared_months__WEBPACK_IMPORTED_MODULE_8__.isBefore(date, currentDay)) {
24555
24587
  transactions.push({
24556
24588
  amount: -120000,
24557
24589
  payee: billPayees.find((p) => p.name.toLowerCase().includes('housy')).id,
@@ -24560,8 +24592,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24560
24592
  category: billCategories.find((c) => c.name === 'Mortgage').id
24561
24593
  });
24562
24594
  }
24563
- date = _shared_months__WEBPACK_IMPORTED_MODULE_9__.addDays(month, 20);
24564
- if (_shared_months__WEBPACK_IMPORTED_MODULE_9__.isBefore(date, currentDay)) {
24595
+ date = _shared_months__WEBPACK_IMPORTED_MODULE_8__.addDays(month, 20);
24596
+ if (_shared_months__WEBPACK_IMPORTED_MODULE_8__.isBefore(date, currentDay)) {
24565
24597
  transactions.push({
24566
24598
  amount: -6000,
24567
24599
  payee: billPayees.find((p) => p.name.toLowerCase().includes('internet')).id,
@@ -24570,8 +24602,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24570
24602
  category: billCategories.find((c) => c.name === 'Internet').id
24571
24603
  });
24572
24604
  }
24573
- date = _shared_months__WEBPACK_IMPORTED_MODULE_9__.addDays(month, 23);
24574
- if (_shared_months__WEBPACK_IMPORTED_MODULE_9__.isBefore(date, currentDay)) {
24605
+ date = _shared_months__WEBPACK_IMPORTED_MODULE_8__.addDays(month, 23);
24606
+ if (_shared_months__WEBPACK_IMPORTED_MODULE_8__.isBefore(date, currentDay)) {
24575
24607
  transactions.push({
24576
24608
  amount: -7500,
24577
24609
  payee: billPayees.find((p) => p.name.toLowerCase().includes('t-mobile')).id,
@@ -24603,7 +24635,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24603
24635
  const transactions = [];
24604
24636
  for (let i = 0; i < numTransactions; i++) {
24605
24637
  let payee;
24606
- if ((0, _random__WEBPACK_IMPORTED_MODULE_11__.random)() < 0.04) {
24638
+ if ((0, _random__WEBPACK_IMPORTED_MODULE_10__.random)() < 0.04) {
24607
24639
  payee = incomePayee;
24608
24640
  }
24609
24641
  else {
@@ -24621,7 +24653,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24621
24653
  amount,
24622
24654
  payee: payee.id,
24623
24655
  account: account.id,
24624
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), i * 2),
24656
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), i * 2),
24625
24657
  category: category.id
24626
24658
  });
24627
24659
  }
@@ -24650,7 +24682,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24650
24682
  amount,
24651
24683
  payee: payee.id,
24652
24684
  account: account.id,
24653
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), integer(10, 360)),
24685
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), integer(10, 360)),
24654
24686
  category: category.id
24655
24687
  });
24656
24688
  }
@@ -24673,7 +24705,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24673
24705
  const transactions = [];
24674
24706
  for (let i = 0; i < numTransactions; i++) {
24675
24707
  let payee;
24676
- if ((0, _random__WEBPACK_IMPORTED_MODULE_11__.random)() < 0.3) {
24708
+ if ((0, _random__WEBPACK_IMPORTED_MODULE_10__.random)() < 0.3) {
24677
24709
  payee = incomePayee;
24678
24710
  }
24679
24711
  else {
@@ -24685,7 +24717,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24685
24717
  amount,
24686
24718
  payee: payee.id,
24687
24719
  account: account.id,
24688
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), i * 5),
24720
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), i * 5),
24689
24721
  category: category.id
24690
24722
  });
24691
24723
  }
@@ -24712,7 +24744,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24712
24744
  amount: integer(-3000, -3500) * 100 * 100,
24713
24745
  payee: payees.find((p) => p.name === 'Starting Balance').id,
24714
24746
  account: account.id,
24715
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), numTransactions) + '-02',
24747
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), numTransactions) + '-02',
24716
24748
  category: getStartingBalanceCat(incomeGroup.categories),
24717
24749
  starting_balance_flag: true
24718
24750
  }
@@ -24723,7 +24755,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24723
24755
  amount,
24724
24756
  payee: payee.id,
24725
24757
  account: account.id,
24726
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), i) + '-02',
24758
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), i) + '-02',
24727
24759
  category: category.id,
24728
24760
  starting_balance_flag: true
24729
24761
  });
@@ -24742,7 +24774,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24742
24774
  amount: integer(3250, 3700) * 100 * 100,
24743
24775
  payee: payees.find((p) => p.name === 'Starting Balance').id,
24744
24776
  account: account.id,
24745
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), numTransactions) + '-02',
24777
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), numTransactions) + '-02',
24746
24778
  category: getStartingBalanceCat(incomeGroup.categories),
24747
24779
  starting_balance_flag: true
24748
24780
  }
@@ -24754,7 +24786,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24754
24786
  amount,
24755
24787
  payee: payee.id,
24756
24788
  account: account.id,
24757
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), i) + '-02',
24789
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subMonths(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), i) + '-02',
24758
24790
  category: category.id
24759
24791
  });
24760
24792
  }
@@ -24771,9 +24803,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24771
24803
  WHERE a.id = ? AND a.offbudget = 0 AND t.is_child = 0 ORDER BY date ASC LIMIT 1`, [
24772
24804
  primaryAccount.id
24773
24805
  ])).date;
24774
- const start = _shared_months__WEBPACK_IMPORTED_MODULE_9__.monthFromDate(_server_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(earliestDate));
24775
- const end = _shared_months__WEBPACK_IMPORTED_MODULE_9__.currentMonth();
24776
- const months = _shared_months__WEBPACK_IMPORTED_MODULE_9__.rangeInclusive(start, end);
24806
+ const start = _shared_months__WEBPACK_IMPORTED_MODULE_8__.monthFromDate(_server_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(earliestDate));
24807
+ const end = _shared_months__WEBPACK_IMPORTED_MODULE_8__.currentMonth();
24808
+ const months = _shared_months__WEBPACK_IMPORTED_MODULE_8__.rangeInclusive(start, end);
24777
24809
  function category(name) {
24778
24810
  for (const group of groups) {
24779
24811
  const cat = group.categories.find((c) => c.name === name);
@@ -24790,14 +24822,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24790
24822
  });
24791
24823
  }
24792
24824
  function setBudgetIfSpent(month, cat) {
24793
- const spent = _server_sheet__WEBPACK_IMPORTED_MODULE_7__.getCellValue(_shared_months__WEBPACK_IMPORTED_MODULE_9__.sheetForMonth(month), `sum-amount-${cat.id}`);
24825
+ const spent = _server_sheet__WEBPACK_IMPORTED_MODULE_6__.getCellValue(_shared_months__WEBPACK_IMPORTED_MODULE_8__.sheetForMonth(month), `sum-amount-${cat.id}`);
24794
24826
  if (spent < 0) {
24795
24827
  setBudget(month, cat, -spent);
24796
24828
  }
24797
24829
  }
24798
- await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.batchMessages)(async () => {
24830
+ await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.batchMessages)(async () => {
24799
24831
  for (const month of months) {
24800
- if (month >= _shared_months__WEBPACK_IMPORTED_MODULE_9__.monthFromDate(_server_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(earliestPrimaryDate))) {
24832
+ if (month >= _shared_months__WEBPACK_IMPORTED_MODULE_8__.monthFromDate(_server_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(earliestPrimaryDate))) {
24801
24833
  setBudget(month, category('Food'), 40000);
24802
24834
  setBudget(month, category('Restaurants'), 30000);
24803
24835
  setBudget(month, category('Entertainment'), 10000);
@@ -24827,13 +24859,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24827
24859
  }
24828
24860
  }
24829
24861
  }));
24830
- await _server_sheet__WEBPACK_IMPORTED_MODULE_7__.waitOnSpreadsheet();
24831
- await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.batchMessages)(async () => {
24862
+ await _server_sheet__WEBPACK_IMPORTED_MODULE_6__.waitOnSpreadsheet();
24863
+ await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.batchMessages)(async () => {
24832
24864
  let prevSaved = 0;
24833
24865
  for (const month of months) {
24834
- if (month >= _shared_months__WEBPACK_IMPORTED_MODULE_9__.monthFromDate(_server_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(earliestPrimaryDate)) && month <= _shared_months__WEBPACK_IMPORTED_MODULE_9__.currentMonth()) {
24835
- const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_9__.sheetForMonth(month);
24836
- const toBudget = _server_sheet__WEBPACK_IMPORTED_MODULE_7__.getCellValue(sheetName, 'to-budget');
24866
+ if (month >= _shared_months__WEBPACK_IMPORTED_MODULE_8__.monthFromDate(_server_db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(earliestPrimaryDate)) && month <= _shared_months__WEBPACK_IMPORTED_MODULE_8__.currentMonth()) {
24867
+ const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_8__.sheetForMonth(month);
24868
+ const toBudget = _server_sheet__WEBPACK_IMPORTED_MODULE_6__.getCellValue(sheetName, 'to-budget');
24837
24869
  const available = toBudget - prevSaved;
24838
24870
  if (available - 403000 > 0) {
24839
24871
  setBudget(month, category('Savings'), available - 403000);
@@ -24846,25 +24878,25 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24846
24878
  }
24847
24879
  }
24848
24880
  }));
24849
- await _server_sheet__WEBPACK_IMPORTED_MODULE_7__.waitOnSpreadsheet();
24850
- const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_9__.sheetForMonth(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentMonth());
24851
- const toBudget = _server_sheet__WEBPACK_IMPORTED_MODULE_7__.getCellValue(sheetName, 'to-budget');
24881
+ await _server_sheet__WEBPACK_IMPORTED_MODULE_6__.waitOnSpreadsheet();
24882
+ const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_8__.sheetForMonth(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentMonth());
24883
+ const toBudget = _server_sheet__WEBPACK_IMPORTED_MODULE_6__.getCellValue(sheetName, 'to-budget');
24852
24884
  if (toBudget < 0) {
24853
24885
  await (0, _server_accounts_sync__WEBPACK_IMPORTED_MODULE_0__.addTransactions)(primaryAccount.id, [
24854
24886
  {
24855
24887
  amount: -toBudget,
24856
24888
  category: category('Income').id,
24857
- date: _shared_months__WEBPACK_IMPORTED_MODULE_9__.currentMonth() + '-01'
24889
+ date: _shared_months__WEBPACK_IMPORTED_MODULE_8__.currentMonth() + '-01'
24858
24890
  }
24859
24891
  ]);
24860
24892
  }
24861
24893
  // let sheetName = monthUtils.sheetForMonth(monthUtils.currentMonth());
24862
24894
  // let toBudget = sheet.getCellValue(sheetName, 'to-budget');
24863
24895
  // setBudget(monthUtils.currentMonth(), category('Savings'), toBudget);
24864
- await _server_sheet__WEBPACK_IMPORTED_MODULE_7__.waitOnSpreadsheet();
24896
+ await _server_sheet__WEBPACK_IMPORTED_MODULE_6__.waitOnSpreadsheet();
24865
24897
  }
24866
24898
  async function createTestBudget(handlers) {
24867
- (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.setSyncingMode)('import');
24899
+ (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.setSyncingMode)('import');
24868
24900
  await _server_db__WEBPACK_IMPORTED_MODULE_4__.execQuery('PRAGMA journal_mode = OFF');
24869
24901
  // Clear out the default categories. This is fine to do without
24870
24902
  // going through the sync system because we are in import mode and
@@ -24949,7 +24981,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
24949
24981
  bill: true
24950
24982
  }
24951
24983
  ];
24952
- await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.batchMessages)(async () => {
24984
+ await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.batchMessages)(async () => {
24953
24985
  for (const payee of payees) {
24954
24986
  payee.id = await handlers['payee-create']({
24955
24987
  name: payee.name
@@ -25041,8 +25073,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25041
25073
  }
25042
25074
  });
25043
25075
  const allGroups = (await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runHandler)(handlers['get-categories'])).grouped;
25044
- (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.setSyncingMode)('import');
25045
- await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.batchMessages)(async () => {
25076
+ (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.setSyncingMode)('import');
25077
+ await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.batchMessages)(async () => {
25046
25078
  for (const account of accounts) {
25047
25079
  if (account.name === 'Bank of America') {
25048
25080
  await fillPrimaryChecking(handlers, account, payees, allGroups);
@@ -25068,19 +25100,19 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25068
25100
  }
25069
25101
  }
25070
25102
  }));
25071
- (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.setSyncingMode)('import');
25103
+ (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.setSyncingMode)('import');
25072
25104
  // This checks to see if the primary account is in the negative.
25073
25105
  // This might happen depending on the transactions added, but we
25074
25106
  // don't want to show that as it'd be weird. We modify the latest
25075
25107
  // deposit transaction to force it to be positive
25076
25108
  const primaryAccount = accounts.find((a) => a.name = 'Bank of America');
25077
- const { data: primaryBalance } = await (0, _server_aql__WEBPACK_IMPORTED_MODULE_1__.runQuery)((0, _shared_query__WEBPACK_IMPORTED_MODULE_10__.q)('transactions').filter({
25109
+ const { data: primaryBalance } = await (0, _server_aql__WEBPACK_IMPORTED_MODULE_1__.runQuery)((0, _shared_query__WEBPACK_IMPORTED_MODULE_9__.q)('transactions').filter({
25078
25110
  account: primaryAccount.id
25079
25111
  }).calculate({
25080
25112
  $sum: '$amount'
25081
25113
  }).serialize());
25082
25114
  if (primaryBalance < 0) {
25083
- const { data: results } = await (0, _server_aql__WEBPACK_IMPORTED_MODULE_1__.runQuery)((0, _shared_query__WEBPACK_IMPORTED_MODULE_10__.q)('transactions').filter({
25115
+ const { data: results } = await (0, _server_aql__WEBPACK_IMPORTED_MODULE_1__.runQuery)((0, _shared_query__WEBPACK_IMPORTED_MODULE_9__.q)('transactions').filter({
25084
25116
  account: primaryAccount.id,
25085
25117
  amount: {
25086
25118
  $gt: 0
@@ -25096,15 +25128,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25096
25128
  });
25097
25129
  }
25098
25130
  // Bust the cache and reload the spreadsheet
25099
- (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.setSyncingMode)('disabled');
25100
- await _server_prefs__WEBPACK_IMPORTED_MODULE_6__.savePrefs({
25101
- isCached: false
25102
- });
25103
- await _server_sheet__WEBPACK_IMPORTED_MODULE_7__.reloadSpreadsheet(_server_db__WEBPACK_IMPORTED_MODULE_4__);
25131
+ (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.setSyncingMode)('disabled');
25132
+ await _server_sheet__WEBPACK_IMPORTED_MODULE_6__.reloadSpreadsheet(_server_db__WEBPACK_IMPORTED_MODULE_4__);
25104
25133
  await _server_budget_base__WEBPACK_IMPORTED_MODULE_3__.createAllBudgets();
25105
- await _server_sheet__WEBPACK_IMPORTED_MODULE_7__.waitOnSpreadsheet();
25134
+ await _server_sheet__WEBPACK_IMPORTED_MODULE_6__.waitOnSpreadsheet();
25106
25135
  // Create some schedules
25107
- await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_8__.batchMessages)(async () => {
25136
+ await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runMutator)(() => (0, _server_sync__WEBPACK_IMPORTED_MODULE_7__.batchMessages)(async () => {
25108
25137
  const account = accounts.find((acc) => acc.name === 'Bank of America');
25109
25138
  await (0, _server_mutators__WEBPACK_IMPORTED_MODULE_5__.runHandler)(handlers['schedule/create'], {
25110
25139
  schedule: {
@@ -25126,7 +25155,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25126
25155
  op: 'is',
25127
25156
  field: 'date',
25128
25157
  value: {
25129
- start: _shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(),
25158
+ start: _shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(),
25130
25159
  frequency: 'monthly',
25131
25160
  patterns: [],
25132
25161
  skipWeekend: false,
@@ -25159,7 +25188,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25159
25188
  {
25160
25189
  op: 'is',
25161
25190
  field: 'date',
25162
- value: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), 1)
25191
+ value: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), 1)
25163
25192
  },
25164
25193
  {
25165
25194
  op: 'isapprox',
@@ -25178,7 +25207,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25178
25207
  op: 'is',
25179
25208
  field: 'date',
25180
25209
  value: {
25181
- start: _shared_months__WEBPACK_IMPORTED_MODULE_9__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), 3),
25210
+ start: _shared_months__WEBPACK_IMPORTED_MODULE_8__.subDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), 3),
25182
25211
  frequency: 'monthly',
25183
25212
  patterns: [],
25184
25213
  skipWeekend: false,
@@ -25207,7 +25236,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25207
25236
  op: 'is',
25208
25237
  field: 'date',
25209
25238
  value: {
25210
- start: _shared_months__WEBPACK_IMPORTED_MODULE_9__.addDays(_shared_months__WEBPACK_IMPORTED_MODULE_9__.currentDay(), 1),
25239
+ start: _shared_months__WEBPACK_IMPORTED_MODULE_8__.addDays(_shared_months__WEBPACK_IMPORTED_MODULE_8__.currentDay(), 1),
25211
25240
  frequency: 'monthly',
25212
25241
  patterns: [],
25213
25242
  skipWeekend: false,
@@ -25661,8 +25690,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25661
25690
  });
25662
25691
  /* harmony import */ var better_sqlite3__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! better-sqlite3 */ "better-sqlite3");
25663
25692
  /* harmony import */ var better_sqlite3__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/ __webpack_require__.n(better_sqlite3__WEBPACK_IMPORTED_MODULE_0__);
25664
- /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
25693
+ /* harmony import */ var uuid__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! uuid */ "./node_modules/uuid/dist/esm-node/v4.js");
25665
25694
  /* harmony import */ var _fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../fs */ "./packages/loot-core/src/platform/server/fs/index.electron.ts");
25695
+ /* harmony import */ var _normalise__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./normalise */ "./packages/loot-core/src/platform/server/sqlite/normalise.ts");
25696
+ /* harmony import */ var _unicodeLike__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./unicodeLike */ "./packages/loot-core/src/platform/server/sqlite/unicodeLike.ts");
25666
25697
  // @ts-strict-ignore
25667
25698
  function verifyParamTypes(sql, arr) {
25668
25699
  arr.forEach((val) => {
@@ -25745,9 +25776,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25745
25776
  }
25746
25777
  }
25747
25778
  }
25779
+ function regexp(regex, text) {
25780
+ return new RegExp(regex).test(text) ? 1 : 0;
25781
+ }
25748
25782
  function openDatabase(pathOrBuffer) {
25749
25783
  const db = new (better_sqlite3__WEBPACK_IMPORTED_MODULE_0___default())(pathOrBuffer);
25750
- // Define Unicode-aware LOWER and UPPER implementation.
25784
+ // Define Unicode-aware LOWER, UPPER, and LIKE implementation.
25751
25785
  // This is necessary because better-sqlite3 uses SQLite build without ICU support.
25752
25786
  // @ts-expect-error @types/better-sqlite3 does not support setting strict 3rd argument
25753
25787
  db.function('UNICODE_LOWER', {
@@ -25757,6 +25791,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25757
25791
  db.function('UNICODE_UPPER', {
25758
25792
  deterministic: true
25759
25793
  }, (arg) => arg?.toUpperCase());
25794
+ // @ts-expect-error @types/better-sqlite3 does not support setting strict 3rd argument
25795
+ db.function('UNICODE_LIKE', {
25796
+ deterministic: true
25797
+ }, _unicodeLike__WEBPACK_IMPORTED_MODULE_3__.unicodeLike);
25798
+ // @ts-expect-error @types/better-sqlite3 does not support setting strict 3rd argument
25799
+ db.function('REGEXP', {
25800
+ deterministic: true
25801
+ }, regexp);
25802
+ // @ts-expect-error @types/better-sqlite3 does not support setting strict 3rd argument
25803
+ db.function('NORMALISE', {
25804
+ deterministic: true
25805
+ }, _normalise__WEBPACK_IMPORTED_MODULE_2__.normalise);
25760
25806
  return db;
25761
25807
  }
25762
25808
  function closeDatabase(db) {
@@ -25765,7 +25811,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25765
25811
  async function exportDatabase(db) {
25766
25812
  // electron does not support better-sqlite serialize since v21
25767
25813
  // save to file and read in the raw data.
25768
- const name = `backup-for-export-${(0, uuid__WEBPACK_IMPORTED_MODULE_2__["default"])()}.db`;
25814
+ const name = `backup-for-export-${(0, uuid__WEBPACK_IMPORTED_MODULE_4__["default"])()}.db`;
25769
25815
  await db.backup(name);
25770
25816
  const data = await (0, _fs__WEBPACK_IMPORTED_MODULE_1__.readFile)(name, 'binary');
25771
25817
  await (0, _fs__WEBPACK_IMPORTED_MODULE_1__.removeFile)(name);
@@ -25773,6 +25819,63 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25773
25819
  }
25774
25820
  /***/
25775
25821
  }),
25822
+ /***/ "./packages/loot-core/src/platform/server/sqlite/normalise.ts":
25823
+ /*!********************************************************************!*\
25824
+ !*** ./packages/loot-core/src/platform/server/sqlite/normalise.ts ***!
25825
+ \********************************************************************/
25826
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
25827
+ "use strict";
25828
+ __webpack_require__.r(__webpack_exports__);
25829
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
25830
+ /* harmony export */ normalise: () => ( /* binding */normalise)
25831
+ /* harmony export */
25832
+ });
25833
+ /* harmony import */ var _shared_normalisation__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../shared/normalisation */ "./packages/loot-core/src/shared/normalisation.ts");
25834
+ function normalise(value) {
25835
+ if (!value) {
25836
+ return null;
25837
+ }
25838
+ return (0, _shared_normalisation__WEBPACK_IMPORTED_MODULE_0__.getNormalisedString)(value);
25839
+ }
25840
+ /***/
25841
+ }),
25842
+ /***/ "./packages/loot-core/src/platform/server/sqlite/unicodeLike.ts":
25843
+ /*!**********************************************************************!*\
25844
+ !*** ./packages/loot-core/src/platform/server/sqlite/unicodeLike.ts ***!
25845
+ \**********************************************************************/
25846
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
25847
+ "use strict";
25848
+ __webpack_require__.r(__webpack_exports__);
25849
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
25850
+ /* harmony export */ unicodeLike: () => ( /* binding */unicodeLike)
25851
+ /* harmony export */
25852
+ });
25853
+ /* harmony import */ var lru_cache__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! lru-cache */ "./node_modules/lru-cache/index.js");
25854
+ /* harmony import */ var lru_cache__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/ __webpack_require__.n(lru_cache__WEBPACK_IMPORTED_MODULE_0__);
25855
+ // @ts-strict-ignore
25856
+ const likePatternCache = new (lru_cache__WEBPACK_IMPORTED_MODULE_0___default())({
25857
+ max: 500
25858
+ });
25859
+ function unicodeLike(pattern, value) {
25860
+ if (!pattern) {
25861
+ return 0;
25862
+ }
25863
+ if (!value) {
25864
+ value = '';
25865
+ }
25866
+ let cachedRegExp = likePatternCache.get(pattern);
25867
+ if (!cachedRegExp) {
25868
+ // we don't escape ? and % because we don't know
25869
+ // whether they originate from the user input or from our query compiler.
25870
+ // Maybe improve the query compiler to correctly process these characters?
25871
+ const processedPattern = pattern.replace(/[.*+^${}()|[\]\\]/g, '\\$&').replaceAll('?', '.').replaceAll('%', '.*');
25872
+ cachedRegExp = new RegExp(processedPattern, 'i');
25873
+ likePatternCache.set(pattern, cachedRegExp);
25874
+ }
25875
+ return cachedRegExp.test(value) ? 1 : 0;
25876
+ }
25877
+ /***/
25878
+ }),
25776
25879
  /***/ "./packages/loot-core/src/server/accounts/export-to-csv.ts":
25777
25880
  /*!*****************************************************************!*\
25778
25881
  !*** ./packages/loot-core/src/server/accounts/export-to-csv.ts ***!
@@ -25837,6 +25940,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25837
25940
  {
25838
25941
  IsParent: 'is_parent'
25839
25942
  },
25943
+ {
25944
+ IsChild: 'is_child'
25945
+ },
25946
+ {
25947
+ SortOrder: 'sort_order'
25948
+ },
25840
25949
  {
25841
25950
  Notes: 'notes'
25842
25951
  },
@@ -25855,23 +25964,28 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
25855
25964
  ]).options({
25856
25965
  splits: 'all'
25857
25966
  }));
25858
- const parentsPayees = new Map();
25967
+ // initialize a map to allow splits to have correct number of split from
25968
+ const parentsChildCount = new Map();
25969
+ const childSplitOrder = new Map();
25970
+ // find children, their order, and total # siblings
25859
25971
  for (const trans of transactions) {
25860
- if (trans.IsParent) {
25861
- parentsPayees.set(trans.Id, trans.Payee);
25972
+ if (trans.IsChild) {
25973
+ let childNumber = parentsChildCount.get(trans.ParentId) || 0;
25974
+ childNumber++;
25975
+ childSplitOrder.set(trans.Id, childNumber);
25976
+ parentsChildCount.set(trans.ParentId, childNumber);
25862
25977
  }
25863
25978
  }
25864
- // filter out any parent transactions
25865
- const noParents = transactions.filter((t) => !t.IsParent);
25866
- // map final properties for export and grab the payee for splits from their parent transaction
25867
- const transactionsForExport = noParents.map((trans) => {
25979
+ // map final properties for export and grab the child count for splits from their parent transaction
25980
+ const transactionsForExport = transactions.map((trans) => {
25868
25981
  return {
25869
25982
  Account: trans.Account,
25870
25983
  Date: trans.Date,
25871
- Payee: trans.ParentId ? parentsPayees.get(trans.ParentId) : trans.Payee,
25872
- Notes: trans.Notes,
25984
+ Payee: trans.Payee,
25985
+ Notes: trans.IsParent ? '(SPLIT INTO ' + parentsChildCount.get(trans.Id) + ') ' + (trans.Notes || '') : trans.IsChild ? '(SPLIT ' + childSplitOrder.get(trans.Id) + ' OF ' + parentsChildCount.get(trans.ParentId) + ') ' + (trans.Notes || '') : trans.Notes,
25873
25986
  Category: trans.Category,
25874
- Amount: trans.Amount == null ? 0 : (0, _shared_util__WEBPACK_IMPORTED_MODULE_1__.integerToAmount)(trans.Amount),
25987
+ Amount: trans.IsParent ? 0 : trans.Amount == null ? 0 : (0, _shared_util__WEBPACK_IMPORTED_MODULE_1__.integerToAmount)(trans.Amount),
25988
+ Split_Amount: trans.IsParent ? (0, _shared_util__WEBPACK_IMPORTED_MODULE_1__.integerToAmount)(trans.Amount) : 0,
25875
25989
  Cleared: trans.Reconciled === true ? 'Reconciled' : trans.Cleared === true ? 'Cleared' : 'Not cleared'
25876
25990
  };
25877
25991
  });
@@ -26480,6 +26594,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
26480
26594
  ops: [
26481
26595
  'is',
26482
26596
  'contains',
26597
+ 'matches',
26483
26598
  'oneOf',
26484
26599
  'isNot',
26485
26600
  'doesNotContain',
@@ -26498,6 +26613,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
26498
26613
  ops: [
26499
26614
  'is',
26500
26615
  'contains',
26616
+ 'matches',
26501
26617
  'oneOf',
26502
26618
  'isNot',
26503
26619
  'doesNotContain',
@@ -26509,7 +26625,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
26509
26625
  assert(Array.isArray(value), 'no-empty-array', `oneOf must have an array value (field: ${fieldName}): ${JSON.stringify(value)}`);
26510
26626
  return value.filter(Boolean).map((val) => val.toLowerCase());
26511
26627
  }
26512
- if (op === 'contains' || op === 'doesNotContain') {
26628
+ if (op === 'contains' || op === 'matches' || op === 'doesNotContain') {
26513
26629
  assert(typeof value === 'string' && value.length > 0, 'no-empty-string', `contains must have non-empty string (field: ${fieldName})`);
26514
26630
  }
26515
26631
  return value.toLowerCase();
@@ -26750,6 +26866,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
26750
26866
  this.field = null;
26751
26867
  this.type = 'id';
26752
26868
  }
26869
+ if (field === 'account') {
26870
+ assert(value, 'no-null', `Field cannot be empty: ${field}`);
26871
+ }
26753
26872
  this.op = op;
26754
26873
  this.rawValue = value;
26755
26874
  this.value = value;
@@ -27008,7 +27127,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27008
27127
  lt: 1,
27009
27128
  lte: 1,
27010
27129
  contains: 0,
27011
- doesNotContain: 0
27130
+ doesNotContain: 0,
27131
+ matches: 0
27012
27132
  };
27013
27133
  function computeScore(rule) {
27014
27134
  const initialScore = rule.conditions.reduce((score, condition) => {
@@ -27186,6 +27306,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27186
27306
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
27187
27307
  /* harmony export */ addTransactions: () => ( /* binding */addTransactions),
27188
27308
  /* harmony export */ getGoCardlessAccounts: () => ( /* binding */getGoCardlessAccounts),
27309
+ /* harmony export */ matchTransactions: () => ( /* binding */matchTransactions),
27189
27310
  /* harmony export */ reconcileTransactions: () => ( /* binding */reconcileTransactions),
27190
27311
  /* harmony export */ syncAccount: () => ( /* binding */syncAccount)
27191
27312
  /* harmony export */
@@ -27298,7 +27419,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27298
27419
  startDate: since
27299
27420
  }, {
27300
27421
  'X-ACTUAL-TOKEN': userToken
27301
- });
27422
+ }, 60000);
27302
27423
  if (res.error_code) {
27303
27424
  throw BankSyncError(res.error_type, res.error_code);
27304
27425
  }
@@ -27388,33 +27509,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27388
27509
  if (trans.date == null) {
27389
27510
  throw new Error('`date` is required when adding a transaction');
27390
27511
  }
27391
- let payee_name;
27392
- // When the amount is equal to 0, we need to determine
27393
- // if this is a "Credited" or "Debited" transaction. This means
27394
- // that it matters whether the amount is a positive or negative zero.
27395
- if (trans.amount > 0 || Object.is(Number(trans.amount), 0)) {
27396
- const nameParts = [];
27397
- const name = trans.debtorName || trans.remittanceInformationUnstructured || (trans.remittanceInformationUnstructuredArray || []).join(', ') || trans.additionalInformation;
27398
- if (name) {
27399
- nameParts.push((0, _title__WEBPACK_IMPORTED_MODULE_10__.title)(name));
27400
- }
27401
- if (trans.debtorAccount && trans.debtorAccount.iban) {
27402
- nameParts.push('(' + trans.debtorAccount.iban.slice(0, 4) + ' XXX ' + trans.debtorAccount.iban.slice(-4) + ')');
27403
- }
27404
- payee_name = nameParts.join(' ');
27405
- }
27406
- else {
27407
- const nameParts = [];
27408
- const name = trans.creditorName || trans.remittanceInformationUnstructured || (trans.remittanceInformationUnstructuredArray || []).join(', ') || trans.additionalInformation;
27409
- if (name) {
27410
- nameParts.push((0, _title__WEBPACK_IMPORTED_MODULE_10__.title)(name));
27411
- }
27412
- if (trans.creditorAccount && trans.creditorAccount.iban) {
27413
- nameParts.push('(' + trans.creditorAccount.iban.slice(0, 4) + ' XXX ' + trans.creditorAccount.iban.slice(-4) + ')');
27414
- }
27415
- payee_name = nameParts.join(' ');
27512
+ if (trans.payeeName == null) {
27513
+ throw new Error('`payeeName` is required when adding a transaction');
27416
27514
  }
27417
- trans.imported_payee = trans.imported_payee || payee_name;
27515
+ trans.imported_payee = trans.imported_payee || trans.payeeName;
27418
27516
  if (trans.imported_payee) {
27419
27517
  trans.imported_payee = trans.imported_payee.trim();
27420
27518
  }
@@ -27422,10 +27520,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27422
27520
  // when rules are run, they have the right data. Resolving payees
27423
27521
  // also simplifies the payee creation process
27424
27522
  trans.account = acctId;
27425
- trans.payee = await resolvePayee(trans, payee_name, payeesToCreate);
27523
+ trans.payee = await resolvePayee(trans, trans.payeeName, payeesToCreate);
27426
27524
  trans.cleared = Boolean(trans.booked);
27427
27525
  normalized.push({
27428
- payee_name,
27526
+ payee_name: trans.payeeName,
27429
27527
  trans: {
27430
27528
  amount: (0, _shared_util__WEBPACK_IMPORTED_MODULE_3__.amountToInteger)(trans.amount),
27431
27529
  payee: trans.payee,
@@ -27454,11 +27552,117 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27454
27552
  }
27455
27553
  });
27456
27554
  }
27457
- async function reconcileTransactions(acctId, transactions, isBankSyncAccount = false) {
27555
+ async function reconcileTransactions(acctId, transactions, isBankSyncAccount = false, isPreview = false) {
27458
27556
  console.log('Performing transaction reconciliation');
27459
- const hasMatched = new Set();
27460
27557
  const updated = [];
27461
27558
  const added = [];
27559
+ const updatedPreview = [];
27560
+ const existingPayeeMap = new Map();
27561
+ const { payeesToCreate, transactionsStep1, transactionsStep2, transactionsStep3 } = await matchTransactions(acctId, transactions, isBankSyncAccount);
27562
+ // Finally, generate & commit the changes
27563
+ for (const { trans, subtransactions, match } of transactionsStep3) {
27564
+ if (match && !trans.forceAddTransaction) {
27565
+ // Skip updating already reconciled (locked) transactions
27566
+ if (match.reconciled) {
27567
+ updatedPreview.push({
27568
+ transaction: trans,
27569
+ ignored: true
27570
+ });
27571
+ continue;
27572
+ }
27573
+ // TODO: change the above sql query to use aql
27574
+ const existing = {
27575
+ ...match,
27576
+ cleared: match.cleared === 1,
27577
+ date: _db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(match.date)
27578
+ };
27579
+ // Update the transaction
27580
+ const updates = {
27581
+ imported_id: trans.imported_id || null,
27582
+ payee: existing.payee || trans.payee || null,
27583
+ category: existing.category || trans.category || null,
27584
+ imported_payee: trans.imported_payee || null,
27585
+ notes: existing.notes || trans.notes || null,
27586
+ cleared: trans.cleared != null ? trans.cleared : true
27587
+ };
27588
+ if ((0, _shared_util__WEBPACK_IMPORTED_MODULE_3__.hasFieldsChanged)(existing, updates, Object.keys(updates))) {
27589
+ updated.push({
27590
+ id: existing.id,
27591
+ ...updates
27592
+ });
27593
+ if (!existingPayeeMap.has(existing.payee)) {
27594
+ const payee = await _db__WEBPACK_IMPORTED_MODULE_4__.getPayee(existing.payee);
27595
+ existingPayeeMap.set(existing.payee, payee?.name);
27596
+ }
27597
+ existing.payee_name = existingPayeeMap.get(existing.payee);
27598
+ existing.amount = (0, _shared_util__WEBPACK_IMPORTED_MODULE_3__.integerToAmount)(existing.amount);
27599
+ updatedPreview.push({
27600
+ transaction: trans,
27601
+ existing
27602
+ });
27603
+ }
27604
+ else {
27605
+ updatedPreview.push({
27606
+ transaction: trans,
27607
+ ignored: true
27608
+ });
27609
+ }
27610
+ if (existing.is_parent && existing.cleared !== updates.cleared) {
27611
+ const children = await _db__WEBPACK_IMPORTED_MODULE_4__.all('SELECT id FROM v_transactions WHERE parent_id = ?', [
27612
+ existing.id
27613
+ ]);
27614
+ for (const child of children) {
27615
+ updated.push({
27616
+ id: child.id,
27617
+ cleared: updates.cleared
27618
+ });
27619
+ }
27620
+ }
27621
+ }
27622
+ else {
27623
+ // Insert a new transaction
27624
+ const { forceAddTransaction, ...newTrans } = trans;
27625
+ const finalTransaction = {
27626
+ ...newTrans,
27627
+ id: (0, uuid__WEBPACK_IMPORTED_MODULE_13__["default"])(),
27628
+ category: trans.category || null,
27629
+ cleared: trans.cleared != null ? trans.cleared : true
27630
+ };
27631
+ if (subtransactions && subtransactions.length > 0) {
27632
+ added.push(...makeSplitTransaction(finalTransaction, subtransactions));
27633
+ }
27634
+ else {
27635
+ added.push(finalTransaction);
27636
+ }
27637
+ }
27638
+ }
27639
+ if (!isPreview) {
27640
+ await createNewPayees(payeesToCreate, [
27641
+ ...added,
27642
+ ...updated
27643
+ ]);
27644
+ await (0, _transactions__WEBPACK_IMPORTED_MODULE_12__.batchUpdateTransactions)({
27645
+ added,
27646
+ updated
27647
+ });
27648
+ }
27649
+ console.log('Debug data for the operations:', {
27650
+ transactionsStep1,
27651
+ transactionsStep2,
27652
+ transactionsStep3,
27653
+ added,
27654
+ updated,
27655
+ updatedPreview
27656
+ });
27657
+ return {
27658
+ added: added.map((trans) => trans.id),
27659
+ updated: updated.map((trans) => trans.id),
27660
+ updatedPreview
27661
+ };
27662
+ }
27663
+ async function matchTransactions(acctId, transactions, isBankSyncAccount = false) {
27664
+ console.log('Performing transaction reconciliation matching');
27665
+ const hasMatched = new Set();
27462
27666
  const transactionNormalization = isBankSyncAccount ? normalizeBankSyncTransactions : normalizeTransactions;
27463
27667
  const { normalized, payeesToCreate } = await transactionNormalization(transactions, acctId);
27464
27668
  // The first pass runs the rules, and preps data for fuzzy matching
@@ -27486,15 +27690,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27486
27690
  // needs to select all fields that need to be read from the
27487
27691
  // matched transaction. See the final pass below for the needed
27488
27692
  // fields.
27489
- fuzzyDataset = await _db__WEBPACK_IMPORTED_MODULE_4__.all(`SELECT id, is_parent, date, imported_id, payee, category, notes, reconciled FROM v_transactions
27490
- WHERE
27491
- -- If both ids are set, and we didn't match earlier then skip dedup
27492
- ( imported_id IS NULL OR ? IS NULL )
27493
- -- Look 7 days ahead, 7 days behind
27494
- AND date >= ? AND date <= ? AND amount = ?
27495
- AND account = ?
27496
- `, [
27497
- trans.imported_id || null,
27693
+ fuzzyDataset = await _db__WEBPACK_IMPORTED_MODULE_4__.all(`SELECT id, is_parent, date, imported_id, payee, imported_payee, category, notes, reconciled, cleared, amount FROM v_transactions
27694
+ WHERE date >= ? AND date <= ? AND amount = ? AND account = ?`, [
27498
27695
  _db__WEBPACK_IMPORTED_MODULE_4__.toDateRepr(_shared_months__WEBPACK_IMPORTED_MODULE_1__.subDays(trans.date, 7)),
27499
27696
  _db__WEBPACK_IMPORTED_MODULE_4__.toDateRepr(_shared_months__WEBPACK_IMPORTED_MODULE_1__.addDays(trans.date, 7)),
27500
27697
  trans.amount || 0,
@@ -27554,80 +27751,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
27554
27751
  }
27555
27752
  return data;
27556
27753
  });
27557
- // Finally, generate & commit the changes
27558
- for (const { trans, subtransactions, match } of transactionsStep3) {
27559
- if (match) {
27560
- // Skip updating already reconciled (locked) transactions
27561
- if (match.reconciled) {
27562
- continue;
27563
- }
27564
- // TODO: change the above sql query to use aql
27565
- const existing = {
27566
- ...match,
27567
- cleared: match.cleared === 1,
27568
- date: _db__WEBPACK_IMPORTED_MODULE_4__.fromDateRepr(match.date)
27569
- };
27570
- // Update the transaction
27571
- const updates = {
27572
- imported_id: trans.imported_id || null,
27573
- payee: existing.payee || trans.payee || null,
27574
- category: existing.category || trans.category || null,
27575
- imported_payee: trans.imported_payee || null,
27576
- notes: existing.notes || trans.notes || null,
27577
- cleared: trans.cleared != null ? trans.cleared : true
27578
- };
27579
- if ((0, _shared_util__WEBPACK_IMPORTED_MODULE_3__.hasFieldsChanged)(existing, updates, Object.keys(updates))) {
27580
- updated.push({
27581
- id: existing.id,
27582
- ...updates
27583
- });
27584
- }
27585
- if (existing.is_parent && existing.cleared !== updates.cleared) {
27586
- const children = await _db__WEBPACK_IMPORTED_MODULE_4__.all('SELECT id FROM v_transactions WHERE parent_id = ?', [
27587
- existing.id
27588
- ]);
27589
- for (const child of children) {
27590
- updated.push({
27591
- id: child.id,
27592
- cleared: updates.cleared
27593
- });
27594
- }
27595
- }
27596
- }
27597
- else {
27598
- // Insert a new transaction
27599
- const finalTransaction = {
27600
- ...trans,
27601
- id: (0, uuid__WEBPACK_IMPORTED_MODULE_13__["default"])(),
27602
- category: trans.category || null,
27603
- cleared: trans.cleared != null ? trans.cleared : true
27604
- };
27605
- if (subtransactions && subtransactions.length > 0) {
27606
- added.push(...makeSplitTransaction(finalTransaction, subtransactions));
27607
- }
27608
- else {
27609
- added.push(finalTransaction);
27610
- }
27611
- }
27612
- }
27613
- await createNewPayees(payeesToCreate, [
27614
- ...added,
27615
- ...updated
27616
- ]);
27617
- await (0, _transactions__WEBPACK_IMPORTED_MODULE_12__.batchUpdateTransactions)({
27618
- added,
27619
- updated
27620
- });
27621
- console.log('Debug data for the operations:', {
27754
+ return {
27755
+ payeesToCreate,
27622
27756
  transactionsStep1,
27623
27757
  transactionsStep2,
27624
- transactionsStep3,
27625
- added,
27626
- updated
27627
- });
27628
- return {
27629
- added: added.map((trans) => trans.id),
27630
- updated: updated.map((trans) => trans.id)
27758
+ transactionsStep3
27631
27759
  };
27632
27760
  }
27633
27761
  // This is similar to `reconcileTransactions` except much simpler: it
@@ -28466,6 +28594,10 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
28466
28594
  // Running contains with id will automatically reach into
28467
28595
  // the `name` of the referenced table and do a string match
28468
28596
  return apply(type === 'id' ? field + '.name' : field, '$like', '%' + value + '%');
28597
+ case 'matches':
28598
+ // Running contains with id will automatically reach into
28599
+ // the `name` of the referenced table and do a regex match
28600
+ return apply(type === 'id' ? field + '.name' : field, '$regexp', value);
28469
28601
  case 'doesNotContain':
28470
28602
  // Running contains with id will automatically reach into
28471
28603
  // the `name` of the referenced table and do a string match
@@ -28978,6 +29110,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
28978
29110
  date: transaction.date,
28979
29111
  transfer_id: transaction.id,
28980
29112
  notes: transaction.notes || null,
29113
+ schedule: transaction.schedule,
28981
29114
  cleared: false
28982
29115
  });
28983
29116
  await _db__WEBPACK_IMPORTED_MODULE_0__.updateTransaction({
@@ -29035,7 +29168,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29035
29168
  payee: payee.id,
29036
29169
  date: transaction.date,
29037
29170
  notes: transaction.notes,
29038
- amount: -transaction.amount
29171
+ amount: -transaction.amount,
29172
+ schedule: transaction.schedule
29039
29173
  });
29040
29174
  const categoryCleared = await clearCategory(transaction, transferredAccount);
29041
29175
  if (categoryCleared) {
@@ -29126,6 +29260,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29126
29260
  return isNaN(number) ? null : number;
29127
29261
  }
29128
29262
  function getDtOrDtTm(Date) {
29263
+ if (!Date) {
29264
+ return null;
29265
+ }
29129
29266
  if ('DtTm' in Date) {
29130
29267
  return Date.DtTm.slice(0, 10);
29131
29268
  }
@@ -29204,9 +29341,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29204
29341
  __webpack_require__.r(__webpack_exports__);
29205
29342
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
29206
29343
  /* harmony export */ accountModel: () => ( /* binding */accountModel),
29344
+ /* harmony export */ budgetModel: () => ( /* binding */budgetModel),
29207
29345
  /* harmony export */ categoryGroupModel: () => ( /* binding */categoryGroupModel),
29208
29346
  /* harmony export */ categoryModel: () => ( /* binding */categoryModel),
29209
- /* harmony export */ payeeModel: () => ( /* binding */payeeModel)
29347
+ /* harmony export */ payeeModel: () => ( /* binding */payeeModel),
29348
+ /* harmony export */ remoteFileModel: () => ( /* binding */remoteFileModel)
29210
29349
  /* harmony export */
29211
29350
  });
29212
29351
  /* harmony import */ var _models__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./models */ "./packages/loot-core/src/server/models.ts");
@@ -29287,6 +29426,36 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29287
29426
  return payee;
29288
29427
  }
29289
29428
  };
29429
+ const remoteFileModel = {
29430
+ toExternal(file) {
29431
+ if (file.deleted) {
29432
+ return null;
29433
+ }
29434
+ return {
29435
+ cloudFileId: file.fileId,
29436
+ state: 'remote',
29437
+ groupId: file.groupId,
29438
+ name: file.name,
29439
+ encryptKeyId: file.encryptKeyId,
29440
+ hasKey: file.hasKey
29441
+ };
29442
+ },
29443
+ fromExternal(file) {
29444
+ return {
29445
+ deleted: false,
29446
+ fileId: file.cloudFileId,
29447
+ ...file
29448
+ };
29449
+ }
29450
+ };
29451
+ const budgetModel = {
29452
+ toExternal(file) {
29453
+ return file;
29454
+ },
29455
+ fromExternal(file) {
29456
+ return file;
29457
+ }
29458
+ };
29290
29459
  /***/
29291
29460
  }),
29292
29461
  /***/ "./packages/loot-core/src/server/api.ts":
@@ -29486,6 +29655,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29486
29655
  id: result.id
29487
29656
  });
29488
29657
  };
29658
+ handlers['api/get-budgets'] = async function () {
29659
+ const budgets = await handlers['get-budgets']();
29660
+ const files = await handlers['get-remote-files']() || [];
29661
+ return [
29662
+ ...budgets.map((file) => _api_models__WEBPACK_IMPORTED_MODULE_8__.budgetModel.toExternal(file)),
29663
+ ...files.map((file) => _api_models__WEBPACK_IMPORTED_MODULE_8__.remoteFileModel.toExternal(file)).filter((file) => file)
29664
+ ];
29665
+ };
29489
29666
  handlers['api/sync'] = async function () {
29490
29667
  const { id } = _prefs__WEBPACK_IMPORTED_MODULE_14__.getPrefs();
29491
29668
  const result = await handlers['sync-budget']();
@@ -29631,11 +29808,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29631
29808
  payees
29632
29809
  });
29633
29810
  };
29634
- handlers['api/transactions-import'] = withMutation(async function ({ accountId, transactions }) {
29811
+ handlers['api/transactions-import'] = withMutation(async function ({ accountId, transactions, isPreview = false }) {
29635
29812
  checkFileOpen();
29636
29813
  return handlers['transactions-import']({
29637
29814
  accountId,
29638
- transactions
29815
+ transactions,
29816
+ isPreview
29639
29817
  });
29640
29818
  });
29641
29819
  handlers['api/transactions-add'] = withMutation(async function ({ accountId, transactions, runTransfers = false, learnCategories = false }) {
@@ -29744,6 +29922,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29744
29922
  forced: true
29745
29923
  });
29746
29924
  });
29925
+ handlers['api/account-balance'] = withMutation(async function ({ id, cutoff = new Date() }) {
29926
+ checkFileOpen();
29927
+ return handlers['account-balance']({
29928
+ id,
29929
+ cutoff
29930
+ });
29931
+ });
29747
29932
  handlers['api/categories-get'] = async function ({ grouped } = {}) {
29748
29933
  checkFileOpen();
29749
29934
  const result = await handlers['get-categories']();
@@ -29796,6 +29981,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29796
29981
  transferId: transferCategoryId
29797
29982
  });
29798
29983
  });
29984
+ handlers['api/common-payees-get'] = async function () {
29985
+ checkFileOpen();
29986
+ const payees = await handlers['common-payees-get']();
29987
+ return payees.map(_api_models__WEBPACK_IMPORTED_MODULE_8__.payeeModel.toExternal);
29988
+ };
29799
29989
  handlers['api/payees-get'] = async function () {
29800
29990
  checkFileOpen();
29801
29991
  const payees = await handlers['payees-get']();
@@ -29828,6 +30018,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29828
30018
  ]
29829
30019
  });
29830
30020
  });
30021
+ handlers['api/payees-merge'] = withMutation(async function ({ targetId, mergeIds }) {
30022
+ checkFileOpen();
30023
+ return handlers['payees-merge']({
30024
+ targetId,
30025
+ mergeIds
30026
+ });
30027
+ });
29831
30028
  handlers['api/rules-get'] = async function () {
29832
30029
  checkFileOpen();
29833
30030
  return handlers['rules-get']();
@@ -29949,6 +30146,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
29949
30146
  /* harmony export */ quoteAlias: () => ( /* binding */quoteAlias)
29950
30147
  /* harmony export */
29951
30148
  });
30149
+ /* harmony import */ var _shared_normalisation__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../shared/normalisation */ "./packages/loot-core/src/shared/normalisation.ts");
29952
30150
  // @ts-strict-ignore
29953
30151
  let _uid = 0;
29954
30152
  function resetUid() {
@@ -30690,7 +30888,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
30690
30888
  'string',
30691
30889
  'string'
30692
30890
  ]);
30693
- return `${left} LIKE ${right}`;
30891
+ return `UNICODE_LIKE(${(0, _shared_normalisation__WEBPACK_IMPORTED_MODULE_0__.getNormalisedString)(right)}, NORMALISE(${left}))`;
30892
+ }
30893
+ case '$regexp':
30894
+ {
30895
+ const [left, right] = valArray(state, [
30896
+ lhs,
30897
+ rhs
30898
+ ], [
30899
+ 'string',
30900
+ 'string'
30901
+ ]);
30902
+ return `REGEXP(${right}, ${left})`;
30694
30903
  }
30695
30904
  case '$notlike':
30696
30905
  {
@@ -30701,7 +30910,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
30701
30910
  'string',
30702
30911
  'string'
30703
30912
  ]);
30704
- return `(${left} NOT LIKE ${right}\n OR ${left} IS NULL)`;
30913
+ return `(NOT UNICODE_LIKE(${(0, _shared_normalisation__WEBPACK_IMPORTED_MODULE_0__.getNormalisedString)(right)}, NORMALISE(${left}))\n OR ${left} IS NULL)`;
30705
30914
  }
30706
30915
  default:
30707
30916
  throw new CompileError(`Unknown operator: ${op}`);
@@ -31636,7 +31845,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31636
31845
  transfer_acct: f('id', {
31637
31846
  ref: 'accounts'
31638
31847
  }),
31639
- tombstone: f('boolean')
31848
+ tombstone: f('boolean'),
31849
+ favorite: f('boolean')
31640
31850
  },
31641
31851
  accounts: {
31642
31852
  id: f('id'),
@@ -31647,6 +31857,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31647
31857
  closed: f('boolean'),
31648
31858
  sort_order: f('float'),
31649
31859
  tombstone: f('boolean'),
31860
+ account_id: f('string'),
31861
+ official_name: f('string'),
31650
31862
  account_sync_source: f('string')
31651
31863
  },
31652
31864
  categories: {
@@ -31746,6 +31958,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31746
31958
  show_uncategorized: f('integer', {
31747
31959
  default: 0
31748
31960
  }),
31961
+ include_current: f('integer', {
31962
+ default: 0
31963
+ }),
31749
31964
  selected_categories: f('json'),
31750
31965
  graph_type: f('string', {
31751
31966
  default: 'BarGraph'
@@ -31765,7 +31980,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31765
31980
  category: f('string'),
31766
31981
  amount: f('integer'),
31767
31982
  carryover: f('integer'),
31768
- goal: f('integer')
31983
+ goal: f('integer'),
31984
+ long_goal: f('integer')
31769
31985
  },
31770
31986
  zero_budgets: {
31771
31987
  id: f('id'),
@@ -31773,7 +31989,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
31773
31989
  category: f('string'),
31774
31990
  amount: f('integer'),
31775
31991
  carryover: f('integer'),
31776
- goal: f('integer')
31992
+ goal: f('integer'),
31993
+ long_goal: f('integer')
31777
31994
  }
31778
31995
  };
31779
31996
  const schemaConfig = {
@@ -32158,7 +32375,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32158
32375
  }
32159
32376
  return backups.map((backup) => ({
32160
32377
  ...backup,
32161
- date: backup.date ? date_fns__WEBPACK_IMPORTED_MODULE_6__["default"](backup.date, 'yyyy-MM-dd h:mm') : null
32378
+ date: backup.date ? date_fns__WEBPACK_IMPORTED_MODULE_6__["default"](backup.date, 'yyyy-MM-dd H:mm') : null
32162
32379
  }));
32163
32380
  }
32164
32381
  async function updateBackups(backups) {
@@ -32283,6 +32500,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32283
32500
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
32284
32501
  /* harmony export */ copyPreviousMonth: () => ( /* binding */copyPreviousMonth),
32285
32502
  /* harmony export */ copySinglePreviousMonth: () => ( /* binding */copySinglePreviousMonth),
32503
+ /* harmony export */ coverOverbudgeted: () => ( /* binding */coverOverbudgeted),
32286
32504
  /* harmony export */ coverOverspending: () => ( /* binding */coverOverspending),
32287
32505
  /* harmony export */ getBudget: () => ( /* binding */getBudget),
32288
32506
  /* harmony export */ getSheetValue: () => ( /* binding */getSheetValue),
@@ -32378,7 +32596,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32378
32596
  amount
32379
32597
  });
32380
32598
  }
32381
- function setGoal({ month, category, goal }) {
32599
+ function setGoal({ month, category, goal, long_goal }) {
32382
32600
  const table = getBudgetTable();
32383
32601
  const existing = _db__WEBPACK_IMPORTED_MODULE_2__.firstSync(`SELECT id FROM ${table} WHERE month = ? AND category = ?`, [
32384
32602
  dbMonth(month),
@@ -32387,14 +32605,16 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32387
32605
  if (existing) {
32388
32606
  return _db__WEBPACK_IMPORTED_MODULE_2__.update(table, {
32389
32607
  id: existing.id,
32390
- goal
32608
+ goal,
32609
+ long_goal
32391
32610
  });
32392
32611
  }
32393
32612
  return _db__WEBPACK_IMPORTED_MODULE_2__.insert(table, {
32394
32613
  id: `${dbMonth(month)}-${category}`,
32395
32614
  month: dbMonth(month),
32396
32615
  category,
32397
- goal
32616
+ goal,
32617
+ long_goal
32398
32618
  });
32399
32619
  }
32400
32620
  function setBuffer(month, amount) {
@@ -32487,16 +32707,22 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32487
32707
  const spent1 = await getSheetValue(_shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(prevMonth1), 'sum-amount-' + cat.id);
32488
32708
  const spent2 = await getSheetValue(_shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(prevMonth2), 'sum-amount-' + cat.id);
32489
32709
  const spent3 = await getSheetValue(_shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(prevMonth3), 'sum-amount-' + cat.id);
32490
- const avg = Math.round((spent1 + spent2 + spent3) / 3);
32710
+ let avg = Math.round((spent1 + spent2 + spent3) / 3);
32711
+ if (cat.is_income === 0) {
32712
+ avg *= -1;
32713
+ }
32491
32714
  setBudget({
32492
32715
  category: cat.id,
32493
32716
  month,
32494
- amount: -avg
32717
+ amount: avg
32495
32718
  });
32496
32719
  }
32497
32720
  });
32498
32721
  }
32499
32722
  async function setNMonthAvg({ month, N, category }) {
32723
+ const categoryFromDb = await _db__WEBPACK_IMPORTED_MODULE_2__.first('SELECT is_income FROM v_categories WHERE id = ?', [
32724
+ category
32725
+ ]);
32500
32726
  let prevMonth = _shared_months__WEBPACK_IMPORTED_MODULE_0__.prevMonth(month);
32501
32727
  let sumAmount = 0;
32502
32728
  for (let l = 0; l < N; l++) {
@@ -32504,11 +32730,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32504
32730
  prevMonth = _shared_months__WEBPACK_IMPORTED_MODULE_0__.prevMonth(prevMonth);
32505
32731
  }
32506
32732
  await (0, _sync__WEBPACK_IMPORTED_MODULE_5__.batchMessages)(async () => {
32507
- const avg = Math.round(sumAmount / N);
32733
+ let avg = Math.round(sumAmount / N);
32734
+ if (categoryFromDb.is_income === 0) {
32735
+ avg *= -1;
32736
+ }
32508
32737
  setBudget({
32509
32738
  category,
32510
32739
  month,
32511
- amount: -avg
32740
+ amount: avg
32512
32741
  });
32513
32742
  });
32514
32743
  }
@@ -32563,6 +32792,16 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32563
32792
  amount: budgeted + amount
32564
32793
  });
32565
32794
  }
32795
+ async function coverOverbudgeted({ month, category }) {
32796
+ const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(month);
32797
+ const toBudget = await getSheetValue(sheetName, 'to-budget');
32798
+ const categoryBudget = await getSheetValue(sheetName, 'budget-' + category);
32799
+ await setBudget({
32800
+ category,
32801
+ month,
32802
+ amount: categoryBudget + toBudget
32803
+ });
32804
+ }
32566
32805
  async function transferCategory({ month, amount, from, to }) {
32567
32806
  const sheetName = _shared_months__WEBPACK_IMPORTED_MODULE_0__.sheetForMonth(month);
32568
32807
  const fromBudgeted = await getSheetValue(sheetName, 'budget-' + from);
@@ -32626,6 +32865,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32626
32865
  app.method('budget/reset-hold', (0, _mutators__WEBPACK_IMPORTED_MODULE_1__.mutator)((0, _undo__WEBPACK_IMPORTED_MODULE_2__.undoable)(_actions__WEBPACK_IMPORTED_MODULE_3__.resetHold)));
32627
32866
  app.method('budget/cover-overspending', (0, _mutators__WEBPACK_IMPORTED_MODULE_1__.mutator)((0, _undo__WEBPACK_IMPORTED_MODULE_2__.undoable)(_actions__WEBPACK_IMPORTED_MODULE_3__.coverOverspending)));
32628
32867
  app.method('budget/transfer-available', (0, _mutators__WEBPACK_IMPORTED_MODULE_1__.mutator)((0, _undo__WEBPACK_IMPORTED_MODULE_2__.undoable)(_actions__WEBPACK_IMPORTED_MODULE_3__.transferAvailable)));
32868
+ app.method('budget/cover-overbudgeted', (0, _mutators__WEBPACK_IMPORTED_MODULE_1__.mutator)((0, _undo__WEBPACK_IMPORTED_MODULE_2__.undoable)(_actions__WEBPACK_IMPORTED_MODULE_3__.coverOverbudgeted)));
32629
32869
  app.method('budget/transfer-category', (0, _mutators__WEBPACK_IMPORTED_MODULE_1__.mutator)((0, _undo__WEBPACK_IMPORTED_MODULE_2__.undoable)(_actions__WEBPACK_IMPORTED_MODULE_3__.transferCategory)));
32630
32870
  app.method('budget/set-carryover', (0, _mutators__WEBPACK_IMPORTED_MODULE_1__.mutator)((0, _undo__WEBPACK_IMPORTED_MODULE_2__.undoable)(_actions__WEBPACK_IMPORTED_MODULE_3__.setCategoryCarryover)));
32631
32871
  /***/
@@ -32879,6 +33119,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
32879
33119
  _sheet__WEBPACK_IMPORTED_MODULE_3__.get().set(`${sheetName}!budget-${budget.category}`, budget.amount || 0);
32880
33120
  _sheet__WEBPACK_IMPORTED_MODULE_3__.get().set(`${sheetName}!carryover-${budget.category}`, budget.carryover === 1 ? true : false);
32881
33121
  _sheet__WEBPACK_IMPORTED_MODULE_3__.get().set(`${sheetName}!goal-${budget.category}`, budget.goal);
33122
+ _sheet__WEBPACK_IMPORTED_MODULE_3__.get().set(`${sheetName}!long-goal-${budget.category}`, budget.long_goal);
32882
33123
  }
32883
33124
  }
32884
33125
  function triggerBudgetChanges(oldValues, newValues) {
@@ -33188,7 +33429,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33188
33429
  await (0, _actions__WEBPACK_IMPORTED_MODULE_2__.setGoal)({
33189
33430
  category: category.id,
33190
33431
  month,
33191
- goal: budgeted - balance
33432
+ goal: budgeted - balance,
33433
+ long_goal: 0
33192
33434
  });
33193
33435
  num_sources += 1;
33194
33436
  }
@@ -33914,35 +34156,34 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33914
34156
  /* harmony import */ var _goals_goalsSpend__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./goals/goalsSpend */ "./packages/loot-core/src/server/budget/goals/goalsSpend.ts");
33915
34157
  /* harmony import */ var _goals_goalsWeek__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./goals/goalsWeek */ "./packages/loot-core/src/server/budget/goals/goalsWeek.ts");
33916
34158
  // @ts-strict-ignore
34159
+ const TEMPLATE_PREFIX = '#template';
34160
+ const GOAL_PREFIX = '#goal';
33917
34161
  async function applyTemplate({ month }) {
33918
34162
  await storeTemplates();
33919
- const category_templates = await getTemplates(null);
33920
- await resetCategoryTargets({
33921
- month,
33922
- category: null
33923
- });
33924
- return processTemplate(month, false, category_templates);
34163
+ const category_templates = await getTemplates(null, 'template');
34164
+ const category_goals = await getTemplates(null, 'goal');
34165
+ const ret = await processTemplate(month, false, category_templates);
34166
+ await processGoals(category_goals, month);
34167
+ return ret;
33925
34168
  }
33926
34169
  async function overwriteTemplate({ month }) {
33927
34170
  await storeTemplates();
33928
- const category_templates = await getTemplates(null);
33929
- await resetCategoryTargets({
33930
- month,
33931
- category: null
33932
- });
33933
- return processTemplate(month, true, category_templates);
34171
+ const category_templates = await getTemplates(null, 'template');
34172
+ const category_goals = await getTemplates(null, 'goal');
34173
+ const ret = await processTemplate(month, true, category_templates);
34174
+ await processGoals(category_goals, month);
34175
+ return ret;
33934
34176
  }
33935
34177
  async function applySingleCategoryTemplate({ month, category }) {
33936
34178
  const categories = await _db__WEBPACK_IMPORTED_MODULE_2__.all(`SELECT * FROM v_categories WHERE id = ?`, [
33937
34179
  category
33938
34180
  ]);
33939
34181
  await storeTemplates();
33940
- const category_templates = await getTemplates(categories[0]);
33941
- await resetCategoryTargets({
33942
- month,
33943
- category: categories
33944
- });
33945
- return processTemplate(month, true, category_templates);
34182
+ const category_templates = await getTemplates(categories[0], 'template');
34183
+ const category_goals = await getTemplates(categories[0], 'goal');
34184
+ const ret = await processTemplate(month, true, category_templates, categories[0]);
34185
+ await processGoals(category_goals, month, categories[0]);
34186
+ return ret;
33946
34187
  }
33947
34188
  function runCheckTemplates() {
33948
34189
  return checkTemplates();
@@ -33986,13 +34227,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
33986
34227
  (0, _actions__WEBPACK_IMPORTED_MODULE_4__.setGoal)({
33987
34228
  category: element.category,
33988
34229
  goal: element.amount,
33989
- month
34230
+ month,
34231
+ long_goal: 0
33990
34232
  });
33991
34233
  });
33992
34234
  });
33993
34235
  }
33994
- async function resetCategoryTargets({ month, category }) {
33995
- let categories;
34236
+ async function resetCategoryTargets(month, category) {
34237
+ let categories = [];
33996
34238
  if (category === null) {
33997
34239
  categories = await getCategories();
33998
34240
  }
@@ -34000,13 +34242,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34000
34242
  categories = category;
34001
34243
  }
34002
34244
  await (0, _sync__WEBPACK_IMPORTED_MODULE_3__.batchMessages)(async () => {
34003
- categories.forEach((element) => {
34245
+ for (let i = 0; i < categories.length; i++) {
34004
34246
  (0, _actions__WEBPACK_IMPORTED_MODULE_4__.setGoal)({
34005
- category: element.id,
34247
+ category: categories[i].id,
34006
34248
  goal: null,
34007
- month
34249
+ month,
34250
+ long_goal: null
34008
34251
  });
34009
- });
34252
+ }
34010
34253
  });
34011
34254
  }
34012
34255
  async function storeTemplates() {
@@ -34029,7 +34272,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34029
34272
  }
34030
34273
  }
34031
34274
  }
34032
- async function getTemplates(category) {
34275
+ async function getTemplates(category, directive) {
34033
34276
  //retrieves template definitions from the database
34034
34277
  const goal_def = await _db__WEBPACK_IMPORTED_MODULE_2__.all('SELECT * FROM categories WHERE goal_def IS NOT NULL');
34035
34278
  const templates = [];
@@ -34037,24 +34280,41 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34037
34280
  templates[goal_def[ll].id] = JSON.parse(goal_def[ll].goal_def);
34038
34281
  }
34039
34282
  if (category) {
34040
- const singleCategoryTemplate = {};
34283
+ const singleCategoryTemplate = [];
34041
34284
  if (templates[category.id] !== undefined) {
34042
- singleCategoryTemplate[category.id] = templates[category.id];
34285
+ singleCategoryTemplate[category.id] = templates[category.id].filter((t) => t.directive === directive);
34286
+ return singleCategoryTemplate;
34043
34287
  }
34288
+ singleCategoryTemplate[category.id] = undefined;
34044
34289
  return singleCategoryTemplate;
34045
34290
  }
34046
34291
  else {
34047
- return templates;
34292
+ const categories = await getCategories();
34293
+ const ret = [];
34294
+ for (let cc = 0; cc < categories.length; cc++) {
34295
+ const id = categories[cc].id;
34296
+ if (templates[id]) {
34297
+ ret[id] = templates[id];
34298
+ ret[id] = ret[id].filter((t) => t.directive === directive);
34299
+ }
34300
+ }
34301
+ return ret;
34048
34302
  }
34049
34303
  }
34050
- async function processTemplate(month, force, category_templates) {
34304
+ async function processTemplate(month, force, category_templates, category) {
34051
34305
  let num_applied = 0;
34052
34306
  let errors = [];
34053
34307
  const idealTemplate = [];
34054
34308
  const setToZero = [];
34055
34309
  let priority_list = [];
34056
- const categories = await getCategories();
34310
+ let categories = [];
34057
34311
  const categories_remove = [];
34312
+ if (category) {
34313
+ categories[0] = category;
34314
+ }
34315
+ else {
34316
+ categories = await getCategories();
34317
+ }
34058
34318
  //clears templated categories
34059
34319
  for (let c = 0; c < categories.length; c++) {
34060
34320
  const category = categories[c];
@@ -34075,13 +34335,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34075
34335
  categories_remove.push(c);
34076
34336
  }
34077
34337
  else {
34078
- // if we are overwritting add this category to list to zero
34079
- setToZero.push({
34080
- category: category.id,
34081
- amount: 0,
34082
- isIncome: category.is_income,
34083
- isTemplate: template ? true : false
34084
- });
34338
+ // add all categories with a template to the list to unset budget
34339
+ if (template?.length > 0) {
34340
+ setToZero.push({
34341
+ category: category.id
34342
+ });
34343
+ }
34085
34344
  }
34086
34345
  }
34087
34346
  }
@@ -34091,11 +34350,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34091
34350
  for (let i = categories_remove.length - 1; i >= 0; i--) {
34092
34351
  categories.splice(categories_remove[i], 1);
34093
34352
  }
34094
- // zero out the categories that need it
34353
+ // zero out budget and goal from categories that need it
34095
34354
  await setGoalBudget({
34096
34355
  month,
34097
- templateBudget: setToZero.filter((f) => f.isTemplate === true)
34356
+ templateBudget: setToZero
34098
34357
  });
34358
+ await resetCategoryTargets(month, categories);
34099
34359
  // sort and filter down to just the requested priorities
34100
34360
  priority_list = priority_list.sort(function (a, b) {
34101
34361
  return a - b;
@@ -34225,10 +34485,34 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34225
34485
  }
34226
34486
  }
34227
34487
  }
34228
- const TEMPLATE_PREFIX = '#template';
34488
+ async function processGoals(goals, month, category) {
34489
+ let categories = [];
34490
+ if (category) {
34491
+ categories[0] = category;
34492
+ }
34493
+ else {
34494
+ categories = await getCategories();
34495
+ }
34496
+ for (let c = 0; c < categories.length; c++) {
34497
+ const cat_id = categories[c].id;
34498
+ const goal_lines = goals[cat_id];
34499
+ if (goal_lines?.length > 0) {
34500
+ await (0, _actions__WEBPACK_IMPORTED_MODULE_4__.setGoal)({
34501
+ month,
34502
+ category: cat_id,
34503
+ goal: (0, _shared_util__WEBPACK_IMPORTED_MODULE_1__.amountToInteger)(goal_lines[0].amount),
34504
+ long_goal: 1
34505
+ });
34506
+ }
34507
+ }
34508
+ }
34229
34509
  async function getCategoryTemplates(category) {
34230
34510
  const templates = {};
34231
- let notes = await _db__WEBPACK_IMPORTED_MODULE_2__.all(`SELECT * FROM notes WHERE lower(note) like '%${TEMPLATE_PREFIX}%'`);
34511
+ let notes = await _db__WEBPACK_IMPORTED_MODULE_2__.all(`
34512
+ SELECT * FROM notes
34513
+ WHERE lower(note) like '%${TEMPLATE_PREFIX}%'
34514
+ OR lower(note) like '%${GOAL_PREFIX}%'
34515
+ `);
34232
34516
  if (category)
34233
34517
  notes = notes.filter((n) => n.id === category.id);
34234
34518
  for (let n = 0; n < notes.length; n++) {
@@ -34236,11 +34520,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
34236
34520
  const template_lines = [];
34237
34521
  for (let l = 0; l < lines.length; l++) {
34238
34522
  const line = lines[l].trim();
34239
- if (!line.toLowerCase().startsWith(TEMPLATE_PREFIX))
34523
+ if (!line.toLowerCase().startsWith(TEMPLATE_PREFIX) && !line.toLowerCase().startsWith(GOAL_PREFIX)) {
34240
34524
  continue;
34241
- const expression = line.slice(TEMPLATE_PREFIX.length);
34525
+ }
34242
34526
  try {
34243
- const parsed = (0, _goal_template_pegjs__WEBPACK_IMPORTED_MODULE_5__.parse)(expression);
34527
+ const parsed = (0, _goal_template_pegjs__WEBPACK_IMPORTED_MODULE_5__.parse)(line);
34244
34528
  template_lines.push(parsed);
34245
34529
  }
34246
34530
  catch (e) {
@@ -35192,6 +35476,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35192
35476
  /* harmony export */ getAccounts: () => ( /* binding */getAccounts),
35193
35477
  /* harmony export */ getCategories: () => ( /* binding */getCategories),
35194
35478
  /* harmony export */ getCategoriesGrouped: () => ( /* binding */getCategoriesGrouped),
35479
+ /* harmony export */ getCommonPayees: () => ( /* binding */getCommonPayees),
35195
35480
  /* harmony export */ getDatabase: () => ( /* binding */getDatabase),
35196
35481
  /* harmony export */ getDatabasePath: () => ( /* binding */getDatabasePath),
35197
35482
  /* harmony export */ getOrphanedPayees: () => ( /* binding */getOrphanedPayees),
@@ -35214,7 +35499,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35214
35499
  /* harmony export */ moveCategory: () => ( /* binding */moveCategory),
35215
35500
  /* harmony export */ moveCategoryGroup: () => ( /* binding */moveCategoryGroup),
35216
35501
  /* harmony export */ openDatabase: () => ( /* binding */openDatabase),
35217
- /* harmony export */ reopenDatabase: () => ( /* binding */reopenDatabase),
35218
35502
  /* harmony export */ run: () => ( /* binding */run),
35219
35503
  /* harmony export */ runQuery: () => ( /* binding */runQuery),
35220
35504
  /* harmony export */ select: () => ( /* binding */select),
@@ -35246,8 +35530,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35246
35530
  /* harmony import */ var _sync__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../sync */ "./packages/loot-core/src/server/sync/index.ts");
35247
35531
  /* harmony import */ var _sort__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./sort */ "./packages/loot-core/src/server/db/sort.ts");
35248
35532
  // @ts-strict-ignore
35249
- let dbPath;
35250
- let db;
35533
+ let dbPath = null;
35534
+ let db = null;
35251
35535
  // Util
35252
35536
  function getDatabasePath() {
35253
35537
  return dbPath;
@@ -35260,10 +35544,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35260
35544
  setDatabase(await _platform_server_sqlite__WEBPACK_IMPORTED_MODULE_3__.openDatabase(dbPath));
35261
35545
  // await execQuery('PRAGMA journal_mode = WAL');
35262
35546
  }
35263
- async function reopenDatabase() {
35264
- await _platform_server_sqlite__WEBPACK_IMPORTED_MODULE_3__.closeDatabase(db);
35265
- setDatabase(await _platform_server_sqlite__WEBPACK_IMPORTED_MODULE_3__.openDatabase(dbPath));
35266
- }
35267
35547
  async function closeDatabase() {
35268
35548
  if (db) {
35269
35549
  await _platform_server_sqlite__WEBPACK_IMPORTED_MODULE_3__.closeDatabase(db);
@@ -35666,7 +35946,25 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
35666
35946
  SELECT p.*, COALESCE(a.name, p.name) AS name FROM payees p
35667
35947
  LEFT JOIN accounts a ON (p.transfer_acct = a.id AND a.tombstone = 0)
35668
35948
  WHERE p.tombstone = 0 AND (p.transfer_acct IS NULL OR a.id IS NOT NULL)
35669
- ORDER BY p.transfer_acct IS NULL DESC, p.name COLLATE NOCASE
35949
+ ORDER BY p.transfer_acct IS NULL DESC, p.name COLLATE NOCASE, a.offbudget, a.sort_order
35950
+ `);
35951
+ }
35952
+ function getCommonPayees() {
35953
+ const threeMonthsAgo = '20240201';
35954
+ const limit = 10;
35955
+ return all(`
35956
+ SELECT p.id as id, p.name as name, p.favorite as favorite,
35957
+ p.category as category, TRUE as common, NULL as transfer_acct,
35958
+ count(*) as c,
35959
+ max(t.date) as latest
35960
+ FROM payees p
35961
+ LEFT JOIN v_transactions t on t.payee == p.id
35962
+ WHERE LENGTH(p.name) > 0
35963
+ GROUP BY p.id
35964
+ HAVING latest > ${threeMonthsAgo}
35965
+ ORDER BY c DESC ,p.transfer_acct IS NULL DESC, p.name
35966
+ COLLATE NOCASE
35967
+ LIMIT ${limit}
35670
35968
  `);
35671
35969
  }
35672
35970
  function syncGetOrphanedPayees() {
@@ -37318,8 +37616,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
37318
37616
  deleted,
37319
37617
  learnCategories
37320
37618
  });
37321
- // Return all data updates to the frontend
37322
- return result.updated;
37619
+ return result;
37323
37620
  });
37324
37621
  });
37325
37622
  handlers['transaction-add'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(async function (transaction) {
@@ -37619,6 +37916,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
37619
37916
  });
37620
37917
  });
37621
37918
  });
37919
+ handlers['common-payees-get'] = async function () {
37920
+ return _db__WEBPACK_IMPORTED_MODULE_27__.getCommonPayees();
37921
+ };
37622
37922
  handlers['payees-get'] = async function () {
37623
37923
  return _db__WEBPACK_IMPORTED_MODULE_27__.getPayees();
37624
37924
  };
@@ -37737,6 +38037,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
37737
38037
  handlers['accounts-get'] = async function () {
37738
38038
  return _db__WEBPACK_IMPORTED_MODULE_27__.getAccounts();
37739
38039
  };
38040
+ handlers['account-balance'] = async function ({ id, cutoff }) {
38041
+ const { balance } = await _db__WEBPACK_IMPORTED_MODULE_27__.first('SELECT sum(amount) as balance FROM transactions WHERE acct = ? AND isParent = 0 AND tombstone = 0 AND date <= ?', [
38042
+ id,
38043
+ _db__WEBPACK_IMPORTED_MODULE_27__.toDateRepr((0, _shared_months__WEBPACK_IMPORTED_MODULE_11__.dayFromDate)(cutoff))
38044
+ ]);
38045
+ return balance ? balance : 0;
38046
+ };
37740
38047
  handlers['account-properties'] = async function ({ id }) {
37741
38048
  const { balance } = await _db__WEBPACK_IMPORTED_MODULE_27__.first('SELECT sum(amount) as balance FROM transactions WHERE acct = ? AND isParent = 0 AND tombstone = 0', [
37742
38049
  id
@@ -37795,7 +38102,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
37795
38102
  const institution = {
37796
38103
  name: externalAccount.institution ?? 'Unknown'
37797
38104
  };
37798
- const bank = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.findOrCreateBank(institution, externalAccount.orgDomain);
38105
+ const bank = await _accounts_link__WEBPACK_IMPORTED_MODULE_15__.findOrCreateBank(institution, externalAccount.orgDomain ?? externalAccount.orgId);
37799
38106
  if (upgradingId) {
37800
38107
  const accRow = await _db__WEBPACK_IMPORTED_MODULE_27__.first('SELECT * FROM accounts WHERE id = ?', [
37801
38108
  upgradingId
@@ -38077,9 +38384,16 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38077
38384
  error: 'unauthorized'
38078
38385
  };
38079
38386
  }
38080
- return (0, _post__WEBPACK_IMPORTED_MODULE_37__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_42__.getServer)().SIMPLEFIN_SERVER + '/accounts', {}, {
38081
- 'X-ACTUAL-TOKEN': userToken
38082
- });
38387
+ try {
38388
+ return await (0, _post__WEBPACK_IMPORTED_MODULE_37__.post)((0, _server_config__WEBPACK_IMPORTED_MODULE_42__.getServer)().SIMPLEFIN_SERVER + '/accounts', {}, {
38389
+ 'X-ACTUAL-TOKEN': userToken
38390
+ }, 60000);
38391
+ }
38392
+ catch (error) {
38393
+ return {
38394
+ error_code: 'TIMED_OUT'
38395
+ };
38396
+ }
38083
38397
  };
38084
38398
  handlers['gocardless-get-banks'] = async function (country) {
38085
38399
  const userToken = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.getItem('user-token');
@@ -38129,7 +38443,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38129
38443
  ]);
38130
38444
  const accounts = await _db__WEBPACK_IMPORTED_MODULE_27__.runQuery(`SELECT a.*, b.bank_id as bankId FROM accounts a
38131
38445
  LEFT JOIN banks b ON a.bank = b.id
38132
- WHERE a.tombstone = 0 AND a.closed = 0 ${id ? 'AND a.id = ?' : ''}`, id ? [
38446
+ WHERE a.tombstone = 0 AND a.closed = 0 ${id ? 'AND a.id = ?' : ''}
38447
+ ORDER BY a.offbudget, a.sort_order`, id ? [
38133
38448
  id
38134
38449
  ] : [], true);
38135
38450
  const errors = [];
@@ -38142,7 +38457,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38142
38457
  try {
38143
38458
  console.group('Bank Sync operation for account:', acct.name);
38144
38459
  const res = await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.syncAccount(userId, userKey, acct.id, acct.account_id, acct.bankId);
38145
- console.groupEnd();
38146
38460
  const { added, updated } = res;
38147
38461
  newTransactions = newTransactions.concat(added);
38148
38462
  matchedTransactions = matchedTransactions.concat(updated);
@@ -38163,7 +38477,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38163
38477
  else if (err instanceof _errors__WEBPACK_IMPORTED_MODULE_30__.PostError && err.reason !== 'internal') {
38164
38478
  errors.push({
38165
38479
  accountId: acct.id,
38166
- message: `Account “${acct.name}” is not linked properly. Please link it again`
38480
+ message: err.reason ? err.reason : `Account “${acct.name}” is not linked properly. Please link it again.`
38167
38481
  });
38168
38482
  }
38169
38483
  else {
@@ -38176,6 +38490,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38176
38490
  (0, _platform_exceptions__WEBPACK_IMPORTED_MODULE_4__.captureException)(err);
38177
38491
  }
38178
38492
  }
38493
+ finally {
38494
+ console.groupEnd();
38495
+ }
38179
38496
  }
38180
38497
  }
38181
38498
  if (updatedAccounts.length > 0) {
@@ -38193,13 +38510,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38193
38510
  updatedAccounts
38194
38511
  };
38195
38512
  };
38196
- handlers['transactions-import'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(function ({ accountId, transactions }) {
38513
+ handlers['transactions-import'] = (0, _mutators__WEBPACK_IMPORTED_MODULE_34__.mutator)(function ({ accountId, transactions, isPreview }) {
38197
38514
  return (0, _undo__WEBPACK_IMPORTED_MODULE_48__.withUndo)(async () => {
38198
38515
  if (typeof accountId !== 'string') {
38199
38516
  throw (0, _errors__WEBPACK_IMPORTED_MODULE_30__.APIError)('transactions-import: accountId must be an id');
38200
38517
  }
38201
38518
  try {
38202
- return await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.reconcileTransactions(accountId, transactions);
38519
+ return await _accounts_sync__WEBPACK_IMPORTED_MODULE_18__.reconcileTransactions(accountId, transactions, false, isPreview);
38203
38520
  }
38204
38521
  catch (err) {
38205
38522
  if (err instanceof _errors__WEBPACK_IMPORTED_MODULE_30__.TransactionError) {
@@ -38210,7 +38527,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38210
38527
  }
38211
38528
  ],
38212
38529
  added: [],
38213
- updated: []
38530
+ updated: [],
38531
+ updatedPreview: []
38214
38532
  };
38215
38533
  }
38216
38534
  throw err;
@@ -38272,13 +38590,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38272
38590
  if ('maxMonths' in prefs) {
38273
38591
  await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.setItem('max-months', '' + prefs.maxMonths);
38274
38592
  }
38275
- if ('autoUpdate' in prefs) {
38276
- await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.setItem('auto-update', '' + prefs.autoUpdate);
38277
- process.parentPort.postMessage({
38278
- type: 'shouldAutoUpdate',
38279
- flag: prefs.autoUpdate
38280
- });
38281
- }
38282
38593
  if ('documentDir' in prefs) {
38283
38594
  if (await _platform_server_fs__WEBPACK_IMPORTED_MODULE_7__.exists(prefs.documentDir)) {
38284
38595
  await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.setItem('document-dir', prefs.documentDir);
@@ -38293,10 +38604,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38293
38604
  return 'ok';
38294
38605
  };
38295
38606
  handlers['load-global-prefs'] = async function () {
38296
- const [[, floatingSidebar], [, maxMonths], [, autoUpdate], [, documentDir], [, encryptKey], [, theme]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.multiGet([
38607
+ const [[, floatingSidebar], [, maxMonths], [, documentDir], [, encryptKey], [, theme]] = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.multiGet([
38297
38608
  'floating-sidebar',
38298
38609
  'max-months',
38299
- 'auto-update',
38300
38610
  'document-dir',
38301
38611
  'encrypt-key',
38302
38612
  'theme'
@@ -38304,7 +38614,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
38304
38614
  return {
38305
38615
  floatingSidebar: floatingSidebar === 'true' ? true : false,
38306
38616
  maxMonths: (0, _shared_util__WEBPACK_IMPORTED_MODULE_13__.stringToInteger)(maxMonths || ''),
38307
- autoUpdate: autoUpdate == null || autoUpdate === 'true' ? true : false,
38308
38617
  documentDir: documentDir || getDefaultDocumentDir(),
38309
38618
  keyId: encryptKey && JSON.parse(encryptKey).id,
38310
38619
  theme: theme === 'light' || theme === 'dark' || theme === 'auto' || theme === 'development' || theme === 'midnight' ? theme : 'auto'
@@ -39131,13 +39440,6 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39131
39440
  }
39132
39441
  (0, _server_config__WEBPACK_IMPORTED_MODULE_42__.setServer)(url);
39133
39442
  _platform_server_connection__WEBPACK_IMPORTED_MODULE_6__.init(socketName, _main_app__WEBPACK_IMPORTED_MODULE_33__.app.handlers);
39134
- if (!isDev && !_platform__WEBPACK_IMPORTED_MODULE_36__.isMobile && !_platform__WEBPACK_IMPORTED_MODULE_36__.isWeb) {
39135
- const autoUpdate = await _platform_server_asyncStorage__WEBPACK_IMPORTED_MODULE_5__.getItem('auto-update');
39136
- process.parentPort.postMessage({
39137
- type: 'shouldAutoUpdate',
39138
- flag: autoUpdate == null || autoUpdate === 'true'
39139
- });
39140
- }
39141
39443
  // Allow running DB queries locally
39142
39444
  global.$query = _aql__WEBPACK_IMPORTED_MODULE_22__.runQuery;
39143
39445
  global.$q = _shared_query__WEBPACK_IMPORTED_MODULE_12__.q;
@@ -39646,18 +39948,23 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39646
39948
  throw new _errors__WEBPACK_IMPORTED_MODULE_1__.PostError(text);
39647
39949
  }
39648
39950
  }
39649
- async function post(url, data, headers = {}) {
39951
+ async function post(url, data, headers = {}, timeout = null) {
39650
39952
  let text;
39651
39953
  let res;
39652
39954
  try {
39955
+ const controller = new AbortController();
39956
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
39957
+ const signal = timeout ? controller.signal : null;
39653
39958
  res = await (0, _platform_server_fetch__WEBPACK_IMPORTED_MODULE_0__.fetch)(url, {
39654
39959
  method: 'POST',
39655
39960
  body: JSON.stringify(data),
39961
+ signal,
39656
39962
  headers: {
39657
39963
  ...headers,
39658
39964
  'Content-Type': 'application/json'
39659
39965
  }
39660
39966
  });
39967
+ clearTimeout(timeoutId);
39661
39968
  text = await res.text();
39662
39969
  }
39663
39970
  catch (err) {
@@ -39856,11 +40163,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39856
40163
  showOffBudget: row.show_offbudget === 1,
39857
40164
  showHiddenCategories: row.show_hidden === 1,
39858
40165
  showUncategorized: row.show_uncategorized === 1,
40166
+ includeCurrentInterval: row.include_current === 1,
39859
40167
  selectedCategories: row.selected_categories,
39860
40168
  graphType: row.graph_type,
39861
40169
  conditions: row.conditions,
39862
- conditionsOp: row.conditions_op,
39863
- data: row.metadata
40170
+ conditionsOp: row.conditions_op
39864
40171
  };
39865
40172
  },
39866
40173
  fromJS(report) {
@@ -39879,11 +40186,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39879
40186
  show_offbudget: report.showOffBudget ? 1 : 0,
39880
40187
  show_hidden: report.showHiddenCategories ? 1 : 0,
39881
40188
  show_uncategorized: report.showUncategorized ? 1 : 0,
40189
+ include_current: report.includeCurrentInterval ? 1 : 0,
39882
40190
  selected_categories: report.selectedCategories,
39883
40191
  graph_type: report.graphType,
39884
40192
  conditions: report.conditions,
39885
- conditions_op: report.conditionsOp,
39886
- metadata: report.data
40193
+ conditions_op: report.conditionsOp
39887
40194
  };
39888
40195
  }
39889
40196
  };
@@ -39935,7 +40242,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39935
40242
  if (nameExists) {
39936
40243
  throw new Error('There is already a filter named ' + item.name);
39937
40244
  }
39938
- await _db__WEBPACK_IMPORTED_MODULE_1__.insertWithSchema('custom_reports', reportModel.fromJS(item));
40245
+ await _db__WEBPACK_IMPORTED_MODULE_1__.updateWithSchema('custom_reports', reportModel.fromJS(item));
39939
40246
  }
39940
40247
  async function deleteReport(id) {
39941
40248
  await _db__WEBPACK_IMPORTED_MODULE_1__.delete_('custom_reports', id);
@@ -39983,8 +40290,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
39983
40290
  throw e;
39984
40291
  }
39985
40292
  return null;
39986
- }).filter((res) => typeof res === 'string');
39987
- return result.length ? result : null;
40293
+ });
40294
+ return result.filter((res) => typeof res === 'string').length ? result : null;
39988
40295
  }
39989
40296
  const conditionErrors = runValidation(rule.conditions, (cond) => new _accounts_rules__WEBPACK_IMPORTED_MODULE_1__.Condition(cond.op, cond.field, cond.value, cond.options, _shared_rules__WEBPACK_IMPORTED_MODULE_0__.FIELD_TYPES));
39990
40297
  const actionErrors = runValidation(rule.actions, (action) => action.op === 'set-split-amount' ? new _accounts_rules__WEBPACK_IMPORTED_MODULE_1__.Action(action.op, null, action.value, action.options, _shared_rules__WEBPACK_IMPORTED_MODULE_0__.FIELD_TYPES) : action.op === 'link-schedule' ? new _accounts_rules__WEBPACK_IMPORTED_MODULE_1__.Action(action.op, null, action.value, null, _shared_rules__WEBPACK_IMPORTED_MODULE_0__.FIELD_TYPES) : new _accounts_rules__WEBPACK_IMPORTED_MODULE_1__.Action(action.op, action.field, action.value, action.options, _shared_rules__WEBPACK_IMPORTED_MODULE_0__.FIELD_TYPES));
@@ -41139,6 +41446,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
41139
41446
  sheet.set(`${sheetName}!budget-${budget.category}`, budget.amount);
41140
41447
  sheet.set(`${sheetName}!carryover-${budget.category}`, budget.carryover === 1 ? true : false);
41141
41448
  sheet.set(`${sheetName}!goal-${budget.category}`, budget.goal);
41449
+ sheet.set(`${sheetName}!long-goal-${budget.category}`, budget.long_goal);
41142
41450
  }
41143
41451
  }
41144
41452
  // For zero-based budgets, load the buffered amounts
@@ -41216,6 +41524,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
41216
41524
  /* harmony export */ Graph: () => ( /* binding */Graph)
41217
41525
  /* harmony export */
41218
41526
  });
41527
+ /* harmony import */ var _prefs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../prefs */ "./packages/loot-core/src/server/prefs.ts");
41219
41528
  // @ts-strict-ignore
41220
41529
  function Graph() {
41221
41530
  const graph = {
@@ -41286,27 +41595,84 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
41286
41595
  }
41287
41596
  return graph;
41288
41597
  }
41289
- function topologicalSortUntil(name, visited, sorted) {
41598
+ function topologicalSort(sourceNodes) {
41599
+ const visited = new Set();
41600
+ const sorted = [];
41601
+ const prefs = (0, _prefs__WEBPACK_IMPORTED_MODULE_0__.getPrefs)();
41602
+ const iterableTopologicalSort = prefs != null ? prefs['flags.iterableTopologicalSort'] : false;
41603
+ sourceNodes.forEach((name) => {
41604
+ if (!visited.has(name)) {
41605
+ if (iterableTopologicalSort) {
41606
+ topologicalSortIterable(name, visited, sorted);
41607
+ }
41608
+ else {
41609
+ topologicalSortUntil(name, visited, sorted, 0);
41610
+ }
41611
+ }
41612
+ });
41613
+ return sorted;
41614
+ }
41615
+ function topologicalSortUntil(name, visited, sorted, level) {
41290
41616
  visited.add(name);
41617
+ if (level > 2500) {
41618
+ console.error('Limit of recursions reached while sorting budget: 2500');
41619
+ return;
41620
+ }
41291
41621
  const iter = adjacent(name).values();
41292
41622
  let cur = iter.next();
41293
41623
  while (!cur.done) {
41294
41624
  if (!visited.has(cur.value)) {
41295
- topologicalSortUntil(cur.value, visited, sorted);
41625
+ topologicalSortUntil(cur.value, visited, sorted, level + 1);
41296
41626
  }
41297
41627
  cur = iter.next();
41298
41628
  }
41299
41629
  sorted.unshift(name);
41300
41630
  }
41301
- function topologicalSort(sourceNodes) {
41302
- const visited = new Set();
41303
- const sorted = [];
41304
- sourceNodes.forEach((name) => {
41305
- if (!visited.has(name)) {
41306
- topologicalSortUntil(name, visited, sorted);
41631
+ function topologicalSortIterable(name, visited, sorted) {
41632
+ const stackTrace = [];
41633
+ stackTrace.push({
41634
+ count: -1,
41635
+ value: name,
41636
+ parent: '',
41637
+ level: 0
41638
+ });
41639
+ while (stackTrace.length > 0) {
41640
+ const current = stackTrace.slice(-1)[0];
41641
+ const adjacents = adjacent(current.value);
41642
+ if (current.count === -1) {
41643
+ current.count = adjacents.size;
41644
+ }
41645
+ if (current.count > 0) {
41646
+ const iter = adjacents.values();
41647
+ let cur = iter.next();
41648
+ while (!cur.done) {
41649
+ if (!visited.has(cur.value)) {
41650
+ stackTrace.push({
41651
+ count: -1,
41652
+ parent: current.value,
41653
+ value: cur.value,
41654
+ level: current.level + 1
41655
+ });
41656
+ }
41657
+ else {
41658
+ current.count--;
41659
+ }
41660
+ cur = iter.next();
41661
+ }
41307
41662
  }
41308
- });
41309
- return sorted;
41663
+ else {
41664
+ if (!visited.has(current.value)) {
41665
+ visited.add(current.value);
41666
+ sorted.unshift(current.value);
41667
+ }
41668
+ const removed = stackTrace.pop();
41669
+ for (let i = 0; i < stackTrace.length; i++) {
41670
+ if (stackTrace[i].value === removed.parent) {
41671
+ stackTrace[i].count--;
41672
+ }
41673
+ }
41674
+ }
41675
+ }
41310
41676
  }
41311
41677
  function generateDOT() {
41312
41678
  const edgeStrings = [];
@@ -41316,9 +41682,9 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
41316
41682
  }
41317
41683
  });
41318
41684
  return `
41319
- digraph G {
41320
- ${edgeStrings.join('\n').replace(/!/g, '_')}
41321
- }
41685
+ digraph G {
41686
+ ${edgeStrings.join('\n').replace(/!/g, '_')}
41687
+ }
41322
41688
  `;
41323
41689
  }
41324
41690
  return graph;
@@ -43749,7 +44115,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43749
44115
  function _yearRange(start, end, inclusive = false) {
43750
44116
  const years = [];
43751
44117
  let year = yearFromDate(start);
43752
- while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(year), _parse(end))) {
44118
+ const endYear = yearFromDate(end);
44119
+ while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(year), _parse(endYear))) {
43753
44120
  years.push(year);
43754
44121
  year = addYears(year, 1);
43755
44122
  }
@@ -43780,7 +44147,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43780
44147
  function _range(start, end, inclusive = false) {
43781
44148
  const months = [];
43782
44149
  let month = monthFromDate(start);
43783
- while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(month), _parse(end))) {
44150
+ const endMonth = monthFromDate(end);
44151
+ while (date_fns__WEBPACK_IMPORTED_MODULE_14__["default"](_parse(month), _parse(endMonth))) {
43784
44152
  months.push(month);
43785
44153
  month = addMonths(month, 1);
43786
44154
  }
@@ -43879,6 +44247,22 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
43879
44247
  });
43880
44248
  /***/
43881
44249
  }),
44250
+ /***/ "./packages/loot-core/src/shared/normalisation.ts":
44251
+ /*!********************************************************!*\
44252
+ !*** ./packages/loot-core/src/shared/normalisation.ts ***!
44253
+ \********************************************************/
44254
+ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
44255
+ "use strict";
44256
+ __webpack_require__.r(__webpack_exports__);
44257
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
44258
+ /* harmony export */ getNormalisedString: () => ( /* binding */getNormalisedString)
44259
+ /* harmony export */
44260
+ });
44261
+ function getNormalisedString(value) {
44262
+ return value.toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, '');
44263
+ }
44264
+ /***/
44265
+ }),
43882
44266
  /***/ "./packages/loot-core/src/shared/query.ts":
43883
44267
  /*!************************************************!*\
43884
44268
  !*** ./packages/loot-core/src/shared/query.ts ***!
@@ -44087,6 +44471,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44087
44471
  ops: [
44088
44472
  'is',
44089
44473
  'contains',
44474
+ 'matches',
44090
44475
  'oneOf',
44091
44476
  'isNot',
44092
44477
  'doesNotContain',
@@ -44102,6 +44487,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44102
44487
  ops: [
44103
44488
  'is',
44104
44489
  'contains',
44490
+ 'matches',
44105
44491
  'oneOf',
44106
44492
  'isNot',
44107
44493
  'doesNotContain',
@@ -44144,7 +44530,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44144
44530
  }));
44145
44531
  const ALLOCATION_METHODS = {
44146
44532
  'fixed-amount': 'a fixed amount',
44147
- 'fixed-percent': 'a fixed percent',
44533
+ 'fixed-percent': 'a fixed percent of the remainder',
44148
44534
  remainder: 'an equal portion of the remainder'
44149
44535
  };
44150
44536
  function mapField(field, opts) {
@@ -44184,6 +44570,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44184
44570
  return 'is between';
44185
44571
  case 'contains':
44186
44572
  return 'contains';
44573
+ case 'matches':
44574
+ return 'matches';
44187
44575
  case 'doesNotContain':
44188
44576
  return 'does not contain';
44189
44577
  case 'gt':
@@ -44442,7 +44830,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44442
44830
  $and: {
44443
44831
  schedule: schedule.id,
44444
44832
  date: {
44445
- $gte: dateCond && dateCond.op === 'is' ? schedule.next_date : _months__WEBPACK_IMPORTED_MODULE_0__.subDays(schedule.next_date, 7)
44833
+ $gte: dateCond && dateCond.op === 'is' ? schedule.next_date : _months__WEBPACK_IMPORTED_MODULE_0__.subDays(schedule.next_date, 2)
44446
44834
  }
44447
44835
  }
44448
44836
  };
@@ -44686,6 +45074,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44686
45074
  /* harmony export */ groupTransaction: () => ( /* binding */groupTransaction),
44687
45075
  /* harmony export */ isPreviewId: () => ( /* binding */isPreviewId),
44688
45076
  /* harmony export */ isTemporaryId: () => ( /* binding */isTemporaryId),
45077
+ /* harmony export */ makeAsNonChildTransactions: () => ( /* binding */makeAsNonChildTransactions),
44689
45078
  /* harmony export */ makeChild: () => ( /* binding */makeChild),
44690
45079
  /* harmony export */ realizeTempTransactions: () => ( /* binding */realizeTempTransactions),
44691
45080
  /* harmony export */ recalculateSplit: () => ( /* binding */recalculateSplit),
@@ -44733,6 +45122,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44733
45122
  error: null
44734
45123
  };
44735
45124
  }
45125
+ function makeNonChild(parent, data) {
45126
+ return {
45127
+ amount: 0,
45128
+ ...data,
45129
+ cleared: parent.cleared != null ? parent.cleared : null,
45130
+ reconciled: parent.reconciled != null ? parent.reconciled : null,
45131
+ sort_order: parent.sort_order || null,
45132
+ starting_balance_flag: null,
45133
+ is_child: false,
45134
+ parent_id: null
45135
+ };
45136
+ }
44736
45137
  function recalculateSplit(trans) {
44737
45138
  // Calculate the new total of split transactions and make sure
44738
45139
  // that it equals the parent amount
@@ -44882,7 +45283,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44882
45283
  return replaceTransactions(transactions, transaction.id, (trans) => {
44883
45284
  if (trans.is_parent) {
44884
45285
  const parent = trans.id === transaction.id ? transaction : trans;
44885
- const sub = trans.subtransactions?.map((t) => {
45286
+ const originalSubtransactions = parent.subtransactions ?? trans.subtransactions;
45287
+ const sub = originalSubtransactions?.map((t) => {
44886
45288
  // Make sure to update the children to reflect the updated
44887
45289
  // properties (if the parent updated)
44888
45290
  let child = t;
@@ -44968,6 +45370,35 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
44968
45370
  }))
44969
45371
  ];
44970
45372
  }
45373
+ function makeAsNonChildTransactions(childTransactionsToUpdate, transactions) {
45374
+ const [parentTransaction, ...childTransactions] = transactions;
45375
+ const newNonChildTransactions = childTransactionsToUpdate.map((t) => makeNonChild(parentTransaction, t));
45376
+ const remainingChildTransactions = childTransactions.filter((t) => !newNonChildTransactions.some((updatedTrans) => updatedTrans.id === t.id));
45377
+ const nonChildTransactionsToUpdate = remainingChildTransactions.length === 1 ? [
45378
+ ...newNonChildTransactions,
45379
+ makeNonChild(parentTransaction, remainingChildTransactions[0])
45380
+ ] : newNonChildTransactions;
45381
+ const deleteParentTransaction = remainingChildTransactions.length <= 1;
45382
+ const updatedParentTransaction = {
45383
+ ...parentTransaction,
45384
+ ...!deleteParentTransaction ? {
45385
+ amount: remainingChildTransactions.map((t) => t.amount).reduce((total, amount) => total + amount, 0)
45386
+ } : {}
45387
+ };
45388
+ return {
45389
+ updated: [
45390
+ ...!deleteParentTransaction ? [
45391
+ updatedParentTransaction
45392
+ ] : [],
45393
+ ...nonChildTransactionsToUpdate
45394
+ ],
45395
+ deleted: [
45396
+ ...deleteParentTransaction ? [
45397
+ updatedParentTransaction
45398
+ ] : []
45399
+ ]
45400
+ };
45401
+ }
44971
45402
  /***/
44972
45403
  }),
44973
45404
  /***/ "./packages/loot-core/src/shared/util.ts":
@@ -45202,13 +45633,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
45202
45633
  },
45203
45634
  {
45204
45635
  value: 'space-comma',
45205
- label: '1 000,33',
45206
- labelNoFraction: '1 000'
45636
+ label: '1\xa0000,33',
45637
+ labelNoFraction: '1\xa0000'
45207
45638
  },
45208
45639
  {
45209
- value: 'space-dot',
45210
- label: '1 000.33',
45211
- labelNoFraction: '1 000'
45640
+ value: 'apostrophe-dot',
45641
+ label: '1000.33',
45642
+ labelNoFraction: '1000'
45212
45643
  },
45213
45644
  {
45214
45645
  value: 'comma-dot-in',
@@ -45237,8 +45668,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
45237
45668
  regex = /[^-0-9,]/g;
45238
45669
  separator = ',';
45239
45670
  break;
45240
- case 'space-dot':
45241
- locale = 'dje';
45671
+ case 'apostrophe-dot':
45672
+ locale = 'de-CH';
45242
45673
  regex = /[^-0-9,.]/g;
45243
45674
  separator = '.';
45244
45675
  separatorRegex = /[,.]/g;
@@ -45295,6 +45726,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
45295
45726
  }
45296
45727
  function amountToCurrencyNoDecimal(n) {
45297
45728
  return getNumberFormat({
45729
+ ...numberFormatConfig,
45298
45730
  hideFraction: true
45299
45731
  }).formatter.format(n);
45300
45732
  }
@@ -51088,9 +51520,11 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51088
51520
  var peg$c19 = "full";
51089
51521
  var peg$c20 = "-";
51090
51522
  var peg$c21 = "remainder";
51091
- var peg$c22 = " ";
51092
- var peg$c23 = ".";
51093
- var peg$c24 = "%";
51523
+ var peg$c22 = "#template";
51524
+ var peg$c23 = "#goal";
51525
+ var peg$c24 = " ";
51526
+ var peg$c25 = ".";
51527
+ var peg$c26 = "%";
51094
51528
  var peg$r0 = /^[0-9]/;
51095
51529
  var peg$r1 = /^[1-9]/;
51096
51530
  var peg$r2 = /^[^\r\n\t]/;
@@ -51117,58 +51551,62 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51117
51551
  var peg$e20 = peg$literalExpectation("full", true);
51118
51552
  var peg$e21 = peg$literalExpectation("-", true);
51119
51553
  var peg$e22 = peg$literalExpectation("remainder", true);
51120
- var peg$e23 = peg$otherExpectation("space");
51121
- var peg$e24 = peg$literalExpectation(" ", false);
51122
- var peg$e25 = peg$otherExpectation("digit");
51123
- var peg$e26 = peg$classExpectation([["0", "9"]], false, false);
51124
- var peg$e27 = peg$otherExpectation("number");
51125
- var peg$e28 = peg$classExpectation([["1", "9"]], false, false);
51126
- var peg$e29 = peg$otherExpectation("amount");
51127
- var peg$e30 = peg$literalExpectation(".", false);
51128
- var peg$e31 = peg$otherExpectation("percentage");
51129
- var peg$e32 = peg$literalExpectation("%", false);
51130
- var peg$e33 = peg$otherExpectation("year");
51131
- var peg$e34 = peg$otherExpectation("month");
51132
- var peg$e35 = peg$literalExpectation("-", false);
51133
- var peg$e36 = peg$otherExpectation("day");
51134
- var peg$e37 = peg$otherExpectation("currency symbol");
51135
- var peg$e38 = peg$anyExpectation();
51136
- var peg$e39 = peg$otherExpectation("Name");
51137
- var peg$e40 = peg$classExpectation(["\r", "\n", "\t"], true, false);
51138
- var peg$f0 = function (priority, percentOf, category) { return { type: 'percentage', percent: +percentOf.percent, previous: percentOf.prev, category, priority: +priority }; };
51139
- var peg$f1 = function (priority, amount, weeks, starting, limit) { return { type: 'week', amount, weeks, starting, limit, priority: +priority }; };
51140
- var peg$f2 = function (priority, amount, month, from, repeat) {
51554
+ var peg$e23 = peg$literalExpectation("#template", false);
51555
+ var peg$e24 = peg$literalExpectation("#goal", false);
51556
+ var peg$e25 = peg$otherExpectation("space");
51557
+ var peg$e26 = peg$literalExpectation(" ", false);
51558
+ var peg$e27 = peg$otherExpectation("digit");
51559
+ var peg$e28 = peg$classExpectation([["0", "9"]], false, false);
51560
+ var peg$e29 = peg$otherExpectation("number");
51561
+ var peg$e30 = peg$classExpectation([["1", "9"]], false, false);
51562
+ var peg$e31 = peg$otherExpectation("amount");
51563
+ var peg$e32 = peg$literalExpectation(".", false);
51564
+ var peg$e33 = peg$otherExpectation("percentage");
51565
+ var peg$e34 = peg$literalExpectation("%", false);
51566
+ var peg$e35 = peg$otherExpectation("year");
51567
+ var peg$e36 = peg$otherExpectation("month");
51568
+ var peg$e37 = peg$literalExpectation("-", false);
51569
+ var peg$e38 = peg$otherExpectation("day");
51570
+ var peg$e39 = peg$otherExpectation("currency symbol");
51571
+ var peg$e40 = peg$anyExpectation();
51572
+ var peg$e41 = peg$otherExpectation("Name");
51573
+ var peg$e42 = peg$classExpectation(["\r", "\n", "\t"], true, false);
51574
+ var peg$f0 = function (template, percentOf, category) { return { type: 'percentage', percent: +percentOf.percent, previous: percentOf.prev, category, priority: template.priority, directive: template.directive }; };
51575
+ var peg$f1 = function (template, amount, weeks, starting, limit) { return { type: 'week', amount, weeks, starting, limit, priority: template.priority, directive: template.directive }; };
51576
+ var peg$f2 = function (template, amount, month, from, repeat) {
51141
51577
  return {
51142
51578
  type: from ? 'spend' : 'by',
51143
51579
  amount,
51144
51580
  month,
51145
51581
  ...(repeat ? repeat[3] : {}),
51146
51582
  from,
51147
- priority: +priority
51583
+ priority: template.priority, directive: template.directive
51148
51584
  };
51149
51585
  };
51150
- var peg$f3 = function (priority, monthly, limit) { return { type: 'simple', monthly, limit, priority: +priority }; };
51151
- var peg$f4 = function (priority, limit) { return { type: 'simple', limit, priority: +priority }; };
51152
- var peg$f5 = function (priority, full, name) { return { type: 'schedule', name, priority: +priority, full }; };
51153
- var peg$f6 = function (priority, remainder) { return { type: 'remainder', priority: null, weight: remainder }; };
51154
- var peg$f7 = function (priority, amount) { return { type: 'average', amount: +amount, priority: +priority }; };
51155
- var peg$f8 = function () { return { annual: false }; };
51156
- var peg$f9 = function (months) { return { annual: false, repeat: +months }; };
51157
- var peg$f10 = function () { return { annual: true }; };
51158
- var peg$f11 = function (years) { return { annual: true, repeat: +years }; };
51159
- var peg$f12 = function (amount) { return { amount: amount, hold: true }; };
51160
- var peg$f13 = function (amount) { return { amount: amount, hold: false }; };
51161
- var peg$f14 = function (percent) { return { percent: percent, prev: true }; };
51162
- var peg$f15 = function (percent) { return { percent: percent, prev: false }; };
51163
- var peg$f16 = function () { return null; };
51164
- var peg$f17 = function (n) { return +n; };
51165
- var peg$f18 = function (month) { return month; };
51166
- var peg$f19 = function () { return true; };
51167
- var peg$f20 = function (number) { return number; };
51168
- var peg$f21 = function (weight) { return +weight || 1; };
51169
- var peg$f22 = function (amount) { return +amount; };
51170
- var peg$f23 = function (percent) { return +percent; };
51171
- var peg$f24 = function (symbol) { return /\p{Sc}/u.test(symbol); };
51586
+ var peg$f3 = function (template, monthly, limit) { return { type: 'simple', monthly, limit, priority: template.priority, directive: template.directive }; };
51587
+ var peg$f4 = function (template, limit) { return { type: 'simple', limit, priority: template.priority, directive: template.directive }; };
51588
+ var peg$f5 = function (template, full, name) { return { type: 'schedule', name, priority: template.priority, directive: template.directive, full }; };
51589
+ var peg$f6 = function (template, remainder, limit) { return { type: 'remainder', priority: null, directive: template.directive, weight: remainder, limit }; };
51590
+ var peg$f7 = function (template, amount) { return { type: 'average', amount: +amount, priority: template.priority, directive: template.directive }; };
51591
+ var peg$f8 = function (goal, amount) { return { type: 'simple', amount: amount, priority: null, directive: 'goal' }; };
51592
+ var peg$f9 = function () { return { annual: false }; };
51593
+ var peg$f10 = function (months) { return { annual: false, repeat: +months }; };
51594
+ var peg$f11 = function () { return { annual: true }; };
51595
+ var peg$f12 = function (years) { return { annual: true, repeat: +years }; };
51596
+ var peg$f13 = function (amount) { return { amount: amount, hold: true }; };
51597
+ var peg$f14 = function (amount) { return { amount: amount, hold: false }; };
51598
+ var peg$f15 = function (percent) { return { percent: percent, prev: true }; };
51599
+ var peg$f16 = function (percent) { return { percent: percent, prev: false }; };
51600
+ var peg$f17 = function () { return null; };
51601
+ var peg$f18 = function (n) { return +n; };
51602
+ var peg$f19 = function (month) { return month; };
51603
+ var peg$f20 = function () { return true; };
51604
+ var peg$f21 = function (number) { return number; };
51605
+ var peg$f22 = function (weight) { return +weight || 1; };
51606
+ var peg$f23 = function (priority) { return { priority: +priority, directive: 'template' }; };
51607
+ var peg$f24 = function (amount) { return +amount; };
51608
+ var peg$f25 = function (percent) { return +percent; };
51609
+ var peg$f26 = function (symbol) { return /\p{Sc}/u.test(symbol); };
51172
51610
  var peg$currPos = 0;
51173
51611
  var peg$savedPos = 0;
51174
51612
  var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -51296,20 +51734,26 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51296
51734
  function peg$parseexpr() {
51297
51735
  var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13;
51298
51736
  s0 = peg$currPos;
51299
- s1 = peg$parsepriority();
51300
- if (s1 === peg$FAILED) {
51301
- s1 = null;
51302
- }
51303
- s2 = peg$parse_();
51304
- if (s2 === peg$FAILED) {
51305
- s2 = null;
51306
- }
51307
- s3 = peg$parsepercentOf();
51308
- if (s3 !== peg$FAILED) {
51309
- s4 = peg$parsename();
51310
- if (s4 !== peg$FAILED) {
51311
- peg$savedPos = s0;
51312
- s0 = peg$f0(s1, s3, s4);
51737
+ s1 = peg$parsetemplate();
51738
+ if (s1 !== peg$FAILED) {
51739
+ s2 = peg$parse_();
51740
+ if (s2 !== peg$FAILED) {
51741
+ s3 = peg$parsepercentOf();
51742
+ if (s3 !== peg$FAILED) {
51743
+ s4 = peg$parsename();
51744
+ if (s4 !== peg$FAILED) {
51745
+ peg$savedPos = s0;
51746
+ s0 = peg$f0(s1, s3, s4);
51747
+ }
51748
+ else {
51749
+ peg$currPos = s0;
51750
+ s0 = peg$FAILED;
51751
+ }
51752
+ }
51753
+ else {
51754
+ peg$currPos = s0;
51755
+ s0 = peg$FAILED;
51756
+ }
51313
51757
  }
51314
51758
  else {
51315
51759
  peg$currPos = s0;
@@ -51322,38 +51766,44 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51322
51766
  }
51323
51767
  if (s0 === peg$FAILED) {
51324
51768
  s0 = peg$currPos;
51325
- s1 = peg$parsepriority();
51326
- if (s1 === peg$FAILED) {
51327
- s1 = null;
51328
- }
51329
- s2 = peg$parse_();
51330
- if (s2 === peg$FAILED) {
51331
- s2 = null;
51332
- }
51333
- s3 = peg$parseamount();
51334
- if (s3 !== peg$FAILED) {
51335
- s4 = peg$parse_();
51336
- if (s4 !== peg$FAILED) {
51337
- s5 = peg$parserepeatEvery();
51338
- if (s5 !== peg$FAILED) {
51339
- s6 = peg$parse_();
51340
- if (s6 !== peg$FAILED) {
51341
- s7 = peg$parseweekCount();
51342
- if (s7 !== peg$FAILED) {
51343
- s8 = peg$parse_();
51344
- if (s8 !== peg$FAILED) {
51345
- s9 = peg$parsestarting();
51346
- if (s9 !== peg$FAILED) {
51347
- s10 = peg$parse_();
51348
- if (s10 !== peg$FAILED) {
51349
- s11 = peg$parsedate();
51350
- if (s11 !== peg$FAILED) {
51351
- s12 = peg$parselimit();
51352
- if (s12 === peg$FAILED) {
51353
- s12 = null;
51769
+ s1 = peg$parsetemplate();
51770
+ if (s1 !== peg$FAILED) {
51771
+ s2 = peg$parse_();
51772
+ if (s2 !== peg$FAILED) {
51773
+ s3 = peg$parseamount();
51774
+ if (s3 !== peg$FAILED) {
51775
+ s4 = peg$parse_();
51776
+ if (s4 !== peg$FAILED) {
51777
+ s5 = peg$parserepeatEvery();
51778
+ if (s5 !== peg$FAILED) {
51779
+ s6 = peg$parse_();
51780
+ if (s6 !== peg$FAILED) {
51781
+ s7 = peg$parseweekCount();
51782
+ if (s7 !== peg$FAILED) {
51783
+ s8 = peg$parse_();
51784
+ if (s8 !== peg$FAILED) {
51785
+ s9 = peg$parsestarting();
51786
+ if (s9 !== peg$FAILED) {
51787
+ s10 = peg$parse_();
51788
+ if (s10 !== peg$FAILED) {
51789
+ s11 = peg$parsedate();
51790
+ if (s11 !== peg$FAILED) {
51791
+ s12 = peg$parselimit();
51792
+ if (s12 === peg$FAILED) {
51793
+ s12 = null;
51794
+ }
51795
+ peg$savedPos = s0;
51796
+ s0 = peg$f1(s1, s3, s7, s11, s12);
51797
+ }
51798
+ else {
51799
+ peg$currPos = s0;
51800
+ s0 = peg$FAILED;
51801
+ }
51802
+ }
51803
+ else {
51804
+ peg$currPos = s0;
51805
+ s0 = peg$FAILED;
51354
51806
  }
51355
- peg$savedPos = s0;
51356
- s0 = peg$f1(s1, s3, s7, s11, s12);
51357
51807
  }
51358
51808
  else {
51359
51809
  peg$currPos = s0;
@@ -51401,39 +51851,45 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51401
51851
  }
51402
51852
  if (s0 === peg$FAILED) {
51403
51853
  s0 = peg$currPos;
51404
- s1 = peg$parsepriority();
51405
- if (s1 === peg$FAILED) {
51406
- s1 = null;
51407
- }
51408
- s2 = peg$parse_();
51409
- if (s2 === peg$FAILED) {
51410
- s2 = null;
51411
- }
51412
- s3 = peg$parseamount();
51413
- if (s3 !== peg$FAILED) {
51414
- s4 = peg$parse_();
51415
- if (s4 !== peg$FAILED) {
51416
- s5 = peg$parseby();
51417
- if (s5 !== peg$FAILED) {
51418
- s6 = peg$parse_();
51419
- if (s6 !== peg$FAILED) {
51420
- s7 = peg$parsemonth();
51421
- if (s7 !== peg$FAILED) {
51422
- s8 = peg$parsespendFrom();
51423
- if (s8 === peg$FAILED) {
51424
- s8 = null;
51425
- }
51426
- s9 = peg$currPos;
51427
- s10 = peg$parse_();
51428
- if (s10 !== peg$FAILED) {
51429
- s11 = peg$parserepeatEvery();
51430
- if (s11 !== peg$FAILED) {
51431
- s12 = peg$parse_();
51432
- if (s12 !== peg$FAILED) {
51433
- s13 = peg$parserepeat();
51434
- if (s13 !== peg$FAILED) {
51435
- s10 = [s10, s11, s12, s13];
51436
- s9 = s10;
51854
+ s1 = peg$parsetemplate();
51855
+ if (s1 !== peg$FAILED) {
51856
+ s2 = peg$parse_();
51857
+ if (s2 !== peg$FAILED) {
51858
+ s3 = peg$parseamount();
51859
+ if (s3 !== peg$FAILED) {
51860
+ s4 = peg$parse_();
51861
+ if (s4 !== peg$FAILED) {
51862
+ s5 = peg$parseby();
51863
+ if (s5 !== peg$FAILED) {
51864
+ s6 = peg$parse_();
51865
+ if (s6 !== peg$FAILED) {
51866
+ s7 = peg$parsemonth();
51867
+ if (s7 !== peg$FAILED) {
51868
+ s8 = peg$parsespendFrom();
51869
+ if (s8 === peg$FAILED) {
51870
+ s8 = null;
51871
+ }
51872
+ s9 = peg$currPos;
51873
+ s10 = peg$parse_();
51874
+ if (s10 !== peg$FAILED) {
51875
+ s11 = peg$parserepeatEvery();
51876
+ if (s11 !== peg$FAILED) {
51877
+ s12 = peg$parse_();
51878
+ if (s12 !== peg$FAILED) {
51879
+ s13 = peg$parserepeat();
51880
+ if (s13 !== peg$FAILED) {
51881
+ s10 = [s10, s11, s12, s13];
51882
+ s9 = s10;
51883
+ }
51884
+ else {
51885
+ peg$currPos = s9;
51886
+ s9 = peg$FAILED;
51887
+ }
51888
+ }
51889
+ else {
51890
+ peg$currPos = s9;
51891
+ s9 = peg$FAILED;
51892
+ }
51437
51893
  }
51438
51894
  else {
51439
51895
  peg$currPos = s9;
@@ -51444,21 +51900,21 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51444
51900
  peg$currPos = s9;
51445
51901
  s9 = peg$FAILED;
51446
51902
  }
51903
+ if (s9 === peg$FAILED) {
51904
+ s9 = null;
51905
+ }
51906
+ peg$savedPos = s0;
51907
+ s0 = peg$f2(s1, s3, s7, s8, s9);
51447
51908
  }
51448
51909
  else {
51449
- peg$currPos = s9;
51450
- s9 = peg$FAILED;
51910
+ peg$currPos = s0;
51911
+ s0 = peg$FAILED;
51451
51912
  }
51452
51913
  }
51453
51914
  else {
51454
- peg$currPos = s9;
51455
- s9 = peg$FAILED;
51456
- }
51457
- if (s9 === peg$FAILED) {
51458
- s9 = null;
51915
+ peg$currPos = s0;
51916
+ s0 = peg$FAILED;
51459
51917
  }
51460
- peg$savedPos = s0;
51461
- s0 = peg$f2(s1, s3, s7, s8, s9);
51462
51918
  }
51463
51919
  else {
51464
51920
  peg$currPos = s0;
@@ -51486,22 +51942,28 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51486
51942
  }
51487
51943
  if (s0 === peg$FAILED) {
51488
51944
  s0 = peg$currPos;
51489
- s1 = peg$parsepriority();
51490
- if (s1 === peg$FAILED) {
51491
- s1 = null;
51492
- }
51493
- s2 = peg$parse_();
51494
- if (s2 === peg$FAILED) {
51495
- s2 = null;
51496
- }
51497
- s3 = peg$parseamount();
51498
- if (s3 !== peg$FAILED) {
51499
- s4 = peg$parselimit();
51500
- if (s4 === peg$FAILED) {
51501
- s4 = null;
51945
+ s1 = peg$parsetemplate();
51946
+ if (s1 !== peg$FAILED) {
51947
+ s2 = peg$parse_();
51948
+ if (s2 !== peg$FAILED) {
51949
+ s3 = peg$parseamount();
51950
+ if (s3 !== peg$FAILED) {
51951
+ s4 = peg$parselimit();
51952
+ if (s4 === peg$FAILED) {
51953
+ s4 = null;
51954
+ }
51955
+ peg$savedPos = s0;
51956
+ s0 = peg$f3(s1, s3, s4);
51957
+ }
51958
+ else {
51959
+ peg$currPos = s0;
51960
+ s0 = peg$FAILED;
51961
+ }
51962
+ }
51963
+ else {
51964
+ peg$currPos = s0;
51965
+ s0 = peg$FAILED;
51502
51966
  }
51503
- peg$savedPos = s0;
51504
- s0 = peg$f3(s1, s3, s4);
51505
51967
  }
51506
51968
  else {
51507
51969
  peg$currPos = s0;
@@ -51509,18 +51971,24 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51509
51971
  }
51510
51972
  if (s0 === peg$FAILED) {
51511
51973
  s0 = peg$currPos;
51512
- s1 = peg$parsepriority();
51513
- if (s1 === peg$FAILED) {
51514
- s1 = null;
51515
- }
51516
- s2 = peg$parse_();
51517
- if (s2 === peg$FAILED) {
51518
- s2 = null;
51519
- }
51520
- s3 = peg$parselimit();
51521
- if (s3 !== peg$FAILED) {
51522
- peg$savedPos = s0;
51523
- s0 = peg$f4(s1, s3);
51974
+ s1 = peg$parsetemplate();
51975
+ if (s1 !== peg$FAILED) {
51976
+ s2 = peg$parse_();
51977
+ if (s2 !== peg$FAILED) {
51978
+ s3 = peg$parselimit();
51979
+ if (s3 !== peg$FAILED) {
51980
+ peg$savedPos = s0;
51981
+ s0 = peg$f4(s1, s3);
51982
+ }
51983
+ else {
51984
+ peg$currPos = s0;
51985
+ s0 = peg$FAILED;
51986
+ }
51987
+ }
51988
+ else {
51989
+ peg$currPos = s0;
51990
+ s0 = peg$FAILED;
51991
+ }
51524
51992
  }
51525
51993
  else {
51526
51994
  peg$currPos = s0;
@@ -51528,26 +51996,32 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51528
51996
  }
51529
51997
  if (s0 === peg$FAILED) {
51530
51998
  s0 = peg$currPos;
51531
- s1 = peg$parsepriority();
51532
- if (s1 === peg$FAILED) {
51533
- s1 = null;
51534
- }
51535
- s2 = peg$parse_();
51536
- if (s2 === peg$FAILED) {
51537
- s2 = null;
51538
- }
51539
- s3 = peg$parseschedule();
51540
- if (s3 !== peg$FAILED) {
51541
- s4 = peg$parse_();
51542
- if (s4 !== peg$FAILED) {
51543
- s5 = peg$parsefull();
51544
- if (s5 === peg$FAILED) {
51545
- s5 = null;
51546
- }
51547
- s6 = peg$parsename();
51548
- if (s6 !== peg$FAILED) {
51549
- peg$savedPos = s0;
51550
- s0 = peg$f5(s1, s5, s6);
51999
+ s1 = peg$parsetemplate();
52000
+ if (s1 !== peg$FAILED) {
52001
+ s2 = peg$parse_();
52002
+ if (s2 !== peg$FAILED) {
52003
+ s3 = peg$parseschedule();
52004
+ if (s3 !== peg$FAILED) {
52005
+ s4 = peg$parse_();
52006
+ if (s4 !== peg$FAILED) {
52007
+ s5 = peg$parsefull();
52008
+ if (s5 === peg$FAILED) {
52009
+ s5 = null;
52010
+ }
52011
+ s6 = peg$parsename();
52012
+ if (s6 !== peg$FAILED) {
52013
+ peg$savedPos = s0;
52014
+ s0 = peg$f5(s1, s5, s6);
52015
+ }
52016
+ else {
52017
+ peg$currPos = s0;
52018
+ s0 = peg$FAILED;
52019
+ }
52020
+ }
52021
+ else {
52022
+ peg$currPos = s0;
52023
+ s0 = peg$FAILED;
52024
+ }
51551
52025
  }
51552
52026
  else {
51553
52027
  peg$currPos = s0;
@@ -51565,18 +52039,28 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51565
52039
  }
51566
52040
  if (s0 === peg$FAILED) {
51567
52041
  s0 = peg$currPos;
51568
- s1 = peg$parsepriority();
51569
- if (s1 === peg$FAILED) {
51570
- s1 = null;
51571
- }
51572
- s2 = peg$parse_();
51573
- if (s2 === peg$FAILED) {
51574
- s2 = null;
51575
- }
51576
- s3 = peg$parseremainder();
51577
- if (s3 !== peg$FAILED) {
51578
- peg$savedPos = s0;
51579
- s0 = peg$f6(s1, s3);
52042
+ s1 = peg$parsetemplate();
52043
+ if (s1 !== peg$FAILED) {
52044
+ s2 = peg$parse_();
52045
+ if (s2 !== peg$FAILED) {
52046
+ s3 = peg$parseremainder();
52047
+ if (s3 !== peg$FAILED) {
52048
+ s4 = peg$parselimit();
52049
+ if (s4 === peg$FAILED) {
52050
+ s4 = null;
52051
+ }
52052
+ peg$savedPos = s0;
52053
+ s0 = peg$f6(s1, s3, s4);
52054
+ }
52055
+ else {
52056
+ peg$currPos = s0;
52057
+ s0 = peg$FAILED;
52058
+ }
52059
+ }
52060
+ else {
52061
+ peg$currPos = s0;
52062
+ s0 = peg$FAILED;
52063
+ }
51580
52064
  }
51581
52065
  else {
51582
52066
  peg$currPos = s0;
@@ -51584,46 +52068,52 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51584
52068
  }
51585
52069
  if (s0 === peg$FAILED) {
51586
52070
  s0 = peg$currPos;
51587
- s1 = peg$parsepriority();
51588
- if (s1 === peg$FAILED) {
51589
- s1 = null;
51590
- }
51591
- s2 = peg$parse_();
51592
- if (s2 === peg$FAILED) {
51593
- s2 = null;
51594
- }
51595
- if (input.substr(peg$currPos, 7).toLowerCase() === peg$c0) {
51596
- s3 = input.substr(peg$currPos, 7);
51597
- peg$currPos += 7;
51598
- }
51599
- else {
51600
- s3 = peg$FAILED;
51601
- if (peg$silentFails === 0) {
51602
- peg$fail(peg$e0);
51603
- }
51604
- }
51605
- if (s3 !== peg$FAILED) {
51606
- s4 = peg$parse_();
51607
- if (s4 !== peg$FAILED) {
51608
- s5 = peg$parsepositive();
51609
- if (s5 !== peg$FAILED) {
51610
- s6 = peg$parse_();
51611
- if (s6 !== peg$FAILED) {
51612
- if (input.substr(peg$currPos, 6).toLowerCase() === peg$c1) {
51613
- s7 = input.substr(peg$currPos, 6);
51614
- peg$currPos += 6;
51615
- }
51616
- else {
51617
- s7 = peg$FAILED;
51618
- if (peg$silentFails === 0) {
51619
- peg$fail(peg$e1);
52071
+ s1 = peg$parsetemplate();
52072
+ if (s1 !== peg$FAILED) {
52073
+ s2 = peg$parse_();
52074
+ if (s2 !== peg$FAILED) {
52075
+ if (input.substr(peg$currPos, 7).toLowerCase() === peg$c0) {
52076
+ s3 = input.substr(peg$currPos, 7);
52077
+ peg$currPos += 7;
52078
+ }
52079
+ else {
52080
+ s3 = peg$FAILED;
52081
+ if (peg$silentFails === 0) {
52082
+ peg$fail(peg$e0);
52083
+ }
52084
+ }
52085
+ if (s3 !== peg$FAILED) {
52086
+ s4 = peg$parse_();
52087
+ if (s4 !== peg$FAILED) {
52088
+ s5 = peg$parsepositive();
52089
+ if (s5 !== peg$FAILED) {
52090
+ s6 = peg$parse_();
52091
+ if (s6 !== peg$FAILED) {
52092
+ if (input.substr(peg$currPos, 6).toLowerCase() === peg$c1) {
52093
+ s7 = input.substr(peg$currPos, 6);
52094
+ peg$currPos += 6;
52095
+ }
52096
+ else {
52097
+ s7 = peg$FAILED;
52098
+ if (peg$silentFails === 0) {
52099
+ peg$fail(peg$e1);
52100
+ }
52101
+ }
52102
+ if (s7 === peg$FAILED) {
52103
+ s7 = null;
52104
+ }
52105
+ peg$savedPos = s0;
52106
+ s0 = peg$f7(s1, s5);
52107
+ }
52108
+ else {
52109
+ peg$currPos = s0;
52110
+ s0 = peg$FAILED;
51620
52111
  }
51621
52112
  }
51622
- if (s7 === peg$FAILED) {
51623
- s7 = null;
52113
+ else {
52114
+ peg$currPos = s0;
52115
+ s0 = peg$FAILED;
51624
52116
  }
51625
- peg$savedPos = s0;
51626
- s0 = peg$f7(s1, s5);
51627
52117
  }
51628
52118
  else {
51629
52119
  peg$currPos = s0;
@@ -51644,6 +52134,25 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51644
52134
  peg$currPos = s0;
51645
52135
  s0 = peg$FAILED;
51646
52136
  }
52137
+ if (s0 === peg$FAILED) {
52138
+ s0 = peg$currPos;
52139
+ s1 = peg$parsegoal();
52140
+ if (s1 !== peg$FAILED) {
52141
+ s2 = peg$parseamount();
52142
+ if (s2 !== peg$FAILED) {
52143
+ peg$savedPos = s0;
52144
+ s0 = peg$f8(s1, s2);
52145
+ }
52146
+ else {
52147
+ peg$currPos = s0;
52148
+ s0 = peg$FAILED;
52149
+ }
52150
+ }
52151
+ else {
52152
+ peg$currPos = s0;
52153
+ s0 = peg$FAILED;
52154
+ }
52155
+ }
51647
52156
  }
51648
52157
  }
51649
52158
  }
@@ -51669,7 +52178,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51669
52178
  }
51670
52179
  if (s1 !== peg$FAILED) {
51671
52180
  peg$savedPos = s0;
51672
- s1 = peg$f8();
52181
+ s1 = peg$f9();
51673
52182
  }
51674
52183
  s0 = s1;
51675
52184
  if (s0 === peg$FAILED) {
@@ -51690,7 +52199,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51690
52199
  }
51691
52200
  if (s3 !== peg$FAILED) {
51692
52201
  peg$savedPos = s0;
51693
- s0 = peg$f9(s1);
52202
+ s0 = peg$f10(s1);
51694
52203
  }
51695
52204
  else {
51696
52205
  peg$currPos = s0;
@@ -51720,7 +52229,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51720
52229
  }
51721
52230
  if (s1 !== peg$FAILED) {
51722
52231
  peg$savedPos = s0;
51723
- s1 = peg$f10();
52232
+ s1 = peg$f11();
51724
52233
  }
51725
52234
  s0 = s1;
51726
52235
  if (s0 === peg$FAILED) {
@@ -51741,7 +52250,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51741
52250
  }
51742
52251
  if (s3 !== peg$FAILED) {
51743
52252
  peg$savedPos = s0;
51744
- s0 = peg$f11(s1);
52253
+ s0 = peg$f12(s1);
51745
52254
  }
51746
52255
  else {
51747
52256
  peg$currPos = s0;
@@ -51796,7 +52305,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51796
52305
  }
51797
52306
  if (s6 !== peg$FAILED) {
51798
52307
  peg$savedPos = s0;
51799
- s0 = peg$f12(s4);
52308
+ s0 = peg$f13(s4);
51800
52309
  }
51801
52310
  else {
51802
52311
  peg$currPos = s0;
@@ -51835,7 +52344,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51835
52344
  s4 = peg$parseamount();
51836
52345
  if (s4 !== peg$FAILED) {
51837
52346
  peg$savedPos = s0;
51838
- s0 = peg$f13(s4);
52347
+ s0 = peg$f14(s4);
51839
52348
  }
51840
52349
  else {
51841
52350
  peg$currPos = s0;
@@ -51879,7 +52388,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51879
52388
  s6 = peg$parse_();
51880
52389
  if (s6 !== peg$FAILED) {
51881
52390
  peg$savedPos = s0;
51882
- s0 = peg$f14(s1);
52391
+ s0 = peg$f15(s1);
51883
52392
  }
51884
52393
  else {
51885
52394
  peg$currPos = s0;
@@ -51921,7 +52430,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51921
52430
  s4 = peg$parse_();
51922
52431
  if (s4 !== peg$FAILED) {
51923
52432
  peg$savedPos = s0;
51924
- s0 = peg$f15(s1);
52433
+ s0 = peg$f16(s1);
51925
52434
  }
51926
52435
  else {
51927
52436
  peg$currPos = s0;
@@ -51951,7 +52460,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51951
52460
  s1 = peg$parseweek();
51952
52461
  if (s1 !== peg$FAILED) {
51953
52462
  peg$savedPos = s0;
51954
- s1 = peg$f16();
52463
+ s1 = peg$f17();
51955
52464
  }
51956
52465
  s0 = s1;
51957
52466
  if (s0 === peg$FAILED) {
@@ -51963,7 +52472,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
51963
52472
  s3 = peg$parseweeks();
51964
52473
  if (s3 !== peg$FAILED) {
51965
52474
  peg$savedPos = s0;
51966
- s0 = peg$f17(s1);
52475
+ s0 = peg$f18(s1);
51967
52476
  }
51968
52477
  else {
51969
52478
  peg$currPos = s0;
@@ -52016,7 +52525,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52016
52525
  s6 = peg$parsemonth();
52017
52526
  if (s6 !== peg$FAILED) {
52018
52527
  peg$savedPos = s0;
52019
- s0 = peg$f18(s6);
52528
+ s0 = peg$f19(s6);
52020
52529
  }
52021
52530
  else {
52022
52531
  peg$currPos = s0;
@@ -52242,7 +52751,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52242
52751
  s2 = peg$parse_();
52243
52752
  if (s2 !== peg$FAILED) {
52244
52753
  peg$savedPos = s0;
52245
- s0 = peg$f19();
52754
+ s0 = peg$f20();
52246
52755
  }
52247
52756
  else {
52248
52757
  peg$currPos = s0;
@@ -52256,7 +52765,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52256
52765
  return s0;
52257
52766
  }
52258
52767
  function peg$parsepriority() {
52259
- var s0, s1, s2, s3;
52768
+ var s0, s1, s2;
52260
52769
  s0 = peg$currPos;
52261
52770
  if (input.substr(peg$currPos, 1).toLowerCase() === peg$c20) {
52262
52771
  s1 = input.charAt(peg$currPos);
@@ -52271,15 +52780,8 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52271
52780
  if (s1 !== peg$FAILED) {
52272
52781
  s2 = peg$parsenumber();
52273
52782
  if (s2 !== peg$FAILED) {
52274
- s3 = peg$parse_();
52275
- if (s3 !== peg$FAILED) {
52276
- peg$savedPos = s0;
52277
- s0 = peg$f20(s2);
52278
- }
52279
- else {
52280
- peg$currPos = s0;
52281
- s0 = peg$FAILED;
52282
- }
52783
+ peg$savedPos = s0;
52784
+ s0 = peg$f21(s2);
52283
52785
  }
52284
52786
  else {
52285
52787
  peg$currPos = s0;
@@ -52315,7 +52817,34 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52315
52817
  s3 = null;
52316
52818
  }
52317
52819
  peg$savedPos = s0;
52318
- s0 = peg$f21(s3);
52820
+ s0 = peg$f22(s3);
52821
+ }
52822
+ else {
52823
+ peg$currPos = s0;
52824
+ s0 = peg$FAILED;
52825
+ }
52826
+ return s0;
52827
+ }
52828
+ function peg$parsetemplate() {
52829
+ var s0, s1, s2;
52830
+ s0 = peg$currPos;
52831
+ if (input.substr(peg$currPos, 9) === peg$c22) {
52832
+ s1 = peg$c22;
52833
+ peg$currPos += 9;
52834
+ }
52835
+ else {
52836
+ s1 = peg$FAILED;
52837
+ if (peg$silentFails === 0) {
52838
+ peg$fail(peg$e23);
52839
+ }
52840
+ }
52841
+ if (s1 !== peg$FAILED) {
52842
+ s2 = peg$parsepriority();
52843
+ if (s2 === peg$FAILED) {
52844
+ s2 = null;
52845
+ }
52846
+ peg$savedPos = s0;
52847
+ s0 = peg$f23(s2);
52319
52848
  }
52320
52849
  else {
52321
52850
  peg$currPos = s0;
@@ -52323,31 +52852,45 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52323
52852
  }
52324
52853
  return s0;
52325
52854
  }
52855
+ function peg$parsegoal() {
52856
+ var s0;
52857
+ if (input.substr(peg$currPos, 5) === peg$c23) {
52858
+ s0 = peg$c23;
52859
+ peg$currPos += 5;
52860
+ }
52861
+ else {
52862
+ s0 = peg$FAILED;
52863
+ if (peg$silentFails === 0) {
52864
+ peg$fail(peg$e24);
52865
+ }
52866
+ }
52867
+ return s0;
52868
+ }
52326
52869
  function peg$parse_() {
52327
52870
  var s0, s1;
52328
52871
  peg$silentFails++;
52329
52872
  s0 = [];
52330
52873
  if (input.charCodeAt(peg$currPos) === 32) {
52331
- s1 = peg$c22;
52874
+ s1 = peg$c24;
52332
52875
  peg$currPos++;
52333
52876
  }
52334
52877
  else {
52335
52878
  s1 = peg$FAILED;
52336
52879
  if (peg$silentFails === 0) {
52337
- peg$fail(peg$e24);
52880
+ peg$fail(peg$e26);
52338
52881
  }
52339
52882
  }
52340
52883
  if (s1 !== peg$FAILED) {
52341
52884
  while (s1 !== peg$FAILED) {
52342
52885
  s0.push(s1);
52343
52886
  if (input.charCodeAt(peg$currPos) === 32) {
52344
- s1 = peg$c22;
52887
+ s1 = peg$c24;
52345
52888
  peg$currPos++;
52346
52889
  }
52347
52890
  else {
52348
52891
  s1 = peg$FAILED;
52349
52892
  if (peg$silentFails === 0) {
52350
- peg$fail(peg$e24);
52893
+ peg$fail(peg$e26);
52351
52894
  }
52352
52895
  }
52353
52896
  }
@@ -52359,7 +52902,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52359
52902
  if (s0 === peg$FAILED) {
52360
52903
  s1 = peg$FAILED;
52361
52904
  if (peg$silentFails === 0) {
52362
- peg$fail(peg$e23);
52905
+ peg$fail(peg$e25);
52363
52906
  }
52364
52907
  }
52365
52908
  return s0;
@@ -52374,14 +52917,14 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52374
52917
  else {
52375
52918
  s0 = peg$FAILED;
52376
52919
  if (peg$silentFails === 0) {
52377
- peg$fail(peg$e26);
52920
+ peg$fail(peg$e28);
52378
52921
  }
52379
52922
  }
52380
52923
  peg$silentFails--;
52381
52924
  if (s0 === peg$FAILED) {
52382
52925
  s1 = peg$FAILED;
52383
52926
  if (peg$silentFails === 0) {
52384
- peg$fail(peg$e25);
52927
+ peg$fail(peg$e27);
52385
52928
  }
52386
52929
  }
52387
52930
  return s0;
@@ -52411,7 +52954,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52411
52954
  if (s0 === peg$FAILED) {
52412
52955
  s1 = peg$FAILED;
52413
52956
  if (peg$silentFails === 0) {
52414
- peg$fail(peg$e27);
52957
+ peg$fail(peg$e29);
52415
52958
  }
52416
52959
  }
52417
52960
  return s0;
@@ -52427,7 +52970,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52427
52970
  else {
52428
52971
  s2 = peg$FAILED;
52429
52972
  if (peg$silentFails === 0) {
52430
- peg$fail(peg$e28);
52973
+ peg$fail(peg$e30);
52431
52974
  }
52432
52975
  }
52433
52976
  if (s2 !== peg$FAILED) {
@@ -52439,7 +52982,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52439
52982
  else {
52440
52983
  s4 = peg$FAILED;
52441
52984
  if (peg$silentFails === 0) {
52442
- peg$fail(peg$e26);
52985
+ peg$fail(peg$e28);
52443
52986
  }
52444
52987
  }
52445
52988
  while (s4 !== peg$FAILED) {
@@ -52451,7 +52994,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52451
52994
  else {
52452
52995
  s4 = peg$FAILED;
52453
52996
  if (peg$silentFails === 0) {
52454
- peg$fail(peg$e26);
52997
+ peg$fail(peg$e28);
52455
52998
  }
52456
52999
  }
52457
53000
  }
@@ -52498,13 +53041,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52498
53041
  if (s5 !== peg$FAILED) {
52499
53042
  s6 = peg$currPos;
52500
53043
  if (input.charCodeAt(peg$currPos) === 46) {
52501
- s7 = peg$c23;
53044
+ s7 = peg$c25;
52502
53045
  peg$currPos++;
52503
53046
  }
52504
53047
  else {
52505
53048
  s7 = peg$FAILED;
52506
53049
  if (peg$silentFails === 0) {
52507
- peg$fail(peg$e30);
53050
+ peg$fail(peg$e32);
52508
53051
  }
52509
53052
  }
52510
53053
  if (s7 !== peg$FAILED) {
@@ -52550,7 +53093,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52550
53093
  }
52551
53094
  if (s3 !== peg$FAILED) {
52552
53095
  peg$savedPos = s0;
52553
- s0 = peg$f22(s3);
53096
+ s0 = peg$f24(s3);
52554
53097
  }
52555
53098
  else {
52556
53099
  peg$currPos = s0;
@@ -52560,7 +53103,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52560
53103
  if (s0 === peg$FAILED) {
52561
53104
  s1 = peg$FAILED;
52562
53105
  if (peg$silentFails === 0) {
52563
- peg$fail(peg$e29);
53106
+ peg$fail(peg$e31);
52564
53107
  }
52565
53108
  }
52566
53109
  return s0;
@@ -52585,13 +53128,13 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52585
53128
  if (s3 !== peg$FAILED) {
52586
53129
  s4 = peg$currPos;
52587
53130
  if (input.charCodeAt(peg$currPos) === 46) {
52588
- s5 = peg$c23;
53131
+ s5 = peg$c25;
52589
53132
  peg$currPos++;
52590
53133
  }
52591
53134
  else {
52592
53135
  s5 = peg$FAILED;
52593
53136
  if (peg$silentFails === 0) {
52594
- peg$fail(peg$e30);
53137
+ peg$fail(peg$e32);
52595
53138
  }
52596
53139
  }
52597
53140
  if (s5 !== peg$FAILED) {
@@ -52638,18 +53181,18 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52638
53181
  s2 = null;
52639
53182
  }
52640
53183
  if (input.charCodeAt(peg$currPos) === 37) {
52641
- s3 = peg$c24;
53184
+ s3 = peg$c26;
52642
53185
  peg$currPos++;
52643
53186
  }
52644
53187
  else {
52645
53188
  s3 = peg$FAILED;
52646
53189
  if (peg$silentFails === 0) {
52647
- peg$fail(peg$e32);
53190
+ peg$fail(peg$e34);
52648
53191
  }
52649
53192
  }
52650
53193
  if (s3 !== peg$FAILED) {
52651
53194
  peg$savedPos = s0;
52652
- s0 = peg$f23(s1);
53195
+ s0 = peg$f25(s1);
52653
53196
  }
52654
53197
  else {
52655
53198
  peg$currPos = s0;
@@ -52664,7 +53207,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52664
53207
  if (s0 === peg$FAILED) {
52665
53208
  s1 = peg$FAILED;
52666
53209
  if (peg$silentFails === 0) {
52667
- peg$fail(peg$e31);
53210
+ peg$fail(peg$e33);
52668
53211
  }
52669
53212
  }
52670
53213
  return s0;
@@ -52714,7 +53257,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52714
53257
  if (s0 === peg$FAILED) {
52715
53258
  s1 = peg$FAILED;
52716
53259
  if (peg$silentFails === 0) {
52717
- peg$fail(peg$e33);
53260
+ peg$fail(peg$e35);
52718
53261
  }
52719
53262
  }
52720
53263
  return s0;
@@ -52733,7 +53276,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52733
53276
  else {
52734
53277
  s3 = peg$FAILED;
52735
53278
  if (peg$silentFails === 0) {
52736
- peg$fail(peg$e35);
53279
+ peg$fail(peg$e37);
52737
53280
  }
52738
53281
  }
52739
53282
  if (s3 !== peg$FAILED) {
@@ -52773,7 +53316,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52773
53316
  if (s0 === peg$FAILED) {
52774
53317
  s1 = peg$FAILED;
52775
53318
  if (peg$silentFails === 0) {
52776
- peg$fail(peg$e34);
53319
+ peg$fail(peg$e36);
52777
53320
  }
52778
53321
  }
52779
53322
  return s0;
@@ -52809,7 +53352,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52809
53352
  if (s0 === peg$FAILED) {
52810
53353
  s1 = peg$FAILED;
52811
53354
  if (peg$silentFails === 0) {
52812
- peg$fail(peg$e36);
53355
+ peg$fail(peg$e38);
52813
53356
  }
52814
53357
  }
52815
53358
  return s0;
@@ -52827,7 +53370,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52827
53370
  else {
52828
53371
  s3 = peg$FAILED;
52829
53372
  if (peg$silentFails === 0) {
52830
- peg$fail(peg$e35);
53373
+ peg$fail(peg$e37);
52831
53374
  }
52832
53375
  }
52833
53376
  if (s3 !== peg$FAILED) {
@@ -52869,12 +53412,12 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52869
53412
  else {
52870
53413
  s1 = peg$FAILED;
52871
53414
  if (peg$silentFails === 0) {
52872
- peg$fail(peg$e38);
53415
+ peg$fail(peg$e40);
52873
53416
  }
52874
53417
  }
52875
53418
  if (s1 !== peg$FAILED) {
52876
53419
  peg$savedPos = peg$currPos;
52877
- s2 = peg$f24(s1);
53420
+ s2 = peg$f26(s1);
52878
53421
  if (s2) {
52879
53422
  s2 = undefined;
52880
53423
  }
@@ -52898,7 +53441,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52898
53441
  if (s0 === peg$FAILED) {
52899
53442
  s1 = peg$FAILED;
52900
53443
  if (peg$silentFails === 0) {
52901
- peg$fail(peg$e37);
53444
+ peg$fail(peg$e39);
52902
53445
  }
52903
53446
  }
52904
53447
  return s0;
@@ -52915,7 +53458,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52915
53458
  else {
52916
53459
  s2 = peg$FAILED;
52917
53460
  if (peg$silentFails === 0) {
52918
- peg$fail(peg$e40);
53461
+ peg$fail(peg$e42);
52919
53462
  }
52920
53463
  }
52921
53464
  if (s2 !== peg$FAILED) {
@@ -52928,7 +53471,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52928
53471
  else {
52929
53472
  s2 = peg$FAILED;
52930
53473
  if (peg$silentFails === 0) {
52931
- peg$fail(peg$e40);
53474
+ peg$fail(peg$e42);
52932
53475
  }
52933
53476
  }
52934
53477
  }
@@ -52946,7 +53489,7 @@ CREATE TABLE kvcache_key (id INTEGER PRIMARY KEY, key REAL);
52946
53489
  if (s0 === peg$FAILED) {
52947
53490
  s1 = peg$FAILED;
52948
53491
  if (peg$silentFails === 0) {
52949
- peg$fail(peg$e39);
53492
+ peg$fail(peg$e41);
52950
53493
  }
52951
53494
  }
52952
53495
  return s0;