From 8aef00ab05da16dc973aa7b6f2eacec692f992c9 Mon Sep 17 00:00:00 2001 From: Martin Berka Date: Thu, 7 May 2026 13:05:04 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20po=C4=8D=C3=ADt=C3=A1n=C3=AD=20=C4=8D?= =?UTF-8?q?=C3=A1stek=20v=20hal=C3=A9=C5=99=C3=ADch=20z=20d=C5=AFvodu=20p?= =?UTF-8?q?=C5=99esnosti?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/components/PizzaOrderList.tsx | 2 +- client/src/components/PizzaOrderRow.tsx | 8 +- .../components/modals/EditGroupFeesModal.tsx | 53 ++- .../src/components/modals/PayForAllModal.tsx | 31 +- .../components/modals/PayForGroupModal.tsx | 31 +- .../modals/PizzaAdditionalFeeModal.tsx | 4 +- client/src/pages/OrderGroupsPage.tsx | 32 +- server/src/chefie.ts | 18 +- server/src/mock.ts | 440 +++++++++--------- server/src/pizza.ts | 2 +- server/src/routes/groupRoutes.ts | 12 +- server/src/routes/qrRoutes.ts | 9 +- server/src/tests/chefie.test.ts | 8 +- server/src/tests/qrRoutes.test.ts | 10 +- types/paths/groups/updateFees.yml | 16 +- types/paths/groups/updateMember.yml | 8 +- types/paths/pizzaDay/updatePizzaFee.yml | 4 +- types/schemas/_index.yml | 62 +-- 18 files changed, 370 insertions(+), 380 deletions(-) diff --git a/client/src/components/PizzaOrderList.tsx b/client/src/components/PizzaOrderList.tsx index 9e276a6..54e8b65 100644 --- a/client/src/components/PizzaOrderList.tsx +++ b/client/src/components/PizzaOrderList.tsx @@ -48,7 +48,7 @@ export default function PizzaOrderList({ state, orders, onDelete, creator }: Rea borderTop: '2px solid var(--luncher-border)' }}> Celkem - {`${total} Kč`} + {`${total / 100} Kč`} diff --git a/client/src/components/PizzaOrderRow.tsx b/client/src/components/PizzaOrderRow.tsx index f685005..94bf877 100644 --- a/client/src/components/PizzaOrderRow.tsx +++ b/client/src/components/PizzaOrderRow.tsx @@ -26,7 +26,7 @@ export default function PizzaOrderRow({ creator, order, state, onDelete, onFeeMo {order.customer} {order.pizzaList!.map(pizzaOrder => - {`${pizzaOrder.name}, ${pizzaOrder.size} (${pizzaOrder.price} Kč)`} + {`${pizzaOrder.name}, ${pizzaOrder.size} (${pizzaOrder.price / 100} Kč)`} {auth?.login === order.customer && state === PizzaDayState.CREATED && { @@ -38,10 +38,10 @@ export default function PizzaOrderRow({ creator, order, state, onDelete, onFeeMo .reduce((prev, curr, index) => [prev,
, curr])} {order.note ?? '-'} - {order.fee?.price ? `${order.fee.price} Kč${order.fee.text ? ` (${order.fee.text})` : ''}` : '-'} + {order.fee?.price ? `${order.fee.price / 100} Kč${order.fee.text ? ` (${order.fee.text})` : ''}` : '-'} - {order.totalPrice} Kč{auth?.login === creator && state === PizzaDayState.CREATED && { setIsFeeModalOpen(true) }} className='action-icon' icon={faMoneyBill1} />} + {order.totalPrice / 100} Kč{auth?.login === creator && state === PizzaDayState.CREATED && { setIsFeeModalOpen(true) }} className='action-icon' icon={faMoneyBill1} />} - setIsFeeModalOpen(false)} onSave={saveFees} initialValues={{ text: order.fee?.text, price: order.fee?.price?.toString() }} /> + setIsFeeModalOpen(false)} onSave={saveFees} initialValues={{ text: order.fee?.text, price: order.fee?.price != null ? String(order.fee.price / 100) : undefined }} /> } \ No newline at end of file diff --git a/client/src/components/modals/EditGroupFeesModal.tsx b/client/src/components/modals/EditGroupFeesModal.tsx index 3aba36a..4d8f9d0 100644 --- a/client/src/components/modals/EditGroupFeesModal.tsx +++ b/client/src/components/modals/EditGroupFeesModal.tsx @@ -9,18 +9,23 @@ type Props = { onSaved: (data: any) => void; }; -function parseNum(s: string): number { +function parseHal(s: string): number { const n = parseFloat(s.replace(',', '.')); - return isNaN(n) || n < 0 ? 0 : Math.round(n * 100) / 100; + return isNaN(n) || n < 0 ? 0 : Math.round(n * 100); +} + +function parsePercent(s: string): number { + const n = parseFloat(s.replace(',', '.')); + return isNaN(n) || n < 0 ? 0 : Math.round(n); } function computeMemberTotal(member: OrderGroupMember, feeShare: number, discountType: string, discountValue: number, memberCount: number): number { const base = member.amount ?? 0; const surcharge = member.surchargeAmount ?? 0; const discount = discountType === 'percent' - ? Math.round((base + surcharge) * discountValue / 100 * 100) / 100 - : Math.round(discountValue / memberCount * 100) / 100; - return Math.round((base + surcharge + feeShare - discount) * 100) / 100; + ? Math.round((base + surcharge) * discountValue / 100) + : Math.round(discountValue / memberCount); + return base + surcharge + feeShare - discount; } export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }: Readonly) { @@ -34,23 +39,25 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }: useEffect(() => { if (!isOpen) return; - setFees(group.fees ? String(group.fees) : ''); - setShipping(group.shipping ? String(group.shipping) : ''); - setTip(group.tip ? String(group.tip) : ''); + setFees(group.fees ? String(group.fees / 100) : ''); + setShipping(group.shipping ? String(group.shipping / 100) : ''); + setTip(group.tip ? String(group.tip / 100) : ''); setDiscountType((group.discountType as 'percent' | 'fixed') ?? 'percent'); - setDiscountValue(group.discountValue ? String(group.discountValue) : ''); + setDiscountValue(group.discountValue + ? ((group.discountType as string) === 'fixed' ? String(group.discountValue / 100) : String(group.discountValue)) + : ''); setError(null); }, [isOpen, group]); const memberEntries = Object.entries(group.members) as [string, OrderGroupMember][]; const memberCount = memberEntries.length; - const feesNum = parseNum(fees); - const shippingNum = parseNum(shipping); - const tipNum = parseNum(tip); - const discountNum = parseNum(discountValue); + const feesNum = parseHal(fees); + const shippingNum = parseHal(shipping); + const tipNum = parseHal(tip); + const discountNum = discountType === 'percent' ? parsePercent(discountValue) : parseHal(discountValue); const totalFees = feesNum + shippingNum + tipNum; - const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount * 100) / 100 : 0; + const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount) : 0; const handleSave = async () => { setError(null); @@ -64,7 +71,7 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }: tip: tipNum, discountType: discountNum > 0 ? discountType : undefined, discountValue: discountNum > 0 ? discountNum : undefined, - }, + } }); if (res.error) { setError((res.error as any).error || 'Nastala chyba'); @@ -143,7 +150,7 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }:
-
Náhled celkových částek ({memberCount} členů, {feeShare > 0 ? `poplatek ${feeShare} Kč/os.` : 'bez poplatku'})
+
Náhled celkových částek ({memberCount} členů, {feeShare > 0 ? `poplatek ${feeShare / 100} Kč/os.` : 'bez poplatku'})
@@ -161,18 +168,18 @@ export default function EditGroupFeesModal({ isOpen, onClose, group, onSaved }: const surcharge = member.surchargeAmount ?? 0; const discount = discountNum > 0 ? (discountType === 'percent' - ? Math.round((base + surcharge) * discountNum / 100 * 100) / 100 - : Math.round(discountNum / memberCount * 100) / 100) + ? Math.round((base + surcharge) * discountNum / 100) + : Math.round(discountNum / memberCount)) : 0; const total = computeMemberTotal(member, feeShare, discountType, discountNum, memberCount); return ( - - - - - + + + + + ); })} diff --git a/client/src/components/modals/PayForAllModal.tsx b/client/src/components/modals/PayForAllModal.tsx index a14016a..eba278d 100644 --- a/client/src/components/modals/PayForAllModal.tsx +++ b/client/src/components/modals/PayForAllModal.tsx @@ -33,9 +33,7 @@ function parseAmount(s: string): number | null { if (!s || s.trim().length === 0) return null; const n = parseFloat(s); if (isNaN(n) || n < 0) return null; - const parts = s.split('.'); - if (parts.length === 2 && parts[1].length > 2) return null; - return Math.round(n * 100) / 100; + return Math.round(n * 100); } export default function PayForAllModal({ isOpen, onClose, locationName, locationChoices, menu, payerLogin, bankAccount, bankAccountHolder }: Readonly) { @@ -55,11 +53,11 @@ export default function PayForAllModal({ isOpen, onClose, locationName, location let baseAmountParseFailed = false; if (menu) { for (const idx of selectedFoods) { - const price = parsePriceCzk(menu.food?.[idx]?.price); - if (price === null) { + const priceKc = parsePriceCzk(menu.food?.[idx]?.price); + if (priceKc === null) { baseAmountParseFailed = true; } else { - baseAmount += price; + baseAmount += Math.round(priceKc * 100); } } } @@ -84,19 +82,19 @@ export default function PayForAllModal({ isOpen, onClose, locationName, location if (includedDiners.length === 0) return 0; const tip = parseAmount(tipTotal); if (tip === null || tip === 0) return 0; - const totalPeople = includedDiners.length + 1; // +1 for payer - return Math.round((tip / totalPeople) * 100) / 100; + const totalPeople = includedDiners.length + 1; + return Math.round(tip / totalPeople); })(); const payerTipShare = (() => { const tip = parseAmount(tipTotal); if (!tip) return 0; - return Math.round((tip - tipPerPerson * includedDiners.length) * 100) / 100; + return tip - tipPerPerson * includedDiners.length; })(); const getTotal = (d: DinerEntry): number => { const surcharge = parseAmount(d.surchargeAmount) ?? 0; const tip = d.login === payerLogin ? payerTipShare : tipPerPerson; - return Math.round((d.baseAmount + surcharge + tip) * 100) / 100; + return d.baseAmount + surcharge + tip; }; const handleInclude = useCallback((login: string, checked: boolean) => { @@ -122,11 +120,6 @@ export default function PayForAllModal({ isOpen, onClose, locationName, location setError(`Celková částka pro ${d.login} musí být kladná`); return; } - const amountStr = total.toString(); - if (amountStr.includes('.') && amountStr.split('.')[1].length > 2) { - setError(`Částka pro ${d.login} má více než 2 desetinná místa`); - return; - } const foods = d.selectedFoods.map(i => menu?.food?.[i]?.name).filter(Boolean).join(', '); const purposeBase = `Oběd ${locationName}${foods ? ` — ${foods}` : ''}`; recipients.push({ @@ -226,7 +219,7 @@ export default function PayForAllModal({ isOpen, onClose, locationName, location @@ -254,10 +247,10 @@ export default function PayForAllModal({ isOpen, onClose, locationName, location ); @@ -278,7 +271,7 @@ export default function PayForAllModal({ isOpen, onClose, locationName, location /> {includedDiners.length > 0 && tipPerPerson > 0 - ? `(${tipPerPerson} Kč / osoba)` + ? `(${tipPerPerson / 100} Kč / osoba)` : ''} diff --git a/client/src/components/modals/PayForGroupModal.tsx b/client/src/components/modals/PayForGroupModal.tsx index 92e0c63..d8571c1 100644 --- a/client/src/components/modals/PayForGroupModal.tsx +++ b/client/src/components/modals/PayForGroupModal.tsx @@ -41,7 +41,7 @@ export default function PayForGroupModal({ isOpen, onClose, group, payerLogin, b const shipping = group.shipping ?? 0; const tip = group.tip ?? 0; const totalFees = fees + shipping + tip; - const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount * 100) / 100 : 0; + const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount) : 0; const getMemberTotal = (entry: DinerEntry): number => { const base = entry.member.amount ?? 0; @@ -50,10 +50,10 @@ export default function PayForGroupModal({ isOpen, onClose, group, payerLogin, b const discountValue = group.discountValue ?? 0; const discount = discountValue > 0 ? (discountType === 'percent' - ? Math.round((base + surcharge) * discountValue / 100 * 100) / 100 - : Math.round(discountValue / memberCount * 100) / 100) + ? Math.round((base + surcharge) * discountValue / 100) + : Math.round(discountValue / memberCount)) : 0; - return Math.round((base + surcharge + feeShare - discount) * 100) / 100; + return base + surcharge + feeShare - discount; }; const includedNonPayers = diners.filter(d => d.included && d.login !== payerLogin); @@ -73,11 +73,6 @@ export default function PayForGroupModal({ isOpen, onClose, group, payerLogin, b setError(`Celková částka pro ${d.login} musí být kladná`); return; } - const amountStr = total.toString(); - if (amountStr.includes('.') && amountStr.split('.')[1].length > 2) { - setError(`Částka pro ${d.login} má více než 2 desetinná místa`); - return; - } recipients.push({ login: d.login, purpose: `Objednávka ${group.name}`.substring(0, 60), @@ -132,15 +127,15 @@ export default function PayForGroupModal({ isOpen, onClose, group, payerLogin, b {hasFees && (
- {fees > 0 && Poplatky: {fees} Kč} - {shipping > 0 && Doprava: {shipping} Kč} - {tip > 0 && Spropitné: {tip} Kč} - → {feeShare} Kč/os. + {fees > 0 && Poplatky: {fees / 100} Kč} + {shipping > 0 && Doprava: {shipping / 100} Kč} + {tip > 0 && Spropitné: {tip / 100} Kč} + → {feeShare / 100} Kč/os.
)} {group.discountValue != null && group.discountValue > 0 && (
- Sleva: {group.discountType === 'percent' ? `${group.discountValue}%` : `${group.discountValue} Kč`} + Sleva: {group.discountType === 'percent' ? `${group.discountValue}%` : `${group.discountValue / 100} Kč`}
)} @@ -180,18 +175,18 @@ export default function PayForGroupModal({ isOpen, onClose, group, payerLogin, b )} {hasFees && ( )} ); diff --git a/client/src/components/modals/PizzaAdditionalFeeModal.tsx b/client/src/components/modals/PizzaAdditionalFeeModal.tsx index 5deac0d..e612568 100644 --- a/client/src/components/modals/PizzaAdditionalFeeModal.tsx +++ b/client/src/components/modals/PizzaAdditionalFeeModal.tsx @@ -15,12 +15,12 @@ export default function PizzaAdditionalFeeModal({ customerName, isOpen, onClose, const priceRef = useRef(null); const doSubmit = () => { - onSave(customerName, textRef.current?.value, Number.parseInt(priceRef.current?.value ?? "0")); + onSave(customerName, textRef.current?.value, Math.round(Number.parseFloat(priceRef.current?.value ?? "0") * 100)); } const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { - onSave(customerName, textRef.current?.value, Number.parseInt(priceRef.current?.value ?? "0")); + onSave(customerName, textRef.current?.value, Math.round(Number.parseFloat(priceRef.current?.value ?? "0") * 100)); } } diff --git a/client/src/pages/OrderGroupsPage.tsx b/client/src/pages/OrderGroupsPage.tsx index 1538420..e42cd1c 100644 --- a/client/src/pages/OrderGroupsPage.tsx +++ b/client/src/pages/OrderGroupsPage.tsx @@ -125,7 +125,7 @@ export default function OrderGroupsPage() { setPageError('Zadejte platnou kladnou částku'); return; } - const ok = await refresh(() => updateGroupMember({ body: { id: groupId, login, amount: n } })); + const ok = await refresh(() => updateGroupMember({ body: { id: groupId, login, amount: Math.round(n * 100) } })); if (ok) setEditAmounts(prev => { const next = { ...prev }; delete next[key]; return next; }); }; @@ -145,7 +145,7 @@ export default function OrderGroupsPage() { setPageError('Zadejte platnou výši příplatku'); return; } - const ok = await refresh(() => updateGroupMember({ body: { id: groupId, login, surchargeText, surchargeAmount: rawAmount === '' ? 0 : surchargeAmount } })); + const ok = await refresh(() => updateGroupMember({ body: { id: groupId, login, surchargeText, surchargeAmount: rawAmount === '' ? 0 : Math.round(surchargeAmount * 100) } })); if (ok) setEditSurcharges(prev => { const next = { ...prev }; delete next[key]; return next; }); }; @@ -254,17 +254,17 @@ export default function OrderGroupsPage() { const editingTimes = group.id in editTimes; const totalFees = (group.fees ?? 0) + (group.shipping ?? 0) + (group.tip ?? 0); - const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount * 100) / 100 : 0; + const feeShare = memberCount > 0 ? Math.round(totalFees / memberCount) : 0; const getMemberTotal = (m: OrderGroupMember) => { const base = m.amount ?? 0; const surcharge = m.surchargeAmount ?? 0; const dv = group.discountValue ?? 0; const discount = dv > 0 ? (group.discountType === 'percent' - ? Math.round((base + surcharge) * dv / 100 * 100) / 100 - : Math.round(dv / memberCount * 100) / 100) + ? Math.round((base + surcharge) * dv / 100) + : Math.round(dv / memberCount)) : 0; - return Math.round((base + surcharge + feeShare - discount) * 100) / 100; + return base + surcharge + feeShare - discount; }; return ( @@ -370,10 +370,10 @@ export default function OrderGroupsPage() { ) : ( canEdit && setEditAmounts(prev => ({ ...prev, [key]: String(member.amount ?? '') }))} + onClick={() => canEdit && setEditAmounts(prev => ({ ...prev, [key]: member.amount != null ? String(member.amount / 100) : '' }))} title={canEdit ? 'Klikněte pro úpravu' : undefined} > - {member.amount != null ? `${member.amount} Kč` : } + {member.amount != null ? `${member.amount / 100} Kč` : } )} @@ -404,11 +404,11 @@ export default function OrderGroupsPage() { ) : ( canEdit && setEditSurcharges(prev => ({ ...prev, [key]: { text: member.surchargeText ?? '', amount: member.surchargeAmount != null ? String(member.surchargeAmount) : '' } }))} + onClick={() => canEdit && setEditSurcharges(prev => ({ ...prev, [key]: { text: member.surchargeText ?? '', amount: member.surchargeAmount != null ? String(member.surchargeAmount / 100) : '' } }))} title={canEdit ? 'Klikněte pro úpravu příplatku' : undefined} > {member.surchargeAmount != null && member.surchargeAmount > 0 ? ( - {member.surchargeText ? `${member.surchargeText}: ` : ''}{member.surchargeAmount} Kč + {member.surchargeText ? `${member.surchargeText}: ` : ''}{member.surchargeAmount / 100} Kč ) : ( )} @@ -440,7 +440,7 @@ export default function OrderGroupsPage() {
{login}{base > 0 ? `${base} Kč` : '—'}{surcharge > 0 ? `${surcharge} Kč` : '—'}{feeShare > 0 ? `${feeShare} Kč` : '—'}{discount > 0 ? `-${discount} Kč` : '—'}{total > 0 ? `${total} Kč` : '—'}{base > 0 ? `${base / 100} Kč` : '—'}{surcharge > 0 ? `${surcharge / 100} Kč` : '—'}{feeShare > 0 ? `${feeShare / 100} Kč` : '—'}{discount > 0 ? `-${discount / 100} Kč` : '—'}{total > 0 ? `${total / 100} Kč` : '—'}
{foodNames || } - {hasMenu && d.baseAmount > 0 && ({d.baseAmount} Kč)} + {hasMenu && d.baseAmount > 0 && ({d.baseAmount / 100} Kč)} {d.baseAmountParseFailed && } - {(() => { const s = isPayer ? payerTipShare : tipPerPerson; return s > 0 ? `${s} Kč` : '—'; })()} + {(() => { const s = isPayer ? payerTipShare : tipPerPerson; return s > 0 ? `${s / 100} Kč` : '—'; })()} - {`${total} Kč`} + {`${total / 100} Kč`}
- {(d.member.amount ?? 0) > 0 ? `${d.member.amount} Kč` : } + {(d.member.amount ?? 0) > 0 ? `${d.member.amount! / 100} Kč` : } - {surcharge > 0 ? `${surcharge} Kč` : } + {surcharge > 0 ? `${surcharge / 100} Kč` : } - {feeShare > 0 ? `${feeShare} Kč` : '—'} + {feeShare > 0 ? `${feeShare / 100} Kč` : '—'} - {total > 0 ? `${total} Kč` : } + {total > 0 ? `${total / 100} Kč` : }
0 ? 'fw-bold' : 'text-muted'}> - {memberTotal > 0 ? `${memberTotal} Kč` : '—'} + {memberTotal > 0 ? `${memberTotal / 100} Kč` : '—'} @@ -464,13 +464,13 @@ export default function OrderGroupsPage() { {/* Souhrn poplatků a slevy */} {(totalFees > 0 || (group.discountValue != null && group.discountValue > 0)) && (
- {group.fees != null && group.fees > 0 && Poplatky: {group.fees} Kč} - {group.shipping != null && group.shipping > 0 && Doprava: {group.shipping} Kč} - {group.tip != null && group.tip > 0 && Spropitné: {group.tip} Kč} - {feeShare > 0 && {feeShare} Kč/os.} + {group.fees != null && group.fees > 0 && Poplatky: {group.fees / 100} Kč} + {group.shipping != null && group.shipping > 0 && Doprava: {group.shipping / 100} Kč} + {group.tip != null && group.tip > 0 && Spropitné: {group.tip / 100} Kč} + {feeShare > 0 && {feeShare / 100} Kč/os.} {group.discountValue != null && group.discountValue > 0 && ( - Sleva: {group.discountType === 'percent' ? `${group.discountValue}%` : `${group.discountValue} Kč`} + Sleva: {group.discountType === 'percent' ? `${group.discountValue}%` : `${group.discountValue / 100} Kč`} )}
diff --git a/server/src/chefie.ts b/server/src/chefie.ts index 8cd50be..82397ad 100644 --- a/server/src/chefie.ts +++ b/server/src/chefie.ts @@ -28,16 +28,16 @@ const buildPizzaUrl = (pizzaUrl: string) => { return `${baseUrl}/${pizzaUrl}`; } -// Ceny krabic dle velikosti +// Ceny krabic dle velikosti v haléřích const boxPrices: { [key: string]: number } = { - "30cm": 13, - "35cm": 15, - "40cm": 18, - "50cm": 25 + "30cm": 1300, + "35cm": 1500, + "40cm": 1800, + "50cm": 2500 } -// Cena obalu pro salát -const SALAT_BOX_PRICE = 13; +// Cena obalu pro salát v haléřích +const SALAT_BOX_PRICE = 1300; /** * Stáhne a scrapne aktuální pizzy ze stránek Pizza Chefie. @@ -79,7 +79,7 @@ export async function downloadPizzy(mock: boolean): Promise { a.each((i, elm) => { const varId = Number.parseInt(elm.attribs.href.split('?varianta=')[1].trim()); const size = $($(elm).contents().get(0)).text().trim(); - const price = Number.parseInt($($(elm).contents().get(1)).text().trim().split(" Kč")[0]); + const price = Number.parseInt($($(elm).contents().get(1)).text().trim().split(" Kč")[0]) * 100; sizes.push({ varId, size, pizzaPrice: price, boxPrice: boxPrices[size], price: price + boxPrices[size] }); }) result.push({ @@ -119,7 +119,7 @@ export async function downloadSalaty(mock: boolean): Promise { ingredients.push($(elm).text()); }); const priceText = $('.cena > span', salatHtml).first().text().trim(); - const price = Number.parseInt(priceText.split(' Kč')[0]); + const price = Number.parseInt(priceText.split(' Kč')[0]) * 100; result.push({ name, ingredients, price: price + SALAT_BOX_PRICE }); } return result; diff --git a/server/src/mock.ts b/server/src/mock.ts index db57404..946c2f8 100644 --- a/server/src/mock.ts +++ b/server/src/mock.ts @@ -661,30 +661,30 @@ const MOCK_PIZZA_LIST = [ { varId: 1, size: "30cm", - pizzaPrice: 138, - boxPrice: 13, - price: 151 + pizzaPrice: 13800, + boxPrice: 1300, + price: 15100 }, { varId: 2, size: "35cm", - pizzaPrice: 166, - boxPrice: 15, - price: 181 + pizzaPrice: 16600, + boxPrice: 1500, + price: 18100 }, { varId: 3, size: "40cm", - pizzaPrice: 223, - boxPrice: 18, - price: 241 + pizzaPrice: 22300, + boxPrice: 1800, + price: 24100 }, { varId: 4, size: "50cm", - pizzaPrice: 306, - boxPrice: 25, - price: 331 + pizzaPrice: 30600, + boxPrice: 2500, + price: 33100 } ] }, @@ -700,30 +700,30 @@ const MOCK_PIZZA_LIST = [ { varId: 6, size: "30cm", - pizzaPrice: 142, - boxPrice: 13, - price: 155 + pizzaPrice: 14200, + boxPrice: 1300, + price: 15500 }, { varId: 7, size: "35cm", - pizzaPrice: 172, - boxPrice: 15, - price: 187 + pizzaPrice: 17200, + boxPrice: 1500, + price: 18700 }, { varId: 8, size: "40cm", - pizzaPrice: 233, - boxPrice: 18, - price: 251 + pizzaPrice: 23300, + boxPrice: 1800, + price: 25100 }, { varId: 9, size: "50cm", - pizzaPrice: 316, - boxPrice: 25, - price: 341 + pizzaPrice: 31600, + boxPrice: 2500, + price: 34100 } ] }, @@ -741,30 +741,30 @@ const MOCK_PIZZA_LIST = [ { varId: 10, size: "30cm", - pizzaPrice: 142, - boxPrice: 13, - price: 155 + pizzaPrice: 14200, + boxPrice: 1300, + price: 15500 }, { varId: 11, size: "35cm", - pizzaPrice: 172, - boxPrice: 15, - price: 187 + pizzaPrice: 17200, + boxPrice: 1500, + price: 18700 }, { varId: 12, size: "40cm", - pizzaPrice: 233, - boxPrice: 18, - price: 251 + pizzaPrice: 23300, + boxPrice: 1800, + price: 25100 }, { varId: 13, size: "50cm", - pizzaPrice: 316, - boxPrice: 25, - price: 341 + pizzaPrice: 31600, + boxPrice: 2500, + price: 34100 } ] }, @@ -780,30 +780,30 @@ const MOCK_PIZZA_LIST = [ { varId: 14, size: "30cm", - pizzaPrice: 142, - boxPrice: 13, - price: 155 + pizzaPrice: 14200, + boxPrice: 1300, + price: 15500 }, { varId: 15, size: "35cm", - pizzaPrice: 172, - boxPrice: 15, - price: 187 + pizzaPrice: 17200, + boxPrice: 1500, + price: 18700 }, { varId: 16, size: "40cm", - pizzaPrice: 233, - boxPrice: 18, - price: 251 + pizzaPrice: 23300, + boxPrice: 1800, + price: 25100 }, { varId: 17, size: "50cm", - pizzaPrice: 294, - boxPrice: 25, - price: 319 + pizzaPrice: 29400, + boxPrice: 2500, + price: 31900 } ] }, @@ -821,30 +821,30 @@ const MOCK_PIZZA_LIST = [ { varId: 22, size: "30cm", - pizzaPrice: 162, - boxPrice: 13, - price: 175 + pizzaPrice: 16200, + boxPrice: 1300, + price: 17500 }, { varId: 23, size: "35cm", - pizzaPrice: 186, - boxPrice: 15, - price: 201 + pizzaPrice: 18600, + boxPrice: 1500, + price: 20100 }, { varId: 24, size: "40cm", - pizzaPrice: 263, - boxPrice: 18, - price: 281 + pizzaPrice: 26300, + boxPrice: 1800, + price: 28100 }, { varId: 25, size: "50cm", - pizzaPrice: 346, - boxPrice: 25, - price: 371 + pizzaPrice: 34600, + boxPrice: 2500, + price: 37100 } ] }, @@ -861,30 +861,30 @@ const MOCK_PIZZA_LIST = [ { varId: 26, size: "30cm", - pizzaPrice: 162, - boxPrice: 13, - price: 175 + pizzaPrice: 16200, + boxPrice: 1300, + price: 17500 }, { varId: 27, size: "35cm", - pizzaPrice: 186, - boxPrice: 15, - price: 201 + pizzaPrice: 18600, + boxPrice: 1500, + price: 20100 }, { varId: 28, size: "40cm", - pizzaPrice: 263, - boxPrice: 18, - price: 281 + pizzaPrice: 26300, + boxPrice: 1800, + price: 28100 }, { varId: 29, size: "50cm", - pizzaPrice: 346, - boxPrice: 25, - price: 371 + pizzaPrice: 34600, + boxPrice: 2500, + price: 37100 } ] }, @@ -902,30 +902,30 @@ const MOCK_PIZZA_LIST = [ { varId: 30, size: "30cm", - pizzaPrice: 162, - boxPrice: 13, - price: 175 + pizzaPrice: 16200, + boxPrice: 1300, + price: 17500 }, { varId: 31, size: "35cm", - pizzaPrice: 186, - boxPrice: 15, - price: 201 + pizzaPrice: 18600, + boxPrice: 1500, + price: 20100 }, { varId: 32, size: "40cm", - pizzaPrice: 263, - boxPrice: 18, - price: 281 + pizzaPrice: 26300, + boxPrice: 1800, + price: 28100 }, { varId: 33, size: "50cm", - pizzaPrice: 346, - boxPrice: 25, - price: 371 + pizzaPrice: 34600, + boxPrice: 2500, + price: 37100 } ] }, @@ -946,30 +946,30 @@ const MOCK_PIZZA_LIST = [ { varId: 34, size: "30cm", - pizzaPrice: 162, - boxPrice: 13, - price: 175 + pizzaPrice: 16200, + boxPrice: 1300, + price: 17500 }, { varId: 35, size: "35cm", - pizzaPrice: 186, - boxPrice: 15, - price: 201 + pizzaPrice: 18600, + boxPrice: 1500, + price: 20100 }, { varId: 36, size: "40cm", - pizzaPrice: 263, - boxPrice: 18, - price: 281 + pizzaPrice: 26300, + boxPrice: 1800, + price: 28100 }, { varId: 37, size: "50cm", - pizzaPrice: 346, - boxPrice: 25, - price: 371 + pizzaPrice: 34600, + boxPrice: 2500, + price: 37100 } ] }, @@ -987,30 +987,30 @@ const MOCK_PIZZA_LIST = [ { varId: 38, size: "30cm", - pizzaPrice: 162, - boxPrice: 13, - price: 175 + pizzaPrice: 16200, + boxPrice: 1300, + price: 17500 }, { varId: 39, size: "35cm", - pizzaPrice: 186, - boxPrice: 15, - price: 201 + pizzaPrice: 18600, + boxPrice: 1500, + price: 20100 }, { varId: 40, size: "40cm", - pizzaPrice: 263, - boxPrice: 18, - price: 281 + pizzaPrice: 26300, + boxPrice: 1800, + price: 28100 }, { varId: 41, size: "50cm", - pizzaPrice: 346, - boxPrice: 25, - price: 371 + pizzaPrice: 34600, + boxPrice: 2500, + price: 37100 } ] }, @@ -1028,30 +1028,30 @@ const MOCK_PIZZA_LIST = [ { varId: 42, size: "30cm", - pizzaPrice: 172, - boxPrice: 13, - price: 185 + pizzaPrice: 17200, + boxPrice: 1300, + price: 18500 }, { varId: 43, size: "35cm", - pizzaPrice: 212, - boxPrice: 15, - price: 227 + pizzaPrice: 21200, + boxPrice: 1500, + price: 22700 }, { varId: 44, size: "40cm", - pizzaPrice: 293, - boxPrice: 18, - price: 311 + pizzaPrice: 29300, + boxPrice: 1800, + price: 31100 }, { varId: 45, size: "50cm", - pizzaPrice: 376, - boxPrice: 25, - price: 401 + pizzaPrice: 37600, + boxPrice: 2500, + price: 40100 } ] }, @@ -1069,30 +1069,30 @@ const MOCK_PIZZA_LIST = [ { varId: 46, size: "30cm", - pizzaPrice: 182, - boxPrice: 13, - price: 195 + pizzaPrice: 18200, + boxPrice: 1300, + price: 19500 }, { varId: 47, size: "35cm", - pizzaPrice: 222, - boxPrice: 15, - price: 237 + pizzaPrice: 22200, + boxPrice: 1500, + price: 23700 }, { varId: 48, size: "40cm", - pizzaPrice: 303, - boxPrice: 18, - price: 321 + pizzaPrice: 30300, + boxPrice: 1800, + price: 32100 }, { varId: 49, size: "50cm", - pizzaPrice: 386, - boxPrice: 25, - price: 411 + pizzaPrice: 38600, + boxPrice: 2500, + price: 41100 } ] }, @@ -1114,30 +1114,30 @@ const MOCK_PIZZA_LIST = [ { varId: 50, size: "30cm", - pizzaPrice: 182, - boxPrice: 13, - price: 195 + pizzaPrice: 18200, + boxPrice: 1300, + price: 19500 }, { varId: 51, size: "35cm", - pizzaPrice: 222, - boxPrice: 15, - price: 237 + pizzaPrice: 22200, + boxPrice: 1500, + price: 23700 }, { varId: 52, size: "40cm", - pizzaPrice: 303, - boxPrice: 18, - price: 321 + pizzaPrice: 30300, + boxPrice: 1800, + price: 32100 }, { varId: 53, size: "50cm", - pizzaPrice: 396, - boxPrice: 25, - price: 421 + pizzaPrice: 39600, + boxPrice: 2500, + price: 42100 } ] }, @@ -1156,30 +1156,30 @@ const MOCK_PIZZA_LIST = [ { varId: 54, size: "30cm", - pizzaPrice: 182, - boxPrice: 13, - price: 195 + pizzaPrice: 18200, + boxPrice: 1300, + price: 19500 }, { varId: 55, size: "35cm", - pizzaPrice: 222, - boxPrice: 15, - price: 237 + pizzaPrice: 22200, + boxPrice: 1500, + price: 23700 }, { varId: 56, size: "40cm", - pizzaPrice: 303, - boxPrice: 18, - price: 321 + pizzaPrice: 30300, + boxPrice: 1800, + price: 32100 }, { varId: 57, size: "50cm", - pizzaPrice: 396, - boxPrice: 25, - price: 421 + pizzaPrice: 39600, + boxPrice: 2500, + price: 42100 } ] }, @@ -1199,30 +1199,30 @@ const MOCK_PIZZA_LIST = [ { varId: 58, size: "30cm", - pizzaPrice: 182, - boxPrice: 13, - price: 195 + pizzaPrice: 18200, + boxPrice: 1300, + price: 19500 }, { varId: 59, size: "35cm", - pizzaPrice: 222, - boxPrice: 15, - price: 237 + pizzaPrice: 22200, + boxPrice: 1500, + price: 23700 }, { varId: 60, size: "40cm", - pizzaPrice: 303, - boxPrice: 18, - price: 321 + pizzaPrice: 30300, + boxPrice: 1800, + price: 32100 }, { varId: 61, size: "50cm", - pizzaPrice: 396, - boxPrice: 25, - price: 421 + pizzaPrice: 39600, + boxPrice: 2500, + price: 42100 } ] }, @@ -1241,30 +1241,30 @@ const MOCK_PIZZA_LIST = [ { varId: 62, size: "30cm", - pizzaPrice: 188, - boxPrice: 13, - price: 201 + pizzaPrice: 18800, + boxPrice: 1300, + price: 20100 }, { varId: 63, size: "35cm", - pizzaPrice: 226, - boxPrice: 15, - price: 241 + pizzaPrice: 22600, + boxPrice: 1500, + price: 24100 }, { varId: 64, size: "40cm", - pizzaPrice: 313, - boxPrice: 18, - price: 331 + pizzaPrice: 31300, + boxPrice: 1800, + price: 33100 }, { varId: 65, size: "50cm", - pizzaPrice: 426, - boxPrice: 25, - price: 451 + pizzaPrice: 42600, + boxPrice: 2500, + price: 45100 } ] }, @@ -1283,30 +1283,30 @@ const MOCK_PIZZA_LIST = [ { varId: 66, size: "30cm", - pizzaPrice: 188, - boxPrice: 13, - price: 201 + pizzaPrice: 18800, + boxPrice: 1300, + price: 20100 }, { varId: 67, size: "35cm", - pizzaPrice: 226, - boxPrice: 15, - price: 241 + pizzaPrice: 22600, + boxPrice: 1500, + price: 24100 }, { varId: 68, size: "40cm", - pizzaPrice: 313, - boxPrice: 18, - price: 331 + pizzaPrice: 31300, + boxPrice: 1800, + price: 33100 }, { varId: 69, size: "50cm", - pizzaPrice: 426, - boxPrice: 25, - price: 451 + pizzaPrice: 42600, + boxPrice: 2500, + price: 45100 } ] }, @@ -1327,30 +1327,30 @@ const MOCK_PIZZA_LIST = [ { varId: 309, size: "30cm", - pizzaPrice: 182, - boxPrice: 13, - price: 195 + pizzaPrice: 18200, + boxPrice: 1300, + price: 19500 }, { varId: 310, size: "35cm", - pizzaPrice: 222, - boxPrice: 15, - price: 237 + pizzaPrice: 22200, + boxPrice: 1500, + price: 23700 }, { varId: 311, size: "40cm", - pizzaPrice: 303, - boxPrice: 18, - price: 321 + pizzaPrice: 30300, + boxPrice: 1800, + price: 32100 }, { varId: 312, size: "50cm", - pizzaPrice: 396, - boxPrice: 25, - price: 421 + pizzaPrice: 39600, + boxPrice: 2500, + price: 42100 } ] }, @@ -1369,30 +1369,30 @@ const MOCK_PIZZA_LIST = [ { varId: 394, size: "30cm", - pizzaPrice: 188, - boxPrice: 13, - price: 201 + pizzaPrice: 18800, + boxPrice: 1300, + price: 20100 }, { varId: 395, size: "35cm", - pizzaPrice: 226, - boxPrice: 15, - price: 241 + pizzaPrice: 22600, + boxPrice: 1500, + price: 24100 }, { varId: 396, size: "40cm", - pizzaPrice: 313, - boxPrice: 18, - price: 331 + pizzaPrice: 31300, + boxPrice: 1800, + price: 33100 }, { varId: 397, size: "50cm", - pizzaPrice: 426, - boxPrice: 25, - price: 451 + pizzaPrice: 42600, + boxPrice: 2500, + price: 45100 } ] } @@ -1434,22 +1434,22 @@ const MOCK_SALAT_LIST = [ { name: "Greek", ingredients: ["Salát", "Černé olivy", "Paprika mix", "Červená cibule", "Rajčata", "Okurka salátová", "Jogurtový dresing"], - price: 174 + 13, + price: (174 + 13) * 100, }, { name: "Caesar", ingredients: ["Salát", "Rajčata", "Kuřecí maso", "Krutony", "Parmazán", "Caesar dresing", "Olivový olej"], - price: 184 + 13, + price: (184 + 13) * 100, }, { name: "Šopský salát", ingredients: ["Salátová okurka", "Rajčata", "Paprika mix", "Červená cibule", "Balkánský sýr"], - price: 164 + 13, + price: (164 + 13) * 100, }, { name: "Těstovinový salát", ingredients: ["Penne", "Okurka", "Rajčata", "Paprika mix", "Kuřecí maso", "Jogurtový dresing"], - price: 184 + 13, + price: (184 + 13) * 100, }, ] diff --git a/server/src/pizza.ts b/server/src/pizza.ts index f044d86..72e64d6 100644 --- a/server/src/pizza.ts +++ b/server/src/pizza.ts @@ -342,7 +342,7 @@ export async function finishPizzaDelivery(login: string, bankAccount?: string, b let message = order.pizzaList!.map(item => item.category === 'salat' ? `Salát ${item.name}` : `Pizza ${item.name} (${item.size})` ).join(', '); - await generateQr(order.customer, bankAccount, bankAccountHolder, order.totalPrice, message, id); + await generateQr(order.customer, bankAccount, bankAccountHolder, order.totalPrice / 100, message, id); order.hasQr = true; // Uložíme nevyřízený QR kód pro persistentní zobrazení await addPendingQr(order.customer, { diff --git a/server/src/routes/groupRoutes.ts b/server/src/routes/groupRoutes.ts index ec67fc5..52915e5 100644 --- a/server/src/routes/groupRoutes.ts +++ b/server/src/routes/groupRoutes.ts @@ -69,7 +69,7 @@ router.post("/updateMember", async (req: Request, res, next) => { if (!targetLogin) return res.status(400).json({ error: 'Nebyl předán login uživatele' }); const patch: Record = {}; if (amount !== undefined) { - if (typeof amount !== 'number' || !Number.isFinite(amount) || amount < 0) { + if (!Number.isInteger(amount) || amount < 0) { return res.status(400).json({ error: 'Neplatná částka' }); } patch.amount = amount; @@ -83,7 +83,7 @@ router.post("/updateMember", async (req: Request, res, next) => { patch.surchargeText = surchargeText; } if (surchargeAmount !== undefined) { - if (typeof surchargeAmount !== 'number' || !Number.isFinite(surchargeAmount) || surchargeAmount < 0) { + if (!Number.isInteger(surchargeAmount) || surchargeAmount < 0) { return res.status(400).json({ error: 'Neplatná výše příplatku' }); } patch.surchargeAmount = surchargeAmount; @@ -113,19 +113,19 @@ router.post("/updateFees", async (req: Request, res, next) => { const login = getLogin(parseToken(req)); const { id, fees, shipping, tip, discountType, discountValue } = req.body ?? {}; if (!id) return res.status(400).json({ error: 'Nebylo předáno ID skupiny' }); - if (fees !== undefined && (typeof fees !== 'number' || !Number.isFinite(fees) || fees < 0)) { + if (fees !== undefined && (!Number.isInteger(fees) || fees < 0)) { return res.status(400).json({ error: 'Neplatná výše poplatků' }); } - if (shipping !== undefined && (typeof shipping !== 'number' || !Number.isFinite(shipping) || shipping < 0)) { + if (shipping !== undefined && (!Number.isInteger(shipping) || shipping < 0)) { return res.status(400).json({ error: 'Neplatná výše dopravy' }); } - if (tip !== undefined && (typeof tip !== 'number' || !Number.isFinite(tip) || tip < 0)) { + if (tip !== undefined && (!Number.isInteger(tip) || tip < 0)) { return res.status(400).json({ error: 'Neplatná výše spropitného' }); } if (discountType !== undefined && discountType !== '' && !['percent', 'fixed'].includes(discountType)) { return res.status(400).json({ error: 'Neplatný typ slevy' }); } - if (discountValue !== undefined && (typeof discountValue !== 'number' || !Number.isFinite(discountValue) || discountValue < 0)) { + if (discountValue !== undefined && (!Number.isInteger(discountValue) || discountValue < 0)) { return res.status(400).json({ error: 'Neplatná výše slevy' }); } try { diff --git a/server/src/routes/qrRoutes.ts b/server/src/routes/qrRoutes.ts index 7de62e9..cd2c074 100644 --- a/server/src/routes/qrRoutes.ts +++ b/server/src/routes/qrRoutes.ts @@ -36,18 +36,13 @@ router.post("/generate", async (req: Request<{}, any, GenerateQrData["body"]>, r if (!recipient.purpose || recipient.purpose.trim().length === 0) { return res.status(400).json({ error: `Příjemce ${recipient.login} nemá vyplněný účel platby` }); } - if (typeof recipient.amount !== 'number' || recipient.amount <= 0) { + if (!Number.isInteger(recipient.amount) || recipient.amount <= 0) { return res.status(400).json({ error: `Příjemce ${recipient.login} má neplatnou částku` }); } - // Validace max 2 desetinná místa - const amountStr = recipient.amount.toString(); - if (amountStr.includes('.') && amountStr.split('.')[1].length > 2) { - return res.status(400).json({ error: `Částka pro ${recipient.login} má více než 2 desetinná místa` }); - } // Vygenerovat QR kód const id = crypto.randomUUID(); - await generateQr(recipient.login, bankAccount, bankAccountHolder, recipient.amount, recipient.purpose, id); + await generateQr(recipient.login, bankAccount, bankAccountHolder, recipient.amount / 100, recipient.purpose, id); // Uložit jako nevyřízený QR kód a okamžitě doručit příjemci const pendingQr = { diff --git a/server/src/tests/chefie.test.ts b/server/src/tests/chefie.test.ts index 5637a06..2b7d44d 100644 --- a/server/src/tests/chefie.test.ts +++ b/server/src/tests/chefie.test.ts @@ -31,8 +31,8 @@ test('saláty mají name a ingredients', async () => { test('cena salátu zahrnuje pevný příplatek 13 Kč za obal', async () => { const salaty = await downloadSalaty(false); - // Caesar sticker price = 129, box = 13 - expect(salaty[0].price).toBe(129 + 13); - // Řecký sticker price = 119, box = 13 - expect(salaty[1].price).toBe(119 + 13); + // Caesar sticker price = 129, box = 13 → (129 + 13) * 100 haléřů + expect(salaty[0].price).toBe((129 + 13) * 100); + // Řecký sticker price = 119, box = 13 → (119 + 13) * 100 haléřů + expect(salaty[1].price).toBe((119 + 13) * 100); }); diff --git a/server/src/tests/qrRoutes.test.ts b/server/src/tests/qrRoutes.test.ts index a558111..858acc9 100644 --- a/server/src/tests/qrRoutes.test.ts +++ b/server/src/tests/qrRoutes.test.ts @@ -28,8 +28,8 @@ beforeEach(() => { const VALID_BODY = { recipients: [ - { login: 'uzivatel1', purpose: 'Pizza Margherita', amount: 149 }, - { login: 'uzivatel2', purpose: 'Pizza Diavola', amount: 179 }, + { login: 'uzivatel1', purpose: 'Pizza Margherita', amount: 14900 }, + { login: 'uzivatel2', purpose: 'Pizza Diavola', amount: 17900 }, ], bankAccount: '19-2000145399/0800', bankAccountHolder: 'Jan Novák', @@ -76,17 +76,17 @@ test('POST /generate vrátí 400 pro zápornou částku', async () => { expect(res.body.error).toContain('částku'); }); -test('POST /generate vrátí 400 pro částku s více než 2 desetinnými místy', async () => { +test('POST /generate vrátí 400 pro necelou částku', async () => { const body = { ...VALID_BODY, - recipients: [{ login: 'uzivatel1', purpose: 'Pizza', amount: 149.999 }], + recipients: [{ login: 'uzivatel1', purpose: 'Pizza', amount: 149.5 }], }; const res = await request(buildApp()) .post('/api/qr/generate') .set('Authorization', TOKEN) .send(body); expect(res.status).toBe(400); - expect(res.body.error).toContain('desetinná'); + expect(res.body.error).toContain('částku'); }); test('POST /generate vrátí 400 pro příjemce bez login', async () => { diff --git a/types/paths/groups/updateFees.yml b/types/paths/groups/updateFees.yml index 4dfcf5a..26db12a 100644 --- a/types/paths/groups/updateFees.yml +++ b/types/paths/groups/updateFees.yml @@ -14,21 +14,21 @@ post: description: ID skupiny type: string fees: - description: Poplatky (Kč) - type: number + description: Poplatky (haléře) + type: integer shipping: - description: Doprava (Kč) - type: number + description: Doprava (haléře) + type: integer tip: - description: Spropitné (Kč) - type: number + description: Spropitné (haléře) + type: integer discountType: description: Typ slevy type: string enum: [percent, fixed] discountValue: - description: Hodnota slevy - type: number + description: Hodnota slevy (procenta nebo haléře pro fixed) + type: integer responses: "200": $ref: "../../api.yml#/components/responses/ClientDataResponse" diff --git a/types/paths/groups/updateMember.yml b/types/paths/groups/updateMember.yml index a8e5a66..1aa3072 100644 --- a/types/paths/groups/updateMember.yml +++ b/types/paths/groups/updateMember.yml @@ -18,8 +18,8 @@ post: description: Login člena ke změně type: string amount: - description: Částka k úhradě v Kč - type: number + description: Částka k úhradě v haléřích + type: integer note: description: Poznámka type: string @@ -27,8 +27,8 @@ post: description: Popis příplatku type: string surchargeAmount: - description: Výše příplatku v Kč - type: number + description: Výše příplatku v haléřích + type: integer responses: "200": $ref: "../../api.yml#/components/responses/ClientDataResponse" diff --git a/types/paths/pizzaDay/updatePizzaFee.yml b/types/paths/pizzaDay/updatePizzaFee.yml index c191172..545b324 100644 --- a/types/paths/pizzaDay/updatePizzaFee.yml +++ b/types/paths/pizzaDay/updatePizzaFee.yml @@ -16,8 +16,8 @@ post: type: string description: Textový popis přirážky/slevy price: - type: number - description: Částka přirážky/slevy v Kč + type: integer + description: Částka přirážky/slevy v haléřích responses: "200": description: Nastavení přirážky/slevy proběhlo úspěšně. diff --git a/types/schemas/_index.yml b/types/schemas/_index.yml index fa8f1db..381d2af 100644 --- a/types/schemas/_index.yml +++ b/types/schemas/_index.yml @@ -420,14 +420,14 @@ PizzaSize: description: Velikost pizzy, např. "30cm" type: string pizzaPrice: - description: Cena samotné pizzy v Kč - type: number + description: Cena samotné pizzy v haléřích + type: integer boxPrice: - description: Cena krabice pizzy v Kč - type: number + description: Cena krabice pizzy v haléřích + type: integer price: - description: Celková cena (pizza + krabice) - type: number + description: Celková cena (pizza + krabice) v haléřích + type: integer Pizza: description: Údaje o konkrétní pizze. type: object @@ -470,8 +470,8 @@ PizzaVariant: description: Velikost pizzy (např. "30cm"), nebo "1 porce" pro salát type: string price: - description: Cena v Kč, včetně krabice/obalu - type: number + description: Cena v haléřích, včetně krabice/obalu + type: integer category: description: Kategorie položky (pizza nebo salat) type: string @@ -494,8 +494,8 @@ Salat: items: type: string price: - description: Cena salátu v Kč (bez obalu) - type: number + description: Cena salátu v haléřích (bez obalu) + type: integer PizzaOrder: description: Údaje o objednávce pizzy jednoho uživatele. type: object @@ -521,11 +521,11 @@ PizzaOrder: description: Popis příplatku (např. "kuřecí maso navíc") type: string price: - description: Cena příplatku v Kč - type: number + description: Cena příplatku v haléřích + type: integer totalPrice: - description: Celková cena všech objednaných pizz daného uživatele, včetně krabic a příplatků - type: number + description: Celková cena všech objednaných pizz daného uživatele v haléřích, včetně krabic a příplatků + type: integer hasQr: description: | Příznak, pokud je k této objednávce vygenerován QR kód pro platbu. To je typicky pravda, pokud: @@ -635,9 +635,9 @@ QrRecipient: description: Účel platby (např. "Pizza prosciutto") type: string amount: - description: Částka v Kč (kladné číslo, max 2 desetinná místa) - type: number - minimum: 0.01 + description: Částka v haléřích (kladné celé číslo) + type: integer + minimum: 1 GenerateQrRequest: description: Request pro generování QR kódů type: object @@ -704,8 +704,8 @@ OrderGroupMember: additionalProperties: false properties: amount: - description: Částka k úhradě v Kč - type: number + description: Částka k úhradě v haléřích + type: integer note: description: Volitelná poznámka (např. co si objednává) type: string @@ -713,8 +713,8 @@ OrderGroupMember: description: Popis příplatku type: string surchargeAmount: - description: Výše příplatku v Kč - type: number + description: Výše příplatku v haléřích + type: integer paid: description: Příznak, zda člen uhradil svůj podíl objednávky type: boolean @@ -753,21 +753,21 @@ OrderGroup: description: Očekávaný čas doručení ve formátu HH:MM type: string fees: - description: Poplatky (balení apod.) celkem v Kč - type: number + description: Poplatky (balení apod.) celkem v haléřích + type: integer shipping: - description: Doprava v Kč - type: number + description: Doprava v haléřích + type: integer tip: - description: Spropitné v Kč - type: number + description: Spropitné v haléřích + type: integer discountType: description: Typ slevy aplikované na objednávku type: string enum: [percent, fixed] discountValue: - description: Hodnota slevy (procenta nebo Kč) - type: number + description: Hodnota slevy (procenta pro typ 'percent', haléře pro typ 'fixed') + type: integer # --- NEVYŘÍZENÉ QR KÓDY --- PendingQr: @@ -790,8 +790,8 @@ PendingQr: description: Jméno uživatele, který QR vygeneroval (příjemce platby) type: string totalPrice: - description: Celková cena objednávky v Kč - type: number + description: Celková cena objednávky v haléřích + type: integer purpose: description: Účel platby (např. "Pizza prosciutto") type: string