) => {
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() {
|
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
|