@actual-app/api 26.5.0-nightly.20260503 → 26.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -115080,9 +115080,8 @@ function getPayMonthOfTotal(t) {
115080
115080
  for (const schedule of schedules) total += schedule.target;
115081
115081
  return total;
115082
115082
  }
115083
- function getSinkingContributionBreakdown(t, remainder, last_month_balance) {
115083
+ async function getSinkingContributionTotal(t, remainder, last_month_balance) {
115084
115084
  let total = 0;
115085
- const perSchedule = /* @__PURE__ */ new Map();
115086
115085
  for (const [index, schedule] of t.entries()) {
115087
115086
  remainder = index === 0 ? schedule.target - last_month_balance : schedule.target - remainder;
115088
115087
  let tg = 0;
@@ -115093,37 +115092,41 @@ function getSinkingContributionBreakdown(t, remainder, last_month_balance) {
115093
115092
  tg = 0;
115094
115093
  remainder = Math.abs(remainder);
115095
115094
  }
115096
- const contribution = tg / (schedule.num_months + 1);
115097
- total += contribution;
115098
- perSchedule.set(schedule.name.trim(), (perSchedule.get(schedule.name.trim()) ?? 0) + contribution);
115099
- }
115100
- return {
115101
- total,
115102
- perSchedule
115103
- };
115104
- }
115105
- function getMonthlyBaseContribution(schedule) {
115106
- let prevDate;
115107
- let intervalMonths;
115108
- switch (schedule.target_frequency) {
115109
- case "yearly": return schedule.target / schedule.target_interval / 12;
115110
- case "monthly": return schedule.target / schedule.target_interval;
115111
- case "weekly":
115112
- prevDate = subWeeks(schedule.next_date_string, schedule.target_interval);
115113
- intervalMonths = differenceInCalendarMonths(schedule.next_date_string, prevDate);
115114
- if (intervalMonths === 0) intervalMonths = 1;
115115
- return schedule.target / intervalMonths;
115116
- case "daily":
115117
- prevDate = subDays(schedule.next_date_string, schedule.target_interval);
115118
- intervalMonths = differenceInCalendarMonths(schedule.next_date_string, prevDate);
115119
- if (intervalMonths === 0) intervalMonths = 1;
115120
- return schedule.target / intervalMonths;
115121
- default: return schedule.target / schedule.target_interval;
115095
+ total += tg / (schedule.num_months + 1);
115122
115096
  }
115097
+ return total;
115123
115098
  }
115124
115099
  function getSinkingBaseContributionTotal(t) {
115125
115100
  let total = 0;
115126
- for (const schedule of t) total += getMonthlyBaseContribution(schedule);
115101
+ for (const schedule of t) {
115102
+ let monthlyAmount = 0;
115103
+ let prevDate;
115104
+ let intervalMonths;
115105
+ switch (schedule.target_frequency) {
115106
+ case "yearly":
115107
+ monthlyAmount = schedule.target / schedule.target_interval / 12;
115108
+ break;
115109
+ case "monthly":
115110
+ monthlyAmount = schedule.target / schedule.target_interval;
115111
+ break;
115112
+ case "weekly":
115113
+ prevDate = subWeeks(schedule.next_date_string, schedule.target_interval);
115114
+ intervalMonths = differenceInCalendarMonths(schedule.next_date_string, prevDate);
115115
+ if (intervalMonths === 0) intervalMonths = 1;
115116
+ monthlyAmount = schedule.target / intervalMonths;
115117
+ break;
115118
+ case "daily":
115119
+ prevDate = subDays(schedule.next_date_string, schedule.target_interval);
115120
+ intervalMonths = differenceInCalendarMonths(schedule.next_date_string, prevDate);
115121
+ if (intervalMonths === 0) intervalMonths = 1;
115122
+ monthlyAmount = schedule.target / intervalMonths;
115123
+ break;
115124
+ default:
115125
+ monthlyAmount = schedule.target / schedule.target_interval;
115126
+ break;
115127
+ }
115128
+ total += monthlyAmount;
115129
+ }
115127
115130
  return total;
115128
115131
  }
115129
115132
  function getSinkingTotal(t) {
@@ -115143,26 +115146,16 @@ async function runSchedule(template_lines, current_month, balance, remainder, la
115143
115146
  const totalSinking = getSinkingTotal(t_sinking);
115144
115147
  const totalSinkingBaseContribution = getSinkingBaseContributionTotal(t_sinking);
115145
115148
  const lastMonthGoal = await getSheetValue(sheetForMonth(subMonths(current_month, 1)), `goal-${category.id}`);
115146
- const perScheduleMonthly = /* @__PURE__ */ new Map();
115147
- const addContribution = (name, amount) => {
115148
- perScheduleMonthly.set(name.trim(), (perScheduleMonthly.get(name.trim()) ?? 0) + amount);
115149
- };
115150
- if (balance >= totalSinking + totalPayMonthOf || lastMonthGoal < totalSinking + totalPayMonthOf && lastMonthGoal !== 0 && balance >= lastMonthGoal && numSubMonthly > 0) {
115151
- to_budget += Math.round(totalPayMonthOf + totalSinkingBaseContribution);
115152
- for (const c of t_payMonthOf) addContribution(c.name, c.target);
115153
- for (const c of t_sinking) addContribution(c.name, getMonthlyBaseContribution(c));
115154
- } else {
115155
- const { total: totalSinkingContribution, perSchedule: sinkingPerSchedule } = getSinkingContributionBreakdown(t_sinking, remainder, last_month_balance);
115149
+ if (balance >= totalSinking + totalPayMonthOf || lastMonthGoal < totalSinking + totalPayMonthOf && lastMonthGoal !== 0 && balance >= lastMonthGoal && numSubMonthly > 0) to_budget += Math.round(totalPayMonthOf + totalSinkingBaseContribution);
115150
+ else {
115151
+ const totalSinkingContribution = await getSinkingContributionTotal(t_sinking, remainder, last_month_balance);
115156
115152
  if (t_sinking.length === 0) to_budget += Math.round(totalPayMonthOf + totalSinkingContribution) - last_month_balance;
115157
115153
  else to_budget += Math.round(totalPayMonthOf + totalSinkingContribution);
115158
- for (const c of t_payMonthOf) addContribution(c.name, c.target);
115159
- for (const [name, amount] of sinkingPerSchedule) addContribution(name, amount);
115160
115154
  }
115161
115155
  return {
115162
115156
  to_budget,
115163
115157
  errors,
115164
- remainder,
115165
- perScheduleMonthly
115158
+ remainder
115166
115159
  };
115167
115160
  }
115168
115161
  //#endregion
@@ -117677,7 +117670,7 @@ async function getCategoriesWithTemplates() {
117677
117670
  return templatesForCategory;
117678
117671
  }
117679
117672
  function prefixFromPriority(priority) {
117680
- return priority === null || priority === 0 ? TEMPLATE_PREFIX : `${TEMPLATE_PREFIX}-${priority}`;
117673
+ return priority === null ? TEMPLATE_PREFIX : `${TEMPLATE_PREFIX}-${priority}`;
117681
117674
  }
117682
117675
  async function unparse(templates) {
117683
117676
  const refill = templates.find((t) => t.type === "refill");
@@ -117767,7 +117760,9 @@ function limitToString(limit) {
117767
117760
  }
117768
117761
  }
117769
117762
  function periodToString(p) {
117770
- return `${p.amount} ${p.period}s`;
117763
+ const { period, amount } = p;
117764
+ if (amount === 1) return period;
117765
+ return `${amount} ${period}s`;
117771
117766
  }
117772
117767
  function repeatToString(annual, repeat) {
117773
117768
  if (annual === void 0) return null;
@@ -117856,12 +117851,9 @@ var CategoryTemplateContext = class CategoryTemplateContext {
117856
117851
  const t = this.templates.filter((t) => t.directive === "template" && t.priority === priority);
117857
117852
  let available = budgetAvail || 0;
117858
117853
  let toBudget = 0;
117859
- const perTemplateLocal = /* @__PURE__ */ new Map();
117860
117854
  let byFlag = false;
117861
117855
  let remainder = 0;
117862
117856
  let scheduleFlag = false;
117863
- let schedulePerTemplate = null;
117864
- let byPerTemplate = null;
117865
117857
  for (const template of t) {
117866
117858
  let newBudget = 0;
117867
117859
  switch (template.type) {
@@ -117884,11 +117876,8 @@ var CategoryTemplateContext = class CategoryTemplateContext {
117884
117876
  newBudget = await CategoryTemplateContext.runPercentage(template, availStart, this);
117885
117877
  break;
117886
117878
  case "by":
117887
- if (!byFlag) {
117888
- const ret = CategoryTemplateContext.runBy(this);
117889
- newBudget = ret.toBudget;
117890
- byPerTemplate = ret.perTemplateNeed;
117891
- } else newBudget = 0;
117879
+ if (!byFlag) newBudget = CategoryTemplateContext.runBy(this);
117880
+ else newBudget = 0;
117892
117881
  byFlag = true;
117893
117882
  break;
117894
117883
  case "schedule":
@@ -117897,7 +117886,6 @@ var CategoryTemplateContext = class CategoryTemplateContext {
117897
117886
  const ret = await runSchedule(t, this.month, budgeted, remainder, this.fromLastMonth, toBudget, [], this.category, this.currency);
117898
117887
  newBudget = ret.to_budget - toBudget;
117899
117888
  remainder = ret.remainder;
117900
- schedulePerTemplate = ret.perScheduleMonthly;
117901
117889
  scheduleFlag = true;
117902
117890
  }
117903
117891
  break;
@@ -117908,51 +117896,24 @@ var CategoryTemplateContext = class CategoryTemplateContext {
117908
117896
  }
117909
117897
  available = available - newBudget;
117910
117898
  toBudget += newBudget;
117911
- perTemplateLocal.set(template, (perTemplateLocal.get(template) ?? 0) + newBudget);
117912
117899
  }
117913
- redistributeBatch(perTemplateLocal, t, "by", (template) => {
117914
- if (template.type !== "by") return 0;
117915
- return Math.max(0, byPerTemplate?.get(template) ?? 0);
117916
- });
117917
- redistributeBatch(perTemplateLocal, t, "schedule", (template) => {
117918
- if (template.type !== "schedule") return 0;
117919
- const monthly = schedulePerTemplate?.get(template.name.trim()) ?? 0;
117920
- return Math.max(0, monthly);
117921
- });
117922
- let scale = 1;
117923
117900
  if (this.limitCheck) {
117924
117901
  if (toBudget + this.toBudgetAmount + this.fromLastMonth >= this.limitAmount) {
117925
117902
  const orig = toBudget;
117926
117903
  toBudget = this.limitAmount - this.toBudgetAmount - this.fromLastMonth;
117927
117904
  this.limitMet = true;
117928
117905
  available = available + orig - toBudget;
117929
- if (orig > 0) scale *= toBudget / orig;
117930
117906
  }
117931
117907
  }
117932
- if (this.hideDecimal) {
117933
- const preRound = toBudget;
117934
- toBudget = this.removeFraction(toBudget);
117935
- if (preRound !== 0) scale *= toBudget / preRound;
117936
- }
117908
+ if (this.hideDecimal) toBudget = this.removeFraction(toBudget);
117937
117909
  if (priority > 0 && available < 0 && !this.category.is_income) {
117938
117910
  this.fullAmount = (this.fullAmount || 0) + toBudget;
117939
- const adjusted = Math.max(0, toBudget + available);
117940
- if (toBudget > 0) scale *= adjusted / toBudget;
117941
- toBudget = adjusted;
117911
+ toBudget = Math.max(0, toBudget + available);
117942
117912
  this.toBudgetAmount += toBudget;
117943
117913
  } else {
117944
117914
  this.fullAmount = (this.fullAmount || 0) + toBudget;
117945
117915
  this.toBudgetAmount += toBudget;
117946
117916
  }
117947
- const perRowScale = Math.max(0, scale);
117948
- const items = Array.from(perTemplateLocal);
117949
- let remaining = Math.max(0, toBudget);
117950
- items.forEach(([template, value], i) => {
117951
- const share = i === items.length - 1 ? remaining : Math.max(0, Math.min(remaining, Math.round(value * perRowScale)));
117952
- const existing = this.perTemplateContribution.get(template) ?? 0;
117953
- this.perTemplateContribution.set(template, existing + share);
117954
- remaining -= share;
117955
- });
117956
117917
  return this.category.is_income ? -toBudget : toBudget;
117957
117918
  }
117958
117919
  runRemainder(budgetAvail, perWeight) {
@@ -117970,17 +117931,6 @@ var CategoryTemplateContext = class CategoryTemplateContext {
117970
117931
  this.limitMet = true;
117971
117932
  }
117972
117933
  }
117973
- if (toBudget > 0 && this.remainderWeight > 0) {
117974
- let remaining = toBudget;
117975
- for (let i = 0; i < this.remainder.length; i++) {
117976
- const template = this.remainder[i];
117977
- const share = i === this.remainder.length - 1 ? remaining : Math.round(toBudget * (template.weight / this.remainderWeight));
117978
- const allocated = Math.max(0, Math.min(share, remaining));
117979
- const existing = this.perTemplateContribution.get(template) ?? 0;
117980
- this.perTemplateContribution.set(template, existing + allocated);
117981
- remaining -= allocated;
117982
- }
117983
- }
117984
117934
  this.toBudgetAmount += toBudget;
117985
117935
  return toBudget;
117986
117936
  }
@@ -117989,8 +117939,7 @@ var CategoryTemplateContext = class CategoryTemplateContext {
117989
117939
  return {
117990
117940
  budgeted: this.toBudgetAmount,
117991
117941
  goal: this.goalAmount,
117992
- longGoal: this.isLongGoal,
117993
- perTemplateContribution: this.perTemplateContribution
117942
+ longGoal: this.isLongGoal
117994
117943
  };
117995
117944
  }
117996
117945
  category;
@@ -118002,7 +117951,6 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118002
117951
  hideDecimal = false;
118003
117952
  remainderWeight = 0;
118004
117953
  toBudgetAmount = 0;
118005
- perTemplateContribution = /* @__PURE__ */ new Map();
118006
117954
  fullAmount = null;
118007
117955
  isLongGoal = null;
118008
117956
  goalAmount = null;
@@ -118060,15 +118008,10 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118060
118008
  static async checkPercentage(templates) {
118061
118009
  const pt = templates.filter((t) => t.type === "percentage");
118062
118010
  if (pt.length === 0) return;
118063
- const incomeCategories = (await getCategories$3()).filter((c) => c.is_income);
118064
- const availNames = new Set(incomeCategories.map((c) => c.name.toLocaleLowerCase()));
118065
- const availIds = new Set(incomeCategories.map((c) => c.id));
118066
- const specialSources = new Set(["all income", "available funds"]);
118067
- pt.forEach((t) => {
118068
- const raw = t.category;
118069
- const lowered = raw.toLocaleLowerCase();
118070
- if (specialSources.has(lowered) || availNames.has(lowered) || availIds.has(raw)) return;
118071
- throw new Error(`Category \x22${raw}\x22 is not found in available income categories`);
118011
+ const reqCategories = pt.map((t) => t.category.toLowerCase());
118012
+ const availNames = (await getCategories$3()).filter((c) => c.is_income).map((c) => c.name.toLocaleLowerCase());
118013
+ reqCategories.forEach((n) => {
118014
+ if (n === "available funds" || n === "all income") {} else if (!availNames.includes(n)) throw new Error(`Category \x22${n}\x22 is not found in available income categories`);
118072
118015
  });
118073
118016
  }
118074
118017
  checkLimit(templates) {
@@ -118132,7 +118075,7 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118132
118075
  const amount = amountToInteger$1(template.amount, templateContext.currency.decimalPlaces);
118133
118076
  const period = template.period.period;
118134
118077
  const numPeriods = template.period.amount;
118135
- let date = template.starting && template.starting.length > 0 ? template.starting : firstDayOfMonth(templateContext.month);
118078
+ let date = template.starting ?? firstDayOfMonth(templateContext.month);
118136
118079
  let dateShiftFunction;
118137
118080
  switch (period) {
118138
118081
  case "day":
@@ -118185,7 +118128,7 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118185
118128
  }
118186
118129
  static async runPercentage(template, availableFunds, templateContext) {
118187
118130
  const percent = template.percent;
118188
- const cat = template.category.toLocaleLowerCase();
118131
+ const cat = template.category.toLowerCase();
118189
118132
  const prev = template.previous;
118190
118133
  let sheetName;
118191
118134
  let monthlyIncome;
@@ -118194,7 +118137,7 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118194
118137
  if (cat === "all income") monthlyIncome = await getSheetValue(sheetName, `total-income`);
118195
118138
  else if (cat === "available funds") monthlyIncome = availableFunds;
118196
118139
  else {
118197
- const incomeCat = (await getCategories$3()).find((c) => c.is_income && (c.id === template.category || c.name.toLocaleLowerCase() === cat));
118140
+ const incomeCat = (await getCategories$3()).find((c) => c.is_income && c.name.toLowerCase() === cat);
118198
118141
  if (!incomeCat) throw new Error(`Income category "${template.category}" not found for percentage template`);
118199
118142
  monthlyIncome = await getSheetValue(sheetName, `sum-amount-${incomeCat.id}`);
118200
118143
  }
@@ -118239,7 +118182,6 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118239
118182
  if (workingShortNumMonths === void 0 || numMonths < workingShortNumMonths) workingShortNumMonths = numMonths;
118240
118183
  }
118241
118184
  const shortNumMonths = workingShortNumMonths || 0;
118242
- const perTemplateNeed = /* @__PURE__ */ new Map();
118243
118185
  for (let i = 0; i < byTemplates.length; i++) {
118244
118186
  const template = byTemplates[i];
118245
118187
  const numMonths = savedInfo[i].numMonths;
@@ -118248,43 +118190,11 @@ var CategoryTemplateContext = class CategoryTemplateContext {
118248
118190
  if (numMonths > shortNumMonths && period) amount = Math.round(amountToInteger$1(template.amount, templateContext.currency.decimalPlaces) / period * (period - numMonths + shortNumMonths));
118249
118191
  else if (numMonths > shortNumMonths) amount = Math.round(amountToInteger$1(template.amount, templateContext.currency.decimalPlaces) / (numMonths + 1) * (shortNumMonths + 1));
118250
118192
  else amount = amountToInteger$1(template.amount, templateContext.currency.decimalPlaces);
118251
- perTemplateNeed.set(template, amount);
118252
118193
  totalNeeded += amount;
118253
118194
  }
118254
- return {
118255
- toBudget: Math.round((totalNeeded - templateContext.fromLastMonth) / (shortNumMonths + 1)),
118256
- perTemplateNeed
118257
- };
118195
+ return Math.round((totalNeeded - templateContext.fromLastMonth) / (shortNumMonths + 1));
118258
118196
  }
118259
118197
  };
118260
- function redistributeBatch(perTemplateLocal, templates, type, weightOf) {
118261
- const siblings = templates.filter((template) => template.type === type);
118262
- if (siblings.length < 2) return;
118263
- let total = 0;
118264
- for (const sibling of siblings) {
118265
- total += perTemplateLocal.get(sibling) ?? 0;
118266
- perTemplateLocal.set(sibling, 0);
118267
- }
118268
- if (total === 0) return;
118269
- const totalWeight = siblings.reduce((sum, s) => sum + weightOf(s), 0);
118270
- if (totalWeight <= 0) {
118271
- let remaining = total;
118272
- siblings.forEach((sibling, i) => {
118273
- const share = i === siblings.length - 1 ? remaining : Math.round(total / siblings.length);
118274
- const allocated = Math.max(0, Math.min(share, remaining));
118275
- perTemplateLocal.set(sibling, (perTemplateLocal.get(sibling) ?? 0) + allocated);
118276
- remaining -= allocated;
118277
- });
118278
- return;
118279
- }
118280
- let remaining = total;
118281
- siblings.forEach((sibling, i) => {
118282
- const share = i === siblings.length - 1 ? remaining : Math.round(total * weightOf(sibling) / totalWeight);
118283
- const allocated = Math.max(0, Math.min(share, remaining));
118284
- perTemplateLocal.set(sibling, (perTemplateLocal.get(sibling) ?? 0) + allocated);
118285
- remaining -= allocated;
118286
- });
118287
- }
118288
118198
  //#endregion
118289
118199
  //#region ../loot-core/src/server/budget/goal-template.ts
118290
118200
  function distributeRemainder(templateContexts, availBudget) {
@@ -118306,7 +118216,7 @@ async function storeTemplates({ categoriesWithTemplates, source }) {
118306
118216
  await batchMessages(async () => {
118307
118217
  for (const { id, templates } of categoriesWithTemplates) await updateWithSchema("categories", {
118308
118218
  id,
118309
- goal_def: templates.length > 0 ? JSON.stringify(templates) : null,
118219
+ goal_def: JSON.stringify(templates),
118310
118220
  template_settings: { source }
118311
118221
  });
118312
118222
  });
@@ -118339,10 +118249,7 @@ async function getCategories$2() {
118339
118249
  async function getTemplates(filter = () => true) {
118340
118250
  const { data: categoriesWithGoalDef } = await aqlQuery$1(q$1("categories").filter({ goal_def: { $ne: null } }).select("*"));
118341
118251
  const categoryTemplates = {};
118342
- for (const categoryWithGoalDef of categoriesWithGoalDef.filter(filter)) {
118343
- if (!categoryWithGoalDef.goal_def) continue;
118344
- categoryTemplates[categoryWithGoalDef.id] = JSON.parse(categoryWithGoalDef.goal_def);
118345
- }
118252
+ for (const categoryWithGoalDef of categoriesWithGoalDef.filter(filter)) categoryTemplates[categoryWithGoalDef.id] = JSON.parse(categoryWithGoalDef.goal_def);
118346
118253
  return categoryTemplates;
118347
118254
  }
118348
118255
  async function getTemplatesForCategory(categoryId) {
@@ -118371,14 +118278,15 @@ async function setGoals(month, templateGoal) {
118371
118278
  });
118372
118279
  });
118373
118280
  }
118374
- async function computeTemplates(month, force, categoryTemplates, categories = []) {
118281
+ async function processTemplate(month, force, categoryTemplates, categories = []) {
118375
118282
  const isTracking = isTrackingBudget();
118376
118283
  if (!categories.length) categories = (await getCategories$2()).filter((c) => isTracking || !c.is_income);
118377
118284
  const templateContexts = [];
118378
118285
  let availBudget = await getSheetValue(sheetForMonth(month), `to-budget`);
118379
118286
  const prioritiesSet = /* @__PURE__ */ new Set();
118380
118287
  const errors = [];
118381
- const orphanGoals = [];
118288
+ const budgetList = [];
118289
+ const goalList = [];
118382
118290
  for (const category of categories) {
118383
118291
  const { id } = category;
118384
118292
  const sheetName = sheetForMonth(month);
@@ -118394,36 +118302,14 @@ async function computeTemplates(month, force, categoryTemplates, categories = []
118394
118302
  } catch (e) {
118395
118303
  errors.push(`${category.name}: ${e.message}`);
118396
118304
  }
118397
- else if (existingGoal !== null && !templates) orphanGoals.push({
118305
+ else if (existingGoal !== null && !templates) goalList.push({
118398
118306
  category: id,
118399
118307
  goal: null,
118400
118308
  longGoal: null
118401
118309
  });
118402
118310
  }
118403
- if (errors.length > 0) return {
118404
- contexts: templateContexts,
118405
- errors,
118406
- orphanGoals
118407
- };
118408
- const priorities = new Int32Array([...prioritiesSet]).sort((a, b) => a - b);
118409
- for (const priority of priorities) {
118410
- const availStart = availBudget;
118411
- for (const templateContext of templateContexts) {
118412
- const budget = await templateContext.runTemplatesForPriority(priority, availBudget, availStart);
118413
- availBudget -= budget;
118414
- }
118415
- }
118416
- distributeRemainder(templateContexts, availBudget);
118417
- return {
118418
- contexts: templateContexts,
118419
- errors,
118420
- orphanGoals
118421
- };
118422
- }
118423
- async function processTemplate(month, force, categoryTemplates, categories = []) {
118424
- const { contexts, errors, orphanGoals } = await computeTemplates(month, force, categoryTemplates, categories);
118425
- if (contexts.length === 0 && errors.length === 0) {
118426
- if (orphanGoals.length > 0) await setGoals(month, orphanGoals);
118311
+ if (templateContexts.length === 0 && errors.length === 0) {
118312
+ if (goalList.length > 0) setGoals(month, goalList);
118427
118313
  return {
118428
118314
  type: "message",
118429
118315
  message: "Everything is up to date"
@@ -118434,9 +118320,16 @@ async function processTemplate(month, force, categoryTemplates, categories = [])
118434
118320
  message: "There were errors interpreting some templates:",
118435
118321
  pre: errors.join(`\n\n`)
118436
118322
  };
118437
- const budgetList = [];
118438
- const goalList = [...orphanGoals];
118439
- contexts.forEach((context) => {
118323
+ const priorities = new Int32Array([...prioritiesSet]).sort((a, b) => a - b);
118324
+ for (const priority of priorities) {
118325
+ const availStart = availBudget;
118326
+ for (const templateContext of templateContexts) {
118327
+ const budget = await templateContext.runTemplatesForPriority(priority, availBudget, availStart);
118328
+ availBudget -= budget;
118329
+ }
118330
+ }
118331
+ availBudget = distributeRemainder(templateContexts, availBudget);
118332
+ templateContexts.forEach((context) => {
118440
118333
  const values = context.getValues();
118441
118334
  budgetList.push({
118442
118335
  category: context.category.id,
@@ -118452,22 +118345,7 @@ async function processTemplate(month, force, categoryTemplates, categories = [])
118452
118345
  await setGoals(month, goalList);
118453
118346
  return {
118454
118347
  type: "message",
118455
- message: `Successfully applied templates to ${contexts.length} categories`
118456
- };
118457
- }
118458
- async function dryRunCategoryTemplate({ month, categoryId, templates }) {
118459
- const allCategoryTemplates = await getTemplates();
118460
- allCategoryTemplates[categoryId] = templates;
118461
- const { contexts } = await computeTemplates(month, true, allCategoryTemplates, []);
118462
- const ctx = contexts.find((c) => c.category.id === categoryId);
118463
- if (!ctx) return {
118464
- budgeted: 0,
118465
- perTemplate: templates.map(() => 0)
118466
- };
118467
- const values = ctx.getValues();
118468
- return {
118469
- budgeted: values.budgeted,
118470
- perTemplate: templates.map((t) => values.perTemplateContribution.get(t) ?? 0)
118348
+ message: `Successfully applied templates to ${templateContexts.length} categories`
118471
118349
  };
118472
118350
  }
118473
118351
  //#endregion
@@ -118511,7 +118389,6 @@ app$14.method("category-group-delete", mutator(undoable(deleteCategoryGroup$1)))
118511
118389
  app$14.method("must-category-transfer", isCategoryTransferRequired);
118512
118390
  app$14.method("budget/get-category-automations", getTemplatesForCategory);
118513
118391
  app$14.method("budget/set-category-automations", mutator(undoable(storeTemplates)));
118514
- app$14.method("budget/dry-run-category-template", dryRunCategoryTemplate);
118515
118392
  app$14.method("budget/store-note-templates", mutator(storeNoteTemplates));
118516
118393
  app$14.method("budget/render-note-templates", unparse);
118517
118394
  async function getCategories$1() {