feat: Úhrada za všechny jednou osobou (#29) #53

Merged
mates merged 1 commits from feat/single-payment into master 2026-04-28 23:17:01 +02:00
Member

Closes #29

Co tato PR přidává

Jeden strávník zaplatí celý účet v restauraci (nebo skupině v OBJEDNAVAM) a ostatní obdrží QR kód pro refundaci. Ikona 💸 se zobrazí v řádku každé LunchChoice pokud: uživatel je sám strávníkem, má ≥2 strávníky a vyplněný bankovní účet v nastavení.

Dialog umožňuje:

  • zaškrtnutím vyloučit strávníky, kteří platí zvlášť
  • přidat každému příplatek (text + Kč, např. „pití 35 Kč")
  • zadat celkové dýško, které se rovnoměrně rozpočítá
  • prefill cen z menu (parsováno z řetězců jako „135 Kč"); pro OBJEDNAVAM bez menu se zadává ručně

Po potvrzení se zavolá stávající POST /api/qr/generate — žádný nový endpoint.

Prerekvizita: podpora více QR kódů na (příjemce, den)

Před touto PR platilo: addPendingQr deduplikoval podle date, qr.ts ukládal PNG pod ${date}_${md5(login)}.png. Druhý QR na stejného příjemce ve stejný den se tiše zahodil (pizza-day QR + manuální QR + tento nový flow = kolize).

Opraveno:

  • PendingQr.id (UUID) — každý QR má vlastní identifikátor
  • dismissPendingQr a obě místa generování nyní pracují s id místo date
  • GET /api/qr vyžaduje ?id= parametr
  • QR obrázky uloženy do Redis/storage jako base64 místo os.tmpdir() — přežijí redeploy serveru

Změněné soubory

Oblast Soubory
OpenAPI schéma types/schemas/_index.yml, types/paths/getPizzaQr.yml, types/paths/pizzaDay/dismissQr.yml
Server server/src/qr.ts, server/src/pizza.ts, server/src/routes/qrRoutes.ts, server/src/routes/pizzaDayRoutes.ts, server/src/index.ts
Client client/src/App.tsx, client/src/components/modals/PayForAllModal.tsx (nový), client/src/utils/parsePrice.ts (nový)

Poznámky k migraci

Existující PendingQr záznamy v Redis bez pole id zůstanou zobrazené v „Nevyřízené platby", ale obrázek QR se nenačte (broken image). Jsou krátkodobé — příjemci je během dne/dvou odškrtnou.

Out-of-scope (kandidáti na follow-up)

  • Notifikace QR_VYGENEROVAN přes ntfy/Teams/Discord
  • Server-side uložení bankAccount + holderName (aktuálně jen localStorage per-zařízení)
Closes #29 ## Co tato PR přidává Jeden strávník zaplatí celý účet v restauraci (nebo skupině v OBJEDNAVAM) a ostatní obdrží QR kód pro refundaci. Ikona 💸 se zobrazí v řádku každé LunchChoice pokud: uživatel je sám strávníkem, má ≥2 strávníky a vyplněný bankovní účet v nastavení. Dialog umožňuje: - zaškrtnutím vyloučit strávníky, kteří platí zvlášť - přidat každému příplatek (text + Kč, např. „pití 35 Kč") - zadat celkové dýško, které se rovnoměrně rozpočítá - prefill cen z menu (parsováno z řetězců jako „135 Kč"); pro OBJEDNAVAM bez menu se zadává ručně Po potvrzení se zavolá stávající `POST /api/qr/generate` — žádný nový endpoint. ## Prerekvizita: podpora více QR kódů na (příjemce, den) Před touto PR platilo: `addPendingQr` deduplikoval podle `date`, `qr.ts` ukládal PNG pod `${date}_${md5(login)}.png`. Druhý QR na stejného příjemce ve stejný den se tiše zahodil (pizza-day QR + manuální QR + tento nový flow = kolize). Opraveno: - `PendingQr.id` (UUID) — každý QR má vlastní identifikátor - `dismissPendingQr` a obě místa generování nyní pracují s `id` místo `date` - `GET /api/qr` vyžaduje `?id=` parametr - **QR obrázky uloženy do Redis/storage jako base64** místo `os.tmpdir()` — přežijí redeploy serveru ## Změněné soubory | Oblast | Soubory | |--------|---------| | OpenAPI schéma | `types/schemas/_index.yml`, `types/paths/getPizzaQr.yml`, `types/paths/pizzaDay/dismissQr.yml` | | Server | `server/src/qr.ts`, `server/src/pizza.ts`, `server/src/routes/qrRoutes.ts`, `server/src/routes/pizzaDayRoutes.ts`, `server/src/index.ts` | | Client | `client/src/App.tsx`, `client/src/components/modals/PayForAllModal.tsx` (nový), `client/src/utils/parsePrice.ts` (nový) | ## Poznámky k migraci Existující `PendingQr` záznamy v Redis bez pole `id` zůstanou zobrazené v „Nevyřízené platby", ale obrázek QR se nenačte (broken image). Jsou krátkodobé — příjemci je během dne/dvou odškrtnou. ## Out-of-scope (kandidáti na follow-up) - Notifikace `QR_VYGENEROVAN` přes ntfy/Teams/Discord - Server-side uložení `bankAccount` + `holderName` (aktuálně jen localStorage per-zařízení)
batmanisko force-pushed feat/single-payment from 2e8db88f07 to 7772db8e63 2026-04-28 22:40:49 +02:00 Compare
batmanisko requested review from mates 2026-04-28 22:43:07 +02:00
batmanisko added 1 commit 2026-04-28 22:45:58 +02:00
feat: úhrada za všechny jednou osobou (issue #29, SINGLE_PAYMENT)
ci/woodpecker/push/workflow Pipeline was canceled
1e1e23df80
Přidává možnost, aby jeden strávník zaplatil celý účet v restauraci a ostatní
obdrželi QR kód pro refundaci.

Prerekvizita — podpora více QR kódů na (příjemce, den):
- PendingQr.id (UUID) nahrazuje deduplikaci podle data; každý QR má vlastní klíč
- QR obrázky uloženy do Redis/storage (base64) místo tmpdir — přežijí redeploy
- GET /api/qr vyžaduje ?id= parametr; dismissQr přijímá {id} místo {date}

Feature:
- Ikona 'Zaplatit za všechny' v choices-table pro každou LunchChoice (kromě
  PIZZA/NEOBEDVAM/ROZHODUJI); viditelná jen při ≥2 strávnících a vyplněném účtu
- PayForAllModal: tabulka strávníků s prefillovanými cenami z menu, příplatky
  per-diner, celkové dýško rozpočtené rovnoměrně, generování QR přes POST /api/qr/generate
- parsePriceCzk() helper pro parsing 'N Kč' → number

Co se nemění: POST /api/qr/generate API kontrakt, PizzaOrder.hasQr boolean

Co se mění v OpenAPI: PendingQr.id (required), getPizzaQr ?id param, dismissQr body

Co-Authored-By: opmrdkazkrtkaus <opmrdkazkrtkaus@melancholik.eu>
batmanisko force-pushed feat/single-payment from 7772db8e63 to 1e1e23df80 2026-04-28 22:45:58 +02:00 Compare
Author
Member

@mates rivjů plz

@mates rivjů plz
mates merged commit 1e1e23df80 into master 2026-04-28 23:17:01 +02:00
mates deleted branch feat/single-payment 2026-04-28 23:17:02 +02:00
Owner

yolo, literally zero checks/fucks given

yolo, literally zero checks/fucks given
Author
Member

shipping fast

shipping fast
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Marbes/Luncher#53