feat: úhrada za všechny jednou osobou (issue #29, SINGLE_PAYMENT)
ci/woodpecker/push/workflow Pipeline was canceled

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>
This commit was merged in pull request #53.
This commit is contained in:
2026-04-28 22:35:15 +02:00
parent e5999852b7
commit 1e1e23df80
11 changed files with 430 additions and 66 deletions
+4 -1
View File
@@ -4,6 +4,7 @@ import { parseToken, formatDate } from "../utils";
import { generateQr } from "../qr";
import { addPendingQr } from "../pizza";
import { GenerateQrData } from "../../../types";
import crypto from "crypto";
const router = express.Router();
@@ -44,10 +45,12 @@ router.post("/generate", async (req: Request<{}, any, GenerateQrData["body"]>, r
}
// Vygenerovat QR kód
await generateQr(recipient.login, bankAccount, bankAccountHolder, recipient.amount, recipient.purpose);
const id = crypto.randomUUID();
await generateQr(recipient.login, bankAccount, bankAccountHolder, recipient.amount, recipient.purpose, id);
// Uložit jako nevyřízený QR kód
await addPendingQr(recipient.login, {
id,
date: today,
creator: login,
totalPrice: recipient.amount,