@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/.tsbuildinfo +1 -1
- package/dist/index.js +72 -195
- package/dist/index.js.map +1 -1
- package/package.json +3 -5
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
|
|
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
|
-
|
|
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)
|
|
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
|
-
|
|
115147
|
-
|
|
115148
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
118064
|
-
const availNames =
|
|
118065
|
-
|
|
118066
|
-
|
|
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
|
|
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.
|
|
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 &&
|
|
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:
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
118404
|
-
|
|
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
|
|
118438
|
-
const
|
|
118439
|
-
|
|
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 ${
|
|
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() {
|