Merge main into the anchored model
Main moved on by 27 commits since this branch forked, including three schema steps of its own (budget folders, placement, nested bills). Resolutions worth knowing: - The anchored-model migration becomes 10 -> 11; main's 7 -> 10 run first. - Main's nextUnconfirmedOccurrenceOnOrAfter walked the calendar grid for every cost, which would have shown the slot-model "next due" for an anchored bill in the budget tree. Both walks are now generators and the lookup dispatches on anchoring, like occurrencesOf. - A folder's "Bills due" summed only occurrences, and an anchored bill's charges are never occurrences, so a charged phone plan read as 0 due. budgetTree now adds an anchored bill's charges in the month. - Main's RecurringSection (with RecurringSplitEditor) supersedes this branch's split editor; the anchoring rules are ported onto it: start-date validation via startDateNeedsDay, month precision hidden for lastCharge, the anchoring control locked once a cost has charges. - PurchaseDialog keeps main's placement control. The "Recurring cost" select replaces main's "Unlink from bill" checkbox, since "None" does the same. A bill created from the dialog nests under its post like one from Settings. - Dropped main's "bounded projection ignores invalid confirmations" test: it exercised slot confirmations on a lastCharge cost, which no longer exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
933027cb1b
89 files changed
+4023
-651
No files matched your search
@@ -25,6 +25,12 @@ const d = createSeedDataset("2026-01", FALLBACK_FX_RATES);
|
||||
const [games, food, social] = d.posts as [typeof d.posts[0], typeof d.posts[0], typeof d.posts[0]];
|
||||
const rent = actions.addPost(d, "Rent", "DKK");
|
||||
const transport = actions.addPost(d, "Transport", "DKK");
|
||||
const housing = actions.addBudgetFolder(d, "Housing", null);
|
||||
const utilities = actions.addBudgetFolder(d, "Small bills", housing.id);
|
||||
rent.folderId = housing.id;
|
||||
const smallBills = actions.addPost(d, "Household bills", "DKK");
|
||||
smallBills.folderId = utilities.id;
|
||||
for (const name of ["Internet", "Phone"]) actions.addRecurringCost(d, { name, folderId: utilities.id, archived: false, amount: { amount: name === "Internet" ? 249 : 129, currency: "DKK" }, startDate: "2026-09", recurrence: { kind: "everyNMonths", n: 1 }, anchoring: "calendar", splitMode: "percent", splits: [{ postId: smallBills.id, value: 100, absorbsRemainder: true }] });
|
||||
const savings = actions.addPost(d, "Savings", "DKK");
|
||||
|
||||
for (let m = 1; m <= 9; m++) {
|
||||
@@ -47,6 +53,7 @@ actions.setRuleOverride(d, "2026-09", social.id, { kind: "fixed", amount: { amou
|
||||
// every combination at once.
|
||||
const wowSub = actions.addRecurringCost(d, {
|
||||
name: "World of Warcraft",
|
||||
folderId: null,
|
||||
archived: false,
|
||||
amount: { amount: 13, currency: "USD" },
|
||||
startDate: "2026-06-05",
|
||||
@@ -57,6 +64,7 @@ const wowSub = actions.addRecurringCost(d, {
|
||||
});
|
||||
actions.addRecurringCost(d, {
|
||||
name: "Rent",
|
||||
folderId: housing.id,
|
||||
archived: false,
|
||||
amount: { amount: 8200, currency: "DKK" },
|
||||
startDate: "2026-06",
|
||||
@@ -67,6 +75,7 @@ actions.addRecurringCost(d, {
|
||||
});
|
||||
actions.addRecurringCost(d, {
|
||||
name: "Veg box",
|
||||
folderId: null,
|
||||
archived: false,
|
||||
amount: { amount: 175, currency: "DKK" },
|
||||
startDate: "2026-06-06",
|
||||
@@ -79,6 +88,7 @@ actions.addRecurringCost(d, {
|
||||
// off-schedule payment moves the whole series — the phone-bill behaviour.
|
||||
const carInsurance = actions.addRecurringCost(d, {
|
||||
name: "Car insurance",
|
||||
folderId: null,
|
||||
archived: false,
|
||||
amount: { amount: 349, currency: "DKK" },
|
||||
startDate: "2026-08-14",
|
||||
|
||||
Reference in new issue
Block a user