fix: dočasné skrytí podniku Šenk Šeříková
CI / Generate TypeScript types (push) Successful in 11s
CI / Server unit tests (push) Successful in 27s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 40s
CI / Playwright E2E tests (push) Failing after 2m44s
CI / Build and push Docker image (push) Skipped
CI / Notify (push) Successful in 2s
CI / Generate TypeScript types (push) Successful in 11s
CI / Server unit tests (push) Successful in 27s
CI / Build server (push) Successful in 29s
CI / Build client (push) Successful in 40s
CI / Playwright E2E tests (push) Failing after 2m44s
CI / Build and push Docker image (push) Skipped
CI / Notify (push) Successful in 2s
This commit is contained in:
+7
-3
@@ -609,7 +609,7 @@ function App() {
|
|||||||
} else {
|
} else {
|
||||||
content = <div className="restaurant-error">Chyba načtení dat</div>
|
content = <div className="restaurant-error">Chyba načtení dat</div>
|
||||||
}
|
}
|
||||||
return <Col md={6} lg={3} className='mt-3'>
|
return <Col md={6} lg className='mt-3'>
|
||||||
<div className="restaurant-card">
|
<div className="restaurant-card">
|
||||||
<div className="restaurant-header" style={{ cursor: canChangeChoice ? 'pointer' : 'default' }} onClick={() => doAddClickFoodChoice(location)}>
|
<div className="restaurant-header" style={{ cursor: canChangeChoice ? 'pointer' : 'default' }} onClick={() => doAddClickFoodChoice(location)}>
|
||||||
<div className="restaurant-header-content">
|
<div className="restaurant-header-content">
|
||||||
@@ -684,7 +684,7 @@ function App() {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<Row className='food-tables'>
|
<Row className='food-tables justify-content-center'>
|
||||||
{Object.keys(Restaurant).map(key => {
|
{Object.keys(Restaurant).map(key => {
|
||||||
const locationKey = key as Restaurant;
|
const locationKey = key as Restaurant;
|
||||||
return food[locationKey] && renderFoodTable(locationKey, food[locationKey]);
|
return food[locationKey] && renderFoodTable(locationKey, food[locationKey]);
|
||||||
@@ -699,7 +699,11 @@ function App() {
|
|||||||
{Object.entries(LunchChoice)
|
{Object.entries(LunchChoice)
|
||||||
.filter(entry => {
|
.filter(entry => {
|
||||||
const locationKey = entry[0] as Restaurant;
|
const locationKey = entry[0] as Restaurant;
|
||||||
return !food[locationKey]?.closed;
|
// Podniky, pro které server nevrátil menu (dočasně uzavřené), nenabízíme
|
||||||
|
if (Object.keys(Restaurant).includes(locationKey) && !food?.[locationKey]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !food?.[locationKey]?.closed;
|
||||||
})
|
})
|
||||||
.map(entry => <option key={entry[0]} value={entry[0]}>{getLunchChoiceName(entry[1])}</option>)}
|
.map(entry => <option key={entry[0]} value={entry[0]}>{getLunchChoiceName(entry[1])}</option>)}
|
||||||
</Form.Select>
|
</Form.Select>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
[
|
[
|
||||||
"Opraveno načítání jídelního lístku TechTower po změně jejich webu"
|
"Opraveno načítání jídelního lístku TechTower po změně jejich webu",
|
||||||
|
"Šenk Šeříková je dočasně skryt, protože je podnik uzavřen"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import express, { Request } from "express";
|
import express, { Request } from "express";
|
||||||
import { getDateForWeekIndex, getData, getRestaurantMenu, getToday, initIfNeeded } from "../service";
|
import { getDateForWeekIndex, getData, isRestaurantDisabled, getActiveRestaurants, getRestaurantMenu, getToday, initIfNeeded } from "../service";
|
||||||
import { formatDate, getDayOfWeekIndex } from "../utils";
|
import { formatDate, getDayOfWeekIndex } from "../utils";
|
||||||
import getStorage from "../storage";
|
import getStorage from "../storage";
|
||||||
import { getWebsocket } from "../websocket";
|
import { getWebsocket } from "../websocket";
|
||||||
import { getLogin } from "../auth";
|
import { getLogin } from "../auth";
|
||||||
import { parseToken } from "../utils";
|
import { parseToken } from "../utils";
|
||||||
import webpush from 'web-push';
|
import webpush from 'web-push';
|
||||||
import { ClientData, GroupState, MealSlot, OrderGroupMember, TrackingProvider } from "../../../types/gen/types.gen";
|
import { ClientData, GroupState, MealSlot, OrderGroupMember, Restaurant, TrackingProvider } from "../../../types/gen/types.gen";
|
||||||
import { getStores } from "../stores";
|
import { getStores } from "../stores";
|
||||||
import { createGroup } from "../groups";
|
import { createGroup } from "../groups";
|
||||||
import {
|
import {
|
||||||
@@ -36,7 +36,7 @@ const LUNCH_CHOICES = [
|
|||||||
'OBJEDNAVAM',
|
'OBJEDNAVAM',
|
||||||
'NEOBEDVAM',
|
'NEOBEDVAM',
|
||||||
'ROZHODUJI',
|
'ROZHODUJI',
|
||||||
];
|
].filter(choice => !isRestaurantDisabled(choice as Restaurant));
|
||||||
|
|
||||||
// Náhodné názvy jídel do poznámek mock objednávek
|
// Náhodné názvy jídel do poznámek mock objednávek
|
||||||
const MOCK_ORDER_FOODS = [
|
const MOCK_ORDER_FOODS = [
|
||||||
@@ -72,12 +72,7 @@ const MAX_ORDER_MEMBER_COUNT = 50;
|
|||||||
const MAX_ORDER_AMOUNT = 100000;
|
const MAX_ORDER_AMOUNT = 100000;
|
||||||
|
|
||||||
// Restaurace s menu
|
// Restaurace s menu
|
||||||
const RESTAURANTS_WITH_MENU = [
|
const RESTAURANTS_WITH_MENU = getActiveRestaurants();
|
||||||
'SLADOVNICKA',
|
|
||||||
'TECHTOWER',
|
|
||||||
'ZASTAVKAUMICHALA',
|
|
||||||
'SENKSERIKOVA',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Middleware pro kontrolu DEV režimu
|
* Middleware pro kontrolu DEV režimu
|
||||||
@@ -138,7 +133,7 @@ async function generateMockDataForDay(dayIndex: number, requestedCount?: number)
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Pokud má restaurace menu, vybereme náhodné jídlo
|
// Pokud má restaurace menu, vybereme náhodné jídlo
|
||||||
if (RESTAURANTS_WITH_MENU.includes(choice) && menus[choice]?.length) {
|
if (RESTAURANTS_WITH_MENU.includes(choice as Restaurant) && menus[choice]?.length) {
|
||||||
const foods = menus[choice];
|
const foods = menus[choice];
|
||||||
// Vybereme náhodné jídlo (ne polévku)
|
// Vybereme náhodné jídlo (ne polévku)
|
||||||
const mainFoods = foods.filter((f: any) => !f.isSoup);
|
const mainFoods = foods.filter((f: any) => !f.isSoup);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import express, { Request, Response } from "express";
|
import express, { Request, Response } from "express";
|
||||||
import { getLogin, getTrusted } from "../auth";
|
import { getLogin, getTrusted } from "../auth";
|
||||||
import { addChoice, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime, updateNote, fetchRestaurantWeekMenuData, saveRestaurantWeekMenu, updateBuyer } from "../service";
|
import { addChoice, getActiveRestaurants, getDateForWeekIndex, getToday, removeChoice, removeChoices, updateDepartureTime, updateNote, fetchRestaurantWeekMenuData, saveRestaurantWeekMenu, updateBuyer } from "../service";
|
||||||
import { getDayOfWeekIndex, parseToken, getFirstWorkDayOfWeek } from "../utils";
|
import { getDayOfWeekIndex, parseToken, getFirstWorkDayOfWeek } from "../utils";
|
||||||
import { getWebsocket } from "../websocket";
|
import { getWebsocket } from "../websocket";
|
||||||
import { callNotifikace } from "../notifikace";
|
import { callNotifikace } from "../notifikace";
|
||||||
@@ -232,8 +232,8 @@ export const refreshMetoda = async (req: Request, res: Response) => {
|
|||||||
return res.status(400).json({ error: "ještě neumim TODO..." });
|
return res.status(400).json({ error: "ještě neumim TODO..." });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Pro všechny restaurace refreshni menu na aktuální týden
|
// Pro všechny aktivní restaurace refreshni menu na aktuální týden
|
||||||
const restaurants = ["SLADOVNICKA", "TECHTOWER", "ZASTAVKAUMICHALA", "SENKSERIKOVA"] as const;
|
const restaurants = getActiveRestaurants();
|
||||||
const firstDay = getFirstWorkDayOfWeek(getToday());
|
const firstDay = getFirstWorkDayOfWeek(getToday());
|
||||||
const results: Record<string, any> = {};
|
const results: Record<string, any> = {};
|
||||||
const successfulRestaurants: string[] = [];
|
const successfulRestaurants: string[] = [];
|
||||||
|
|||||||
+28
-7
@@ -9,6 +9,24 @@ import { ClientData, DepartureTime, LunchChoice, LunchChoices, MealSlot, PizzaDa
|
|||||||
const storage = getStorage();
|
const storage = getStorage();
|
||||||
const MENU_PREFIX = 'menu';
|
const MENU_PREFIX = 'menu';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dočasně uzavřené podniky – nezobrazují se na hlavní stránce, nelze je zvolit
|
||||||
|
* a neprovádí se pro ně načítání menu z jejich webu.
|
||||||
|
*/
|
||||||
|
export const DISABLED_RESTAURANTS: readonly Restaurant[] = [
|
||||||
|
Restaurant.SENKSERIKOVA, // dočasně uzavřen
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Vrátí true, pokud je podnik dočasně vyřazen z nabídky. */
|
||||||
|
export function isRestaurantDisabled(restaurant: Restaurant | LunchChoice): boolean {
|
||||||
|
return DISABLED_RESTAURANTS.includes(restaurant as Restaurant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vrátí podniky s menu, které nejsou dočasně vyřazeny. */
|
||||||
|
export function getActiveRestaurants(): Restaurant[] {
|
||||||
|
return (Object.values(Restaurant) as Restaurant[]).filter(r => !isRestaurantDisabled(r));
|
||||||
|
}
|
||||||
|
|
||||||
function getDataKey(date: Date, slot?: MealSlot): string {
|
function getDataKey(date: Date, slot?: MealSlot): string {
|
||||||
const base = formatDate(date);
|
const base = formatDate(date);
|
||||||
return slot === MealSlot.EXTRA ? `${base}_extra` : base;
|
return slot === MealSlot.EXTRA ? `${base}_extra` : base;
|
||||||
@@ -55,13 +73,12 @@ export async function getData(date?: Date, slot?: MealSlot): Promise<ClientData>
|
|||||||
if (slot === MealSlot.EXTRA) {
|
if (slot === MealSlot.EXTRA) {
|
||||||
clientData.stores = await getStores();
|
clientData.stores = await getStores();
|
||||||
} else {
|
} else {
|
||||||
clientData.menus = {
|
// Dočasně vyřazené podniky se do odpovědi vůbec nezahrnují (klient je pak nezobrazí)
|
||||||
SLADOVNICKA: await getRestaurantMenu('SLADOVNICKA', date),
|
const menus: RestaurantDayMenuMap = {};
|
||||||
// UMOTLIKU: await getRestaurantMenu('UMOTLIKU', date),
|
for (const restaurant of getActiveRestaurants()) {
|
||||||
TECHTOWER: await getRestaurantMenu('TECHTOWER', date),
|
menus[restaurant] = await getRestaurantMenu(restaurant, date);
|
||||||
ZASTAVKAUMICHALA: await getRestaurantMenu('ZASTAVKAUMICHALA', date),
|
|
||||||
SENKSERIKOVA: await getRestaurantMenu('SENKSERIKOVA', date),
|
|
||||||
}
|
}
|
||||||
|
clientData.menus = menus;
|
||||||
// Očistí volby jídel odkazující na indexy, které v aktuálním menu již neexistují.
|
// Očistí volby jídel odkazující na indexy, které v aktuálním menu již neexistují.
|
||||||
// Pokud se v odpovědi něco změnilo, promítne očistu i do uložených dat (self-heal).
|
// Pokud se v odpovědi něco změnilo, promítne očistu i do uložených dat (self-heal).
|
||||||
if (pruneStaleFoodChoices(clientData.choices, clientData.menus)) {
|
if (pruneStaleFoodChoices(clientData.choices, clientData.menus)) {
|
||||||
@@ -236,7 +253,8 @@ export async function getRestaurantMenu(restaurant: Restaurant, date?: Date, for
|
|||||||
const usedDate = date ?? getToday();
|
const usedDate = date ?? getToday();
|
||||||
const dayOfWeekIndex = getDayOfWeekIndex(usedDate);
|
const dayOfWeekIndex = getDayOfWeekIndex(usedDate);
|
||||||
const now = new Date().getTime();
|
const now = new Date().getTime();
|
||||||
if (getIsWeekend(usedDate)) {
|
// O víkendu a u dočasně vyřazených podniků menu vůbec nenačítáme
|
||||||
|
if (getIsWeekend(usedDate) || isRestaurantDisabled(restaurant)) {
|
||||||
return {
|
return {
|
||||||
lastUpdate: now,
|
lastUpdate: now,
|
||||||
closed: true,
|
closed: true,
|
||||||
@@ -468,6 +486,9 @@ export async function addChoice(login: string, trusted: boolean, locationKey: Lu
|
|||||||
await initIfNeeded(usedDate, slot);
|
await initIfNeeded(usedDate, slot);
|
||||||
let data = await getClientData(usedDate, slot);
|
let data = await getClientData(usedDate, slot);
|
||||||
validateTrusted(data, login, trusted);
|
validateTrusted(data, login, trusted);
|
||||||
|
if (isRestaurantDisabled(locationKey)) {
|
||||||
|
throw new Error(`Podnik ${locationKey} je dočasně uzavřen`);
|
||||||
|
}
|
||||||
await validateFoodIndex(locationKey, foodIndex, date);
|
await validateFoodIndex(locationKey, foodIndex, date);
|
||||||
|
|
||||||
if (!slot || slot === MealSlot.OBED) {
|
if (!slot || slot === MealSlot.OBED) {
|
||||||
|
|||||||
Reference in New Issue
Block a user