Skip to content

Keep a bill's category and payment mode when it is updated - #98

Open
Pascal-SAPUI5 wants to merge 1 commit into
InteractionEngineer:mainfrom
Pascal-SAPUI5:fix/preserve-bill-category-on-update
Open

Keep a bill's category and payment mode when it is updated#98
Pascal-SAPUI5 wants to merge 1 commit into
InteractionEngineer:mainfrom
Pascal-SAPUI5:fix/preserve-bill-category-on-update

Conversation

@Pascal-SAPUI5

@Pascal-SAPUI5 Pascal-SAPUI5 commented Aug 23, 2026

Copy link
Copy Markdown

Editing any bill in a Cospend project silently moved it to "uncategorised" and
reset its payment mode on the server.

Cause

Two things combined.

Bill never decoded categoryid or paymentmode, so both values were dropped
the moment a bill arrived from the server. paramsFor(_:) then hardcoded
"categoryid": "0" and "paymentmode": "n" into every request.

Changing only a bill's amount was therefore enough to destroy its category, and
Cospend's own category statistics degraded a little with every edit made from
the app.

Fix

Both fields are now decoded and round-tripped, falling back to the documented
Cospend defaults (0 / "n") for a bill that genuinely has none.
BillDetailViewModel.createBill() carries them across the edit form, which has
no field for either — so a bill keeps whatever it was given in the Cospend web
UI even when edited here.

iHateMoney is unaffected: it has no such concepts, and neither key is sent on
that path.

Changes

  • PayForMe/Model/Bill.swift — decode categoryid / paymentmode, stop
    hardcoding them in paramsFor(_:)
  • PayForMe/Views/BillDetail/BillDetailViewModel.swift — carry both values
    through the edit form
  • PayForMeTests/BillCategoryPreservationTests.swift — new

Verifying

Six tests in BillCategoryPreservationTests cover the round trip end to end:

  • testCategoryAndPaymentModeAreDecoded — both fields survive decoding
  • testPayloadWithoutTheFieldsStillDecodes — an older payload lacking them
    still decodes
  • testParamsPreserveCategoryAndPaymentMode — the request carries them back
  • testParamsFallBackToCospendDefaults — a bill with neither gets 0 / "n"
  • testIHateMoneyParamsCarryNeitherField — iHateMoney requests stay unchanged
  • testEditingABillKeepsItsCategory — the regression itself, through the edit
    path

By hand: in a Cospend project, give a bill a category and a payment mode in the
web UI, then change only its amount in the app. Before this change the bill came
back uncategorised with the payment mode reset; now both survive.

The change to project.pbxproj is only the registration of the new test file.

Relation to #42

This is the bug underneath #42, not the feature itself. #42 asks for pickers to
choose a category and payment method when creating a bill; this PR makes those
values survive at all. As things stand, Bill discards them on decode and
paramsFor(_:) overwrites them on every request — so a picker built on top would
have nothing to read and nothing to write to.

The logic here is deliberately independent of the UI, following
@InteractionEngineer's note on that issue (29 July), and it touches only the
Cospend path — iHateMoney has no such concepts, as pointed out in the same
comment.

@magshee — you picked up #42 in July. This should give you the round trip to
build the pickers on, and nothing in it constrains how the UI ends up looking.
Happy to adjust or drop it if it gets in your way.

Editing any bill in a Cospend project silently moved it to "uncategorised"
and reset its payment mode on the server.

Two things combined to cause it. `Bill` never decoded `categoryid` or
`paymentmode`, so both values were dropped the moment a bill arrived from the
server; and `paramsFor(_:)` then hardcoded `"categoryid": "0"` and
`"paymentmode": "n"` into every request. Changing only a bill's amount was
therefore enough to destroy its category, and Cospend's own category
statistics degraded a little with every edit made from the app.

Both fields are now decoded and round-tripped, falling back to the documented
defaults for a bill that genuinely has none. `BillDetailViewModel.createBill()`
carries them across the edit form, which has no field for either.

iHateMoney is unaffected: it has no such concepts and neither key is sent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Xgcu26TW3shuDwi9VENji
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant