spliit
spliit copied to clipboard
[Feature request] CSV export: switch to per‑expense saldo format and remove reimbursement column
Background
Discussion status and references:
- PR #456 introduces “Paid By” + sorting; reviewers requested the format change in a separate PR.
- Issue #455 asks for CSV↔JSON parity (incl. “Paid By” and ordering).
- Issue #471 shows the payer can appear negative in participant columns, which is not useful for “personal cost” or for balancing.
- Issue #342 discusses that the current “signed shares” columns lose information and are awkward in spreadsheets; a per‑expense saldo is more practical.
Problem statement:
- Participant columns encode “signed shares,” which are neither clear personal costs nor per‑expense balances; this makes the export unintuitive compared to the JSON data model.
- Reimbursements appear as expenses, distorting totals and requiring a special flag.
Proposed direction:
- Switch participant columns to per‑expense saldo (payer advances; others owe). Model reimbursements as internal transfers by using
Cost=0.
Why now:
- This follows Jessica’s PR (#456) that fixed sorting and added "Paid By". To keep scope clean, this PR focuses on the CSV format revamp as a dedicated, reviewable change.
Summary
This PR switches the CSV export to a per‑expense saldo format that aligns better with user expectations and spreadsheet workflows. Participant columns carry the net effect (saldo) of each expense. Reimbursements use Cost=0, which removes the need for a dedicated reimbursement flag.
Changes
- Columns
- Keep:
Date,Description,Category,Currency,Cost,Original cost,Original currency,Conversion rate,Split mode,Paid By. - Remove:
Is Reimbursement(redundant once reimbursements useCost=0). - Participant columns: per‑expense saldos (payer positive advance; others negative owed amounts).
- Keep:
- Behaviour
- Reimbursements: exported as internal transfers with
Cost=0; participant saldos reflect direction/amount. - Incomes: negative
Costvalues; participant saldos remain consistent. - Sorting: consistent with JSON export (by
expenseDate, thencreatedAt).
- Reimbursements: exported as internal transfers with
- Implementation
- CSV route updated to compute participant saldos; paid amounts and conversion values normalized to plain numbers before formatting.
CSV Format (Descriptive)
- Fixed columns:
Date,Description,Category,Currency,Cost,Original cost,Original currency,Conversion rate,Split mode,Paid By. - Participant columns: per‑expense saldo per participant.
- Semantics:
- Payer:
saldo = totalAmount - ownShareAmount(advance for others). - Others:
saldo = - ownShareAmount(owed to the payer).
- Payer:
- Special cases:
- Reimbursements →
Cost = 0(internal transfer; not group spending). - Incomes → negative
Cost(distribution to participants).
- Reimbursements →
Testing
- Manual: export CSVs for classical expenses, altruist payments, self‑payments, incomes, and reimbursements; verify that “who owes whom” is directly readable and that reimbursements use
Cost=0. - Script‑assisted: run the CSV→sentences helper (attached) to cross‑check narrative output and totals.
Rationale
- Practical and close to intent: participant columns show the real‑world effect per expense (advance vs. owed), matching users’ mental model and spreadsheet usage.
- Trade‑off: the exact split method (shares/percentages) is not serialized; amounts are. In practice, amounts are what downstream tools operate on.
- Clarity:
Is Reimbursementbecomes unnecessary withCost=0; totals remain correct and the transfer direction is visible in participant columns.
Why remove the Is Reimbursement column?
- Reimbursements are internal transfers, not spending. Using
Cost=0keeps group totals correct without an extra flag. - The participant columns already encode direction and amount; the boolean adds no additional value.
Evidence
- Exercised against a comprehensive set of scenarios (classical expenses, altruist payments, self‑payments, incomes, reimbursements) using a CSV→sentences helper and curated test CSVs (attached via PR comment).