Files
flo d612acd715 Add settled balance panel, cash booking mode, and Kasse dashboard line
- Balance panel turns green with "Bezahlt ✓" + breakdown when open_balance <= 0, on all four tab pages (me, pay, staff_user, staff_pay)
- booking_mode radio on me.html and staff_user.html: normal / for_free / cash_paid; cash_paid auto-creates matching UserPayment(method=cash)
- Dashboard finance section shows "Kasse (bar)" sum of all cash payments for cross-checking
- staff_pay prefill lower-capped at 0; "Zahlung eintragen" always visible on staff_user

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 20:02:14 +02:00

106 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Suff drink booking tool
Self-service drink tab for festival attendees. Lives at `/suff/`. Plain Django, no JS.
## Auth
- `User.pin` (hashed CharField, 3 digits), separate from `password`. Strong password stays for `/admin/`.
- `PinBackend` authenticates by `username` + `pin`. `ModelBackend` first in `AUTHENTICATION_BACKENDS` so admin still needs strong password.
- PIN reset is **crew-only**. No self-reset, no random PINs, PINs never displayed.
## Name flow
Username = `slugify(input)`. POST name:
- not found → `create` mode → mandatory 3-digit PIN → create user → login
- found, has PIN → `login` mode → enter PIN
- found, no PIN, **no activity** (no Consumption + no UserPayment) → `claim` mode → set PIN → login
- found, no PIN, **has activity**`no_pin.html` ("ask someone at the bar")
## Booking
- `/suff/me/` shows: greeting, total/paid/open balance, drink grid, day-grouped history.
- Single form wraps two radio buttons (`booking_mode`) + all drink buttons (`name="drink_id"`).
- `booking_mode` values: `normal` (default, no radio selected), `for_free`, `cash_paid`.
- `+1` POST creates `Consumption(amount=1, day=current_weekday, for_free=...)`.
- `cash_paid` booking auto-creates matching `UserPayment(method=cash)` — same as anonymous walk-ins.
- Trash icon per row → `confirm_delete.html` → POST deletes own consumption (booking phase only).
- History grouped by festival day, newest-first per day.
## Payments
- `/suff/pay/` — user enters amount + method (cash/paypal/bank/other) + optional note. Creates `UserPayment`. Pre-fills with current `open_balance`.
- Method choices: `UserPayment.Method`.
- Open balance = sum(Consumption.price where !for_free) sum(UserPayment.amount).
- Balance panel shows settled state (green "Bezahlt ✓" + breakdown) when `open_balance <= 0`; amber with "Offen X €" otherwise. Applied on `/suff/me/`, `/suff/pay/`, `/suff/staff/u/<name>/`, `/suff/staff/u/<name>/pay/`.
## Crew (`is_staff`)
Separate page tree under `/suff/staff/`:
- `/suff/staff/` — alphabetical user list, anonymous gast on top, "Neuen Benutzer anlegen" link.
- `/suff/staff/new/` — register user. Name required, PIN optional 3 digits.
- `/suff/staff/u/<name>/` — book/pay/delete for that user. Mirrors `me.html`. "Zahlung eintragen" link always visible.
- `/suff/staff/u/<name>/pin/` — overwrite PIN (3 digits required, no clear).
- `/suff/staff/u/<name>/pay/` — record payment for that user. Amount pre-fills with `max(open_balance, 0)`.
- `/suff/staff/u/<name>/book/<id>/delete/` — delete consumption (and matching auto-payment if anon).
Staff booking form has same `booking_mode` radios (normal / for_free / cash_paid) as user view.
Target username highlighted via `.staff-target` (cyan pill) on every crew page.
## Anonymous walk-ins
- Seeded user `anonym` (migration 0009). No PIN, never logs in.
- Crew books for anonymous via staff_user page → drink booking auto-creates matching `UserPayment(method=cash, note="Auto: <drink>")` so balance always 0.
- Deleting an anonymous consumption removes one matching auto-payment.
- Anonymous has no pay page (404). PayPal walk-ins → register a real user instead.
## Time gating (Berlin tz)
- Phases: `before` / `booking` / `closed`.
- Test window: 2026-05-15 → 2026-05-31. Original festival: 2026-06-11 → 2026-06-14.
- `closed` shows static page; outside booking, all action endpoints redirect or 404.
- `settings.PRODUCTION=False` forces `booking`.
## Dashboard
- `/suff/dashboard/` (staff only). Donations vs. expenses with progress bar, drink inventory rows, refinance %, per-user open balances, top spender, top drink, busiest day, top drinker per day.
- Finance section includes "Kasse (bar)" — sum of all `UserPayment(method=cash)` — for cross-checking real cash in the box.
## Drink categories
- `Drink.category`: beer / alc_free_beer / radler / alc_free_radler / soft / water.
- Buttons gradient-colored per category. Sorted by category in grid.
## Files
- `gaehsnitz/auth_backends.py``PinBackend`
- `gaehsnitz/suff.py` — all suff views + phase + crew helpers
- `gaehsnitz/suff_urls.py` — routes
- `gaehsnitz/admin.py``SetPinForm` + `set_pin_view`
- `gaehsnitz/templates/suff/{base,name,pin,no_pin,me,pay,dashboard,closed,confirm_delete,staff_index,staff_user,staff_pay,staff_register,staff_pin_reset,staff_confirm_delete}.html`
- `gaehsnitz/static/suff/{style.css,favicon.svg}`
- `gaehsnitz/migrations/0009_anonymous_user.py` — seeds `anonym`
## Frontend
Mobile-first dark theme. `#161616` bg, `#EE9933`/`#FFCC77` amber, `#885522` brown borders, `#66ddee` cyan for crew target. Drink buttons gradient-colored per category. Toast banner for booking confirmation. `:active` scale feedback. SVG favicon.
## Open ideas / next session
### Pay-on-the-spot / quick-pay-cash
Single button on `me` (and crew_user) page: "Offenen Betrag bar bezahlen" → creates `UserPayment(method=cash, amount=open_balance)`. Lets bar crew clear tab in one tap when guest pays cash directly. (Skipped for now, keep in mind.)
### Prepay vs. pay-at-end
Currently a single open balance. Could surface "Prepay 50 €" as a flow vs. "Pay at the end" — same data model, different framing. Maybe a "Vorkasse" preset on pay page.
### Misc
- PWA manifest for add-to-homescreen
- Drink icons/emoji per type
- Style phase pages (`before` / `closed`)
- Per-user QR for fast crew lookup at the bar