mirror of
https://github.com/kuhyx/testsAndMisc-archive.git
synced 2026-11-11 12:27:34 +01:00
billsplit was a standalone Flutter app in ~/Downloads with one commit and no git remote — that directory was the only copy of its history. Three things the move needed beyond copying the tree: - The root .gitignore silently swallowed 32 of its files (*.png, *.ico, *.manifest). Ignored files do not error on `git add`, they just vanish, so this would have committed an app that cannot build. Added a trailing block of ! overrides plus .binary-allowlist (which did not exist yet) — the documented in-repo exception for binaries a build genuinely needs. The ../testsAndMisc_binaries/ symlink scheme does not apply: those directories are gone, and a symlinked PNG breaks a fresh clone. - billsplit/.github/workflows/ci.yaml was inert once nested; GitHub only reads workflows at the repository root. Relocated with a working-directory and a billsplit/** path filter. - The app's coverage gate moved to python_pkg/billsplit_coverage/ so every Python file stays under python_pkg/, and gained a test suite at 100% branch coverage as that location requires. billsplit/ now holds only Dart. Also replaces the stock Flutter icon with a family icon from the shared generator. The glyph is a filled silhouette because the family's 72px stroke cannot carry a fine torn edge, and the split is an evenodd-cut perforation so the holes stay transparent on the foreground and monochrome layers. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
78 lines
3.4 KiB
Markdown
78 lines
3.4 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
|
|
|
|
The repo ships `lib/`, `test/`, and `pubspec.yaml` without platform runner
|
|
folders. Generate them once for the platforms you want:
|
|
|
|
```sh
|
|
cd billsplit
|
|
flutter create . --platforms=linux,windows,macos,android,ios
|
|
flutter pub get
|
|
flutter run # picks a connected device / desktop
|
|
```
|
|
|
|
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
|