This commit is contained in:
+21
-9
@@ -428,33 +428,45 @@ function App() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pizzaSuggestions = useMemo(() => {
|
const pizzaSuggestions = useMemo(() => {
|
||||||
if (!data?.pizzaList) {
|
if (!data?.pizzaList && !data?.salatList) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const suggestions: SelectSearchOption[] = [];
|
const suggestions: SelectSearchOption[] = [];
|
||||||
data.pizzaList.forEach((pizza, index) => {
|
data.pizzaList?.forEach((pizza, index) => {
|
||||||
const group: SelectSearchOption = { name: pizza.name, type: "group", items: [] }
|
const group: SelectSearchOption = { name: pizza.name, type: "group", items: [] }
|
||||||
pizza.sizes.forEach((size, sizeIndex) => {
|
pizza.sizes.forEach((size, sizeIndex) => {
|
||||||
const name = `${size.size} (${size.price} Kč)`;
|
const name = `${size.size} (${size.price} Kč)`;
|
||||||
const value = `${index}|${sizeIndex}`;
|
const value = `pizza|${index}|${sizeIndex}`;
|
||||||
group.items?.push({ name, value });
|
group.items?.push({ name, value });
|
||||||
})
|
})
|
||||||
suggestions.push(group);
|
suggestions.push(group);
|
||||||
})
|
});
|
||||||
|
if (data.salatList?.length) {
|
||||||
|
const salatGroup: SelectSearchOption = { name: "Saláty", type: "group", items: [] }
|
||||||
|
data.salatList.forEach((salat, index) => {
|
||||||
|
salatGroup.items?.push({ name: `${salat.name} (${salat.price} Kč)`, value: `salat|${index}` });
|
||||||
|
});
|
||||||
|
suggestions.push(salatGroup);
|
||||||
|
}
|
||||||
return suggestions;
|
return suggestions;
|
||||||
}, [data?.pizzaList]);
|
}, [data?.pizzaList, data?.salatList]);
|
||||||
|
|
||||||
const handlePizzaChange = async (value: SelectedOptionValue | SelectedOptionValue[]) => {
|
const handlePizzaChange = async (value: SelectedOptionValue | SelectedOptionValue[]) => {
|
||||||
if (auth?.login && data?.pizzaList) {
|
if (auth?.login) {
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
throw new TypeError('Nepodporovaný typ hodnoty: ' + typeof value);
|
throw new TypeError('Nepodporovaný typ hodnoty: ' + typeof value);
|
||||||
}
|
}
|
||||||
const s = value.split('|');
|
const s = value.split('|');
|
||||||
const pizzaIndex = Number.parseInt(s[0]);
|
if (s[0] === 'salat') {
|
||||||
const pizzaSizeIndex = Number.parseInt(s[1]);
|
const salatIndex = Number.parseInt(s[1]);
|
||||||
|
await addPizza({ body: { salatIndex } });
|
||||||
|
} else {
|
||||||
|
const pizzaIndex = Number.parseInt(s[1]);
|
||||||
|
const pizzaSizeIndex = Number.parseInt(s[2]);
|
||||||
await addPizza({ body: { pizzaIndex, pizzaSizeIndex } });
|
await addPizza({ body: { pizzaIndex, pizzaSizeIndex } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handlePizzaDelete = async (pizzaOrder: PizzaVariant) => {
|
const handlePizzaDelete = async (pizzaOrder: PizzaVariant) => {
|
||||||
await removePizza({ body: { pizzaOrder } });
|
await removePizza({ body: { pizzaOrder } });
|
||||||
@@ -821,7 +833,7 @@ function App() {
|
|||||||
<SelectSearch
|
<SelectSearch
|
||||||
search={true}
|
search={true}
|
||||||
options={pizzaSuggestions}
|
options={pizzaSuggestions}
|
||||||
placeholder='Vyhledat pizzu...'
|
placeholder='Vyhledat pizzu nebo salát...'
|
||||||
onChange={handlePizzaChange}
|
onChange={handlePizzaChange}
|
||||||
onBlur={_ => { }}
|
onBlur={_ => { }}
|
||||||
onFocus={_ => { }}
|
onFocus={_ => { }}
|
||||||
|
|||||||
+41
-2
@@ -1,6 +1,7 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { load } from 'cheerio';
|
import { load } from 'cheerio';
|
||||||
import { getPizzaListMock } from './mock';
|
import { getPizzaListMock, getSalatListMock } from './mock';
|
||||||
|
import { Salat } from '../../types/gen/types.gen';
|
||||||
|
|
||||||
// TODO přesunout do types
|
// TODO přesunout do types
|
||||||
type PizzaSize = {
|
type PizzaSize = {
|
||||||
@@ -20,7 +21,8 @@ type Pizza = {
|
|||||||
|
|
||||||
// TODO mělo by být konfigurovatelné proměnnou z prostředí s tímhle jako default
|
// TODO mělo by být konfigurovatelné proměnnou z prostředí s tímhle jako default
|
||||||
const baseUrl = 'https://www.pizzachefie.cz';
|
const baseUrl = 'https://www.pizzachefie.cz';
|
||||||
const pizzyUrl = `${baseUrl}/pizzy.html?pobocka=plzen`;
|
const pizzyUrl = `${baseUrl}/pizzy.html`;
|
||||||
|
const salayUrl = `${baseUrl}/salaty.html`;
|
||||||
|
|
||||||
const buildPizzaUrl = (pizzaUrl: string) => {
|
const buildPizzaUrl = (pizzaUrl: string) => {
|
||||||
return `${baseUrl}/${pizzaUrl}`;
|
return `${baseUrl}/${pizzaUrl}`;
|
||||||
@@ -34,6 +36,9 @@ const boxPrices: { [key: string]: number } = {
|
|||||||
"50cm": 25
|
"50cm": 25
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cena obalu pro salát
|
||||||
|
const SALAT_BOX_PRICE = 13;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stáhne a scrapne aktuální pizzy ze stránek Pizza Chefie.
|
* Stáhne a scrapne aktuální pizzy ze stránek Pizza Chefie.
|
||||||
*
|
*
|
||||||
@@ -85,3 +90,37 @@ export async function downloadPizzy(mock: boolean): Promise<Pizza[]> {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stáhne a scrapne aktuální saláty ze stránek Pizza Chefie.
|
||||||
|
* Příplatek za obal je pro každý salát pevně 13 Kč.
|
||||||
|
*
|
||||||
|
* @param mock zda vrátit pouze mock data
|
||||||
|
*/
|
||||||
|
export async function downloadSalaty(mock: boolean): Promise<Salat[]> {
|
||||||
|
if (mock) {
|
||||||
|
return new Promise((resolve) => setTimeout(() => resolve(getSalatListMock()), 1000));
|
||||||
|
}
|
||||||
|
const html = await axios.get(salayUrl).then(res => res.data);
|
||||||
|
const $ = load(html);
|
||||||
|
const links = $('.vypisproduktu > div > h4 > a');
|
||||||
|
const urls = [];
|
||||||
|
for (const element of links) {
|
||||||
|
if (element.name === 'a' && element.attribs?.href) {
|
||||||
|
urls.push(buildPizzaUrl(element.attribs.href));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const result: Salat[] = [];
|
||||||
|
for (const url of urls) {
|
||||||
|
const salatHtml = await axios.get(url).then(res => res.data);
|
||||||
|
const name = $('.produkt > h2', salatHtml).first().text().trim();
|
||||||
|
const ingredients: string[] = [];
|
||||||
|
$('.prisady > li', salatHtml).each((i, elm) => {
|
||||||
|
ingredients.push($(elm).text());
|
||||||
|
});
|
||||||
|
const priceText = $('.cena > span', salatHtml).first().text().trim();
|
||||||
|
const price = Number.parseInt(priceText.split(' Kč')[0]);
|
||||||
|
result.push({ name, ingredients, price: price + SALAT_BOX_PRICE });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -1429,6 +1429,34 @@ export const getPizzaListMock = () => {
|
|||||||
return MOCK_PIZZA_LIST;
|
return MOCK_PIZZA_LIST;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mockovací data pro saláty
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Caesar",
|
||||||
|
ingredients: ["Salát", "Rajčata", "Kuřecí maso", "Krutony", "Parmazán", "Caesar dresing", "Olivový olej"],
|
||||||
|
price: 184 + 13,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Šopský salát",
|
||||||
|
ingredients: ["Salátová okurka", "Rajčata", "Paprika mix", "Červená cibule", "Balkánský sýr"],
|
||||||
|
price: 164 + 13,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Těstovinový salát",
|
||||||
|
ingredients: ["Penne", "Okurka", "Rajčata", "Paprika mix", "Kuřecí maso", "Jogurtový dresing"],
|
||||||
|
price: 184 + 13,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
export const getSalatListMock = () => {
|
||||||
|
return MOCK_SALAT_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
export const getStatsMock = (): WeeklyStats => {
|
export const getStatsMock = (): WeeklyStats => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
+75
-5
@@ -2,9 +2,9 @@ import { formatDate } from "./utils";
|
|||||||
import { callNotifikace } from "./notifikace";
|
import { callNotifikace } from "./notifikace";
|
||||||
import { generateQr } from "./qr";
|
import { generateQr } from "./qr";
|
||||||
import getStorage from "./storage";
|
import getStorage from "./storage";
|
||||||
import { downloadPizzy } from "./chefie";
|
import { downloadPizzy, downloadSalaty } from "./chefie";
|
||||||
import { getClientData, getToday, initIfNeeded } from "./service";
|
import { getClientData, getToday, initIfNeeded } from "./service";
|
||||||
import { Pizza, ClientData, PizzaDayState, PizzaSize, PizzaOrder, PizzaVariant, UdalostEnum, PendingQr } from "../../types/gen/types.gen";
|
import { Pizza, Salat, ClientData, PizzaDayState, PizzaSize, PizzaOrder, PizzaVariant, UdalostEnum, PendingQr } from "../../types/gen/types.gen";
|
||||||
|
|
||||||
const storage = getStorage();
|
const storage = getStorage();
|
||||||
const PENDING_QR_PREFIX = 'pending_qr';
|
const PENDING_QR_PREFIX = 'pending_qr';
|
||||||
@@ -38,6 +38,34 @@ export async function savePizzaList(pizzaList: Pizza[]): Promise<ClientData> {
|
|||||||
return clientData;
|
return clientData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vrátí seznam dostupných salátů pro dnešní den.
|
||||||
|
* Stáhne je, pokud je pro dnešní den nemá.
|
||||||
|
*/
|
||||||
|
export async function getSalatList(): Promise<Salat[] | undefined> {
|
||||||
|
await initIfNeeded();
|
||||||
|
let clientData = await getClientData(getToday());
|
||||||
|
if (!clientData.salatList) {
|
||||||
|
const mock = process.env.MOCK_DATA === 'true';
|
||||||
|
clientData = await saveSalatList(await downloadSalaty(mock));
|
||||||
|
}
|
||||||
|
return Promise.resolve(clientData.salatList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uloží seznam dostupných salátů pro dnešní den.
|
||||||
|
*
|
||||||
|
* @param salatList seznam dostupných salátů
|
||||||
|
*/
|
||||||
|
export async function saveSalatList(salatList: Salat[]): Promise<ClientData> {
|
||||||
|
await initIfNeeded();
|
||||||
|
const today = formatDate(getToday());
|
||||||
|
const clientData = await getClientData(getToday());
|
||||||
|
clientData.salatList = salatList;
|
||||||
|
await storage.setData(today, clientData);
|
||||||
|
return clientData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vytvoří pizza day pro aktuální den a vrátí data pro klienta.
|
* Vytvoří pizza day pro aktuální den a vrátí data pro klienta.
|
||||||
*/
|
*/
|
||||||
@@ -48,8 +76,8 @@ export async function createPizzaDay(creator: string): Promise<ClientData> {
|
|||||||
throw Error("Pizza day pro dnešní den již existuje");
|
throw Error("Pizza day pro dnešní den již existuje");
|
||||||
}
|
}
|
||||||
// TODO berka rychlooprava, vyřešit lépe - stahovat jednou, na jediném místě!
|
// TODO berka rychlooprava, vyřešit lépe - stahovat jednou, na jediném místě!
|
||||||
const pizzaList = await getPizzaList();
|
const [pizzaList, salatList] = await Promise.all([getPizzaList(), getSalatList()]);
|
||||||
const data: ClientData = { pizzaDay: { state: PizzaDayState.CREATED, creator, orders: [] }, pizzaList, ...clientData };
|
const data: ClientData = { pizzaDay: { state: PizzaDayState.CREATED, creator, orders: [] }, pizzaList, salatList, ...clientData };
|
||||||
const today = formatDate(getToday());
|
const today = formatDate(getToday());
|
||||||
await storage.setData(today, data);
|
await storage.setData(today, data);
|
||||||
callNotifikace({ input: { udalost: UdalostEnum.ZAHAJENA_PIZZA, user: creator } })
|
callNotifikace({ input: { udalost: UdalostEnum.ZAHAJENA_PIZZA, user: creator } })
|
||||||
@@ -113,6 +141,46 @@ export async function addPizzaOrder(login: string, pizza: Pizza, size: PizzaSize
|
|||||||
return clientData;
|
return clientData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Přidá objednávku salátu uživateli.
|
||||||
|
*
|
||||||
|
* @param login login uživatele
|
||||||
|
* @param salat zvolený salát
|
||||||
|
*/
|
||||||
|
export async function addSalatOrder(login: string, salat: Salat) {
|
||||||
|
const today = formatDate(getToday());
|
||||||
|
const clientData = await getClientData(getToday());
|
||||||
|
if (!clientData.pizzaDay) {
|
||||||
|
throw Error("Pizza day pro dnešní den neexistuje");
|
||||||
|
}
|
||||||
|
if (clientData.pizzaDay.state !== PizzaDayState.CREATED) {
|
||||||
|
throw Error("Pizza day není ve stavu " + PizzaDayState.CREATED);
|
||||||
|
}
|
||||||
|
let order: PizzaOrder | undefined = clientData.pizzaDay?.orders?.find(o => o.customer === login);
|
||||||
|
if (!order) {
|
||||||
|
order = {
|
||||||
|
customer: login,
|
||||||
|
pizzaList: [],
|
||||||
|
totalPrice: 0,
|
||||||
|
hasQr: false,
|
||||||
|
}
|
||||||
|
clientData.pizzaDay.orders ??= [];
|
||||||
|
clientData.pizzaDay.orders.push(order);
|
||||||
|
}
|
||||||
|
const salatOrder: PizzaVariant = {
|
||||||
|
varId: 0,
|
||||||
|
name: salat.name,
|
||||||
|
size: "1 porce",
|
||||||
|
price: salat.price,
|
||||||
|
category: 'salat',
|
||||||
|
}
|
||||||
|
order.pizzaList ??= [];
|
||||||
|
order.pizzaList.push(salatOrder);
|
||||||
|
order.totalPrice += salatOrder.price;
|
||||||
|
await storage.setData(today, clientData);
|
||||||
|
return clientData;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Odstraní všechny pizzy uživatele (celou jeho objednávku).
|
* Odstraní všechny pizzy uživatele (celou jeho objednávku).
|
||||||
* Pokud Pizza day neexistuje nebo není ve stavu CREATED, neudělá nic.
|
* Pokud Pizza day neexistuje nebo není ve stavu CREATED, neudělá nic.
|
||||||
@@ -269,7 +337,9 @@ export async function finishPizzaDelivery(login: string, bankAccount?: string, b
|
|||||||
if (bankAccount?.length && bankAccountHolder?.length) {
|
if (bankAccount?.length && bankAccountHolder?.length) {
|
||||||
for (const order of clientData.pizzaDay.orders!) {
|
for (const order of clientData.pizzaDay.orders!) {
|
||||||
if (order.customer !== login) { // zatím platí creator = objednávající, a pro toho nemá QR kód smysl
|
if (order.customer !== login) { // zatím platí creator = objednávající, a pro toho nemá QR kód smysl
|
||||||
let message = order.pizzaList!.map(pizza => `Pizza ${pizza.name} (${pizza.size})`).join(', ');
|
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);
|
await generateQr(order.customer, bankAccount, bankAccountHolder, order.totalPrice, message);
|
||||||
order.hasQr = true;
|
order.hasQr = true;
|
||||||
// Uložíme nevyřízený QR kód pro persistentní zobrazení
|
// Uložíme nevyřízený QR kód pro persistentní zobrazení
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import express, { Request } from "express";
|
import express, { Request } from "express";
|
||||||
import { getLogin } from "../auth";
|
import { getLogin } from "../auth";
|
||||||
import { createPizzaDay, deletePizzaDay, getPizzaList, addPizzaOrder, removePizzaOrder, lockPizzaDay, unlockPizzaDay, finishPizzaOrder, finishPizzaDelivery, updatePizzaDayNote, updatePizzaFee, dismissPendingQr } from "../pizza";
|
import { createPizzaDay, deletePizzaDay, getPizzaList, getSalatList, addPizzaOrder, addSalatOrder, removePizzaOrder, lockPizzaDay, unlockPizzaDay, finishPizzaOrder, finishPizzaDelivery, updatePizzaDayNote, updatePizzaFee, dismissPendingQr } from "../pizza";
|
||||||
import { parseToken } from "../utils";
|
import { parseToken } from "../utils";
|
||||||
import { getWebsocket } from "../websocket";
|
import { getWebsocket } from "../websocket";
|
||||||
import { AddPizzaData, DismissQrData, FinishDeliveryData, RemovePizzaData, UpdatePizzaDayNoteData, UpdatePizzaFeeData } from "../../../types";
|
import { AddPizzaData, DismissQrData, FinishDeliveryData, RemovePizzaData, UpdatePizzaDayNoteData, UpdatePizzaFeeData } from "../../../types";
|
||||||
@@ -24,11 +24,26 @@ router.post("/delete", async (req: Request<{}, any, undefined>, res) => {
|
|||||||
|
|
||||||
router.post("/add", async (req: Request<{}, any, AddPizzaData["body"]>, res) => {
|
router.post("/add", async (req: Request<{}, any, AddPizzaData["body"]>, res) => {
|
||||||
const login = getLogin(parseToken(req));
|
const login = getLogin(parseToken(req));
|
||||||
if (isNaN(req.body?.pizzaIndex)) {
|
if (req.body?.salatIndex !== undefined && !isNaN(req.body.salatIndex)) {
|
||||||
throw Error("Nebyl předán index pizzy");
|
// Přidání salátu
|
||||||
|
const salatIndex = req.body.salatIndex;
|
||||||
|
const salaty = await getSalatList();
|
||||||
|
if (!salaty) {
|
||||||
|
throw Error("Selhalo získání seznamu dostupných salátů.");
|
||||||
|
}
|
||||||
|
if (!salaty[salatIndex]) {
|
||||||
|
throw Error("Neplatný index salátu: " + salatIndex);
|
||||||
|
}
|
||||||
|
const data = await addSalatOrder(login, salaty[salatIndex]);
|
||||||
|
getWebsocket().emit("message", data);
|
||||||
|
res.status(200).json({});
|
||||||
|
} else {
|
||||||
|
// Přidání pizzy
|
||||||
|
if (req.body?.pizzaIndex === undefined || isNaN(req.body.pizzaIndex)) {
|
||||||
|
throw Error("Nebyl předán index pizzy ani salátu");
|
||||||
}
|
}
|
||||||
const pizzaIndex = req.body.pizzaIndex;
|
const pizzaIndex = req.body.pizzaIndex;
|
||||||
if (isNaN(req.body?.pizzaSizeIndex)) {
|
if (req.body?.pizzaSizeIndex === undefined || isNaN(req.body.pizzaSizeIndex)) {
|
||||||
throw Error("Nebyl předán index velikosti pizzy");
|
throw Error("Nebyl předán index velikosti pizzy");
|
||||||
}
|
}
|
||||||
const pizzaSizeIndex = req.body.pizzaSizeIndex;
|
const pizzaSizeIndex = req.body.pizzaSizeIndex;
|
||||||
@@ -45,6 +60,7 @@ router.post("/add", async (req: Request<{}, any, AddPizzaData["body"]>, res) =>
|
|||||||
const data = await addPizzaOrder(login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
const data = await addPizzaOrder(login, pizzy[pizzaIndex], pizzy[pizzaIndex].sizes[pizzaSizeIndex]);
|
||||||
getWebsocket().emit("message", data);
|
getWebsocket().emit("message", data);
|
||||||
res.status(200).json({});
|
res.status(200).json({});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/remove", async (req: Request<{}, any, RemovePizzaData["body"]>, res) => {
|
router.post("/remove", async (req: Request<{}, any, RemovePizzaData["body"]>, res) => {
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
post:
|
post:
|
||||||
operationId: addPizza
|
operationId: addPizza
|
||||||
summary: Přidání pizzy do objednávky.
|
summary: Přidání pizzy nebo salátu do objednávky.
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
required:
|
|
||||||
- pizzaIndex
|
|
||||||
- pizzaSizeIndex
|
|
||||||
properties:
|
properties:
|
||||||
pizzaIndex:
|
pizzaIndex:
|
||||||
description: Index pizzy v nabídce
|
description: Index pizzy v nabídce (pro přidání pizzy)
|
||||||
type: integer
|
type: integer
|
||||||
pizzaSizeIndex:
|
pizzaSizeIndex:
|
||||||
description: Index velikosti pizzy v nabídce variant
|
description: Index velikosti pizzy v nabídce variant (pro přidání pizzy)
|
||||||
|
type: integer
|
||||||
|
salatIndex:
|
||||||
|
description: Index salátu v nabídce (pro přidání salátu)
|
||||||
type: integer
|
type: integer
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Přidání pizzy do objednávky proběhlo úspěšně.
|
description: Přidání pizzy nebo salátu do objednávky proběhlo úspěšně.
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ ClientData:
|
|||||||
description: Datum a čas poslední aktualizace pizz
|
description: Datum a čas poslední aktualizace pizz
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
salatList:
|
||||||
|
description: Seznam dostupných salátů pro předaný den
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/Salat"
|
||||||
pendingQrs:
|
pendingQrs:
|
||||||
description: Nevyřízené QR kódy pro platbu z předchozích pizza day
|
description: Nevyřízené QR kódy pro platbu z předchozích pizza day
|
||||||
type: array
|
type: array
|
||||||
@@ -426,7 +431,7 @@ Pizza:
|
|||||||
items:
|
items:
|
||||||
$ref: "#/PizzaSize"
|
$ref: "#/PizzaSize"
|
||||||
PizzaVariant:
|
PizzaVariant:
|
||||||
description: Konkrétní varianta (velikost) jedné pizzy.
|
description: Konkrétní varianta (velikost) jedné pizzy nebo salátu.
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
required:
|
required:
|
||||||
@@ -436,16 +441,40 @@ PizzaVariant:
|
|||||||
- price
|
- price
|
||||||
properties:
|
properties:
|
||||||
varId:
|
varId:
|
||||||
description: Unikátní identifikátor varianty pizzy
|
description: Unikátní identifikátor varianty
|
||||||
type: integer
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: Název pizzy
|
description: Název pizzy nebo salátu
|
||||||
type: string
|
type: string
|
||||||
size:
|
size:
|
||||||
description: Velikost pizzy (např. "30cm")
|
description: Velikost pizzy (např. "30cm"), nebo "1 porce" pro salát
|
||||||
type: string
|
type: string
|
||||||
price:
|
price:
|
||||||
description: Cena pizzy v Kč, včetně krabice
|
description: Cena v Kč, včetně krabice/obalu
|
||||||
|
type: number
|
||||||
|
category:
|
||||||
|
description: Kategorie položky (pizza nebo salat)
|
||||||
|
type: string
|
||||||
|
enum: [pizza, salat]
|
||||||
|
Salat:
|
||||||
|
description: Salát z nabídky Pizza Chefie
|
||||||
|
type: object
|
||||||
|
additionalProperties: false
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- ingredients
|
||||||
|
- price
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Název salátu
|
||||||
|
type: string
|
||||||
|
ingredients:
|
||||||
|
description: Seznam obsažených ingrediencí
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
price:
|
||||||
|
description: Cena salátu v Kč (bez obalu)
|
||||||
type: number
|
type: number
|
||||||
PizzaOrder:
|
PizzaOrder:
|
||||||
description: Údaje o objednávce pizzy jednoho uživatele.
|
description: Údaje o objednávce pizzy jednoho uživatele.
|
||||||
|
|||||||
Reference in New Issue
Block a user