feat(settings): a recurring cost's splits are editable
The owner's first report: a cost's post was fixed at creation and could not be changed. RecurringCost has carried splits and splitMode with the same shape as Purchase since the first version, so this wires up a capability the data model already had rather than adding one — and a bill can now span envelopes. SplitEditor is narrowed from PurchaseDraft to the four fields it actually reads. PurchaseDraft satisfies that structurally, so the dialog's call site does not change at all. The anchoring control is disabled once a cost has charges, matching the store's refusal rather than offering an action that would fail on save. Also fixes a carried item: the anchoring handler now expands a month-only startDate in the same mutate call that switches to lastCharge anchoring, matching the normalisation the recurrence-kind handler already had — an everyNMonths cost anchored to lastCharge needs a day-granular startDate, and the store validates that pairing on every write.
This commit is contained in:
1 parent
61e3773733
commit
ccde30b8ea
4 files changed
+211
-19
No files matched your search
+14
-1
@@ -31,6 +31,19 @@ export interface PurchaseDraft {
|
||||
plan: PlanDraft | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The slice of a form draft that `SplitEditor` actually reads. `PurchaseDraft`
|
||||
* satisfies it structurally, so the purchase dialog's call site is unchanged —
|
||||
* and a recurring cost can now use the same editor without pretending to be a
|
||||
* purchase.
|
||||
*/
|
||||
export interface SplitTarget {
|
||||
amount: number;
|
||||
currency: Currency;
|
||||
splitMode: "percent" | "fixed";
|
||||
splits: SplitDraft[];
|
||||
}
|
||||
|
||||
export function emptyDraft(monthId: MonthId, postId: string): PurchaseDraft {
|
||||
return {
|
||||
date: monthId,
|
||||
@@ -45,7 +58,7 @@ export function emptyDraft(monthId: MonthId, postId: string): PurchaseDraft {
|
||||
}
|
||||
|
||||
/** What the split editor must show: how far the parts are from the whole. */
|
||||
export function splitBalance(draft: PurchaseDraft, digits: number): number {
|
||||
export function splitBalance(draft: SplitTarget, digits: number): number {
|
||||
const target = draft.splitMode === "percent" ? 100 : draft.amount;
|
||||
const sum = draft.splits.reduce((total, split) => total + split.value, 0);
|
||||
return roundMoney(target - sum, digits);
|
||||
|
||||
Reference in new issue
Block a user