testsAndMisc-archive/billsplit/README.md
Krzysztof kuhy Rudnicki c49c578fa7 billsplit: drop the four unused platform runner directories
windows/ (18 files), macos/ (28), ios/ (40) and linux/ (10) were flutter
create scaffolding that nothing in this repo builds: billsplit-ci.yml runs
pub get, dart format, analyze, test and the Python coverage gate, with no
flutter build step for any platform, and no script or doc invokes one
either. 96 tracked files, 4188 lines.

This also removes win32_window.cpp (288 lines), the last over-cap C++
file. It could not be split honestly - flutter regenerates it - so
deleting the target it belongs to is the honest way off the list.
Over-cap: 41 -> 40, and the cpp category is now empty.

Unpicked all three references: the .binary-allowlist icon entries and the
.gitignore un-ignore rules that existed only to let those icons past the
binary block, plus the README claim that the repo ships without platform
runner folders (false while 96 were tracked, true again now).

The four dirs are now gitignored so `flutter create` regenerates them
locally without re-tracking them. Verified by actually running
`flutter create . --platforms=linux,windows,macos,ios`: git add -An then
refuses all four as ignored. analyze/test/format stay green, 60 tests.

analysis_options.yaml is deliberately untouched - flutter analyze rewrites
the platform excludes back on every run, so removing them is not durable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
2026-08-17 11:14:32 +02:00

82 lines
3.6 KiB
Markdown

# BillSplit
Flutter app (mobile + desktop) for splitting shop receipts between people —
including the drinkers vs non-drinkers case — with Biedronka e-paragon import
and .xlsx export.
## Features
- **People roster** with a per-person _drinks alcohol_ toggle, plus arbitrary
**groups** (tags) like "meat eaters".
- **Receipts**: import a Polish fiscal e-receipt JSON (`e-paragon`,
JPK_KASA_PARAGON_v2-0 — the file the Biedronka app exports; the embedded JWS
payload is decoded, signature not verified) or build one manually. Multiple
receipts persist locally (`state.json` in app documents).
- **Per-item assignment**: each item is split among _Everyone / Drinkers /
Non-drinkers / a group / hand-picked people_. Alcohol is auto-detected on
import (wódka/piwo/wino/… keywords) and defaults to drinkers only; deposits
(kaucja) become their own line split among everyone. Category and assignment
are always editable — the keyword detection is a default, not a decision.
- **Grosz-exact math**: every item's shares sum to exactly the item total
(largest-remainder distribution), so per-person totals reconcile with the
receipt to the grosz — no floating point drift.
- **Totals view**: per person, with alcohol / rest breakdown, unassigned-item
warnings, and a reconciliation check against the paid amount.
- **Export .xlsx**: one row per item with a 1/0 person matrix plus a summary —
same layout as the hand-made spreadsheet this app grew out of. Matrix and
summary are exported values (the app is the calculator); column totals are
live SUM formulas.
## Running
`android/` is the only platform runner folder the repo tracks. Generate the
others locally for whatever you want to run on:
```sh
cd billsplit
flutter create . --platforms=linux,windows,macos,ios
flutter pub get
flutter run # picks a connected device / desktop
```
Those four directories are gitignored, so a regenerated runner stays local
instead of being committed back. CI never builds them: `billsplit-ci.yml` runs
`flutter analyze` and `flutter test` only.
Tested with Flutter 3.44.8 / Dart 3.10.
## Tests
```sh
flutter test
```
Covers: parsing the real sample receipt in `test/fixtures/` (49 items +
deposit, totals 590.55 + 7.00 = 597.55 zł), split invariants incl. a 500-case
fuzz of the remainder distribution, assignment-mode resolution, and xlsx
generation (the test writes `build/test_export.xlsx` for external inspection).
## Design notes / edge cases
- Money is `int` grosze end to end; formatting happens only at the UI edge.
- An item resolving to zero people (e.g. "non-drinkers" on an all-drinker
receipt) is **excluded from totals and loudly flagged**, never silently
dropped into someone's bill.
- Deleting a person prunes them from groups, receipt participants and custom
assignments; deleting a group falls back affected items to _Everyone_.
- Assignment modes are stored symbolically (not as materialized ID sets), so
adding a person later automatically includes them in _Everyone_ items.
Touching a person checkbox materializes the current set and switches the
item to _custom_.
- `paidTotalGr` (what the card was charged) is kept separately from the item
sum; a mismatch shows red in Totals instead of being "fixed" silently.
## Quality gates (enforced in CI)
- `dart format --set-exit-if-changed .` — formatting is canonical
- `flutter analyze --fatal-infos` — `very_good_analysis` + `strict-casts`,
`strict-inference`, `strict-raw-types`; any info fails the build
- `flutter test --coverage` + `tool/coverage_check.py` — **100% line
coverage of `lib/` is mandatory**; the gate also fails if a lib file is
never executed by any test