Stabilize purchase functionality: fix ID prefix, uniqueness, and split participant inclusion

This commit is contained in:
2026-03-13 22:29:17 +04:00
parent 31dd1dc2ee
commit 1274cefc0f
14 changed files with 489 additions and 19 deletions

View File

@@ -243,7 +243,23 @@ export function rebalancePurchaseSplit(
}
// Special case: if it's 'equal' mode and we aren't handling a specific change, force equal
if (draft.splitInputMode === 'equal' && changedMemberId === null) {
// Also initialize equal split for exact/percentage modes when no specific change provided
if (draft.splitInputMode !== 'equal' && changedMemberId === null) {
const active = participants.map((p, idx) => ({ ...p, idx })).filter((p) => p.included)
if (active.length > 0) {
const count = BigInt(active.length)
const baseShare = totalMinor / count
const remainder = totalMinor % count
active.forEach((p, i) => {
const share = baseShare + (BigInt(i) < remainder ? 1n : 0n)
participants[p.idx] = {
...participants[p.idx]!,
shareAmountMajor: minorToMajorString(share),
isAutoCalculated: true
}
})
}
} else if (draft.splitInputMode === 'equal' && changedMemberId === null) {
const active = participants.map((p, idx) => ({ ...p, idx })).filter((p) => p.included)
if (active.length > 0) {
const count = BigInt(active.length)

View File

@@ -266,18 +266,19 @@ export default function LedgerRoute() {
const [addingPayment, setAddingPayment] = createSignal(false)
const addPurchaseButtonText = createMemo(() => {
if (addingPurchase()) return copy().purchaseSaveAction // or maybe adding...
if (newPurchase().splitInputMode === 'equal') return copy().purchaseSaveAction
if (!validatePurchaseDraft(newPurchase()).valid) return copy().purchaseBalanceAction
if (addingPurchase()) return copy().savingPurchase
if (newPurchase().splitInputMode !== 'equal' && !validatePurchaseDraft(newPurchase()).valid) {
return copy().purchaseBalanceAction
}
return copy().purchaseSaveAction
})
const editPurchaseButtonText = createMemo(() => {
const draft = purchaseDraft()
if (savingPurchase()) return copy().savingPurchase
if (!draft) return copy().purchaseSaveAction
if (draft.splitInputMode === 'equal') return copy().purchaseSaveAction
if (!validatePurchaseDraft(draft).valid) return copy().purchaseBalanceAction
const draft = purchaseDraft()
if (draft && draft.splitInputMode !== 'equal' && !validatePurchaseDraft(draft).valid) {
return copy().purchaseBalanceAction
}
return copy().purchaseSaveAction
})
@@ -387,8 +388,8 @@ export default function LedgerRoute() {
participants: draft.participants.map((p) => ({
memberId: p.memberId,
included: p.included,
...(p.shareAmountMajor && draft.splitMode === 'custom_amounts'
? { shareAmountMajor: p.shareAmountMajor }
...(draft.splitMode === 'custom_amounts'
? { shareAmountMajor: p.shareAmountMajor || '0.00' }
: {})
}))
}
@@ -433,8 +434,8 @@ export default function LedgerRoute() {
participants: draft.participants.map((p) => ({
memberId: p.memberId,
included: p.included,
...(p.shareAmountMajor && draft.splitMode === 'custom_amounts'
? { shareAmountMajor: p.shareAmountMajor }
...(draft.splitMode === 'custom_amounts'
? { shareAmountMajor: p.shareAmountMajor || '0.00' }
: {})
}))
}
@@ -714,11 +715,13 @@ export default function LedgerRoute() {
loading={addingPurchase()}
disabled={!newPurchase().description.trim() || !newPurchase().amountMajor.trim()}
onClick={() => {
if (
newPurchase().splitInputMode !== 'equal' &&
!validatePurchaseDraft(newPurchase()).valid
) {
setNewPurchase((p) => rebalancePurchaseSplit(p, null, null))
const draft = newPurchase()
if (draft.splitInputMode !== 'equal' && !validatePurchaseDraft(draft).valid) {
const rebalanced = rebalancePurchaseSplit(draft, null, null)
setNewPurchase(rebalanced)
if (validatePurchaseDraft(rebalanced).valid) {
void handleAddPurchase()
}
} else {
void handleAddPurchase()
}
@@ -816,7 +819,11 @@ export default function LedgerRoute() {
draft.splitInputMode !== 'equal' &&
!validatePurchaseDraft(draft).valid
) {
setPurchaseDraft((d) => (d ? rebalancePurchaseSplit(d, null, null) : d))
const rebalanced = rebalancePurchaseSplit(draft, null, null)
setPurchaseDraft(rebalanced)
if (validatePurchaseDraft(rebalanced).valid) {
void handleSavePurchase()
}
} else {
void handleSavePurchase()
}