caterium-app/ops/demo/trial-demo-data.mjs

80 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Fictional training recipes and prices. No customer or Solnce catalog data.
const suppliers=[
['fresh','Демо: овощи и молочные продукты'],['protein','Демо: мясо и рыба'],
['bakery','Демо: пекарня'],['grocery','Демо: бакалея'],['pack','Демо: упаковка']
].map(([key,name])=>({id:`demo-v1-supplier-${key}`,name,active:true,category:'Учебный поставщик',contact:'',phone:'',email:'',address:'',deliveryDays:'По договорённости',minOrder:0,note:'Вымышленный поставщик для знакомства с приложением.'}));
// key, product name, purchase unit price, supplier, unit
const products=[
['baguette','Багет',240,'bakery'],['tomato','Томаты',260,'fresh'],['basil','Базилик',1500,'fresh'],
['oil','Масло оливковое',1100,'grocery'],['rye','Хлеб ржаной',220,'bakery'],
['salmon','Лосось слабосолёный',2400,'protein'],['cream','Сыр сливочный',850,'fresh'],
['cucumber','Огурцы',220,'fresh'],['dill','Укроп',700,'fresh'],['toast','Хлеб тостовый',240,'bakery'],
['chicken','Филе курицы готовое',850,'protein'],['lettuce','Салат листовой',700,'fresh'],
['mozzarella','Моцарелла мини',950,'fresh'],['cherry','Томаты черри',450,'fresh'],
['tartlet','Тарталетки готовые',750,'bakery'],['mushroom','Шампиньоны',340,'fresh'],
['cooking-cream','Сливки',500,'fresh'],['gouda','Сыр гауда',900,'fresh'],['onion','Лук репчатый',80,'fresh'],
['tortilla','Тортилья',450,'bakery'],['turkey','Ветчина из индейки',1000,'protein'],['pepper','Перец сладкий',380,'fresh'],
['brie','Сыр бри',1600,'fresh'],['blue','Сыр с голубой плесенью',1700,'fresh'],['grape','Виноград',420,'fresh'],
['walnut','Орех грецкий очищенный',1000,'grocery'],['honey','Мёд',800,'grocery'],['cracker','Крекер',500,'bakery'],
['salami','Салями',1400,'protein'],['beef','Ростбиф готовый',2000,'protein'],['pickle','Корнишоны',400,'grocery'],
['olive','Маслины без косточек',650,'grocery'],['mustard','Горчица',350,'grocery'],['carrot','Морковь',90,'fresh'],
['hummus','Хумус готовый',600,'grocery'],['biscuit','Крошка бисквитная',500,'bakery'],
['strawberry','Клубника',750,'fresh'],['blueberry','Голубика',1300,'fresh'],['sugar','Пудра сахарная',160,'grocery'],
['box','Коробка для кейтеринга',65,'pack','шт.'],['skewer','Шпажка бамбуковая',2,'pack','шт.'],
['cup','Стаканчик десертный',9,'pack','шт.'],['sauce-cup','Соусник',7,'pack','шт.']
].map(([key,name,cost,supplier,unit='кг'])=>({key,id:`demo-v1-stock-${key}`,name,cost,unit,supplierId:`demo-v1-supplier-${supplier}`}));
const byKey=new Map(products.map(p=>[p.key,p]));
// Product quantities are gross/net in grams; packaging is in pieces.
const recipes=[
{id:'bruschetta-tomato',name:'Брускетты с томатами и базиликом',price:2200,pieces:24,
rows:[['baguette',480,480],['tomato',330,300],['basil',26,24],['oil',36,36]],
composition:['24 брускетты с томатами, базиликом и оливковым маслом'],allergens:['Глютен'],
steps:['Нарезать багет на 24 одинаковых ломтика и подсушить.','Подготовить томаты и базилик, смешать с маслом.','Распределить начинку по ломтикам, уложить в коробку.']},
{id:'salmon-cream',name:'Канапе с лососем и сливочным сыром',price:3200,pieces:16,
rows:[['rye',240,240],['salmon',240,240],['cream',160,160],['cucumber',84,72],['dill',10,8]],
composition:['16 канапе на ржаном хлебе с лососем, сливочным сыром и огурцом'],allergens:['Рыба','Молоко','Глютен'],
steps:['Вырезать из ржаного хлеба 16 основ.','Нанести сливочный сыр, добавить ломтики огурца и лосося.','Украсить укропом и уложить в коробку.']},
{id:'chicken-sandwich',name:'Мини-сэндвичи с курицей',price:2400,pieces:12,
rows:[['toast',360,360],['chicken',240,240],['cream',120,120],['tomato',92,84],['lettuce',45,36]],
composition:['12 мини-сэндвичей с готовым куриным филе, томатами, салатом и сливочным сыром'],allergens:['Глютен','Молоко'],
steps:['Нарезать готовое куриное филе, подготовить овощи и салат.','Собрать сэндвичи из тостового хлеба, сыра, курицы и овощей.','Нарезать на 12 одинаковых мини-сэндвичей и упаковать.']},
{id:'caprese',name:'Канапе «Капрезе»',price:2100,pieces:20,
rows:[['mozzarella',360,360],['cherry',308,280],['basil',22,20],['oil',40,40],['skewer',20,20]],
composition:['20 шпажек с моцареллой, черри и базиликом'],allergens:['Молоко'],
steps:['Подготовить черри и базилик, обсушить моцареллу.','Собрать 20 шпажек, распределив ингредиенты поровну.','Добавить оливковое масло, уложить в коробку.']},
{id:'mushroom-tartlet',name:'Тарталетки с грибами и сыром',price:2300,pieces:20,
rows:[['tartlet',200,200],['mushroom',440,300],['cooking-cream',100,100],['gouda',120,120],['onion',88,60],['oil',20,20]],
composition:['20 тарталеток с шампиньонами, сливками и сыром'],allergens:['Глютен','Молоко'],
steps:['Подготовить и обжарить лук с грибами на масле; в расчёте учтены потери массы.','Добавить сливки и распределить начинку по 20 тарталеткам.','Добавить сыр, запечь до расплавления и упаковать после охлаждения.']},
{id:'turkey-wrap',name:'Роллы из тортильи с индейкой',price:2700,pieces:25,
rows:[['tortilla',320,320],['turkey',320,320],['cream',180,180],['lettuce',75,60],['pepper',150,120]],
composition:['25 мини-роллов с ветчиной из индейки, сливочным сыром, перцем и салатом'],allergens:['Глютен','Молоко'],
steps:['Подготовить салат и перец, нарезать ветчину.','Нанести сыр на тортильи, распределить начинку и свернуть плотные рулеты.','Нарезать на 25 порций и уложить срезом вверх.']},
{id:'cheese-fruit',name:'Сырный бокс с виноградом и орехами',price:2900,pieces:0,
rows:[['brie',200,200],['gouda',180,180],['blue',120,120],['grape',176,160],['walnut',50,50],['honey',40,40],['cracker',50,50],['sauce-cup',1,1]],
composition:['Бри, гауда и сыр с голубой плесенью','Виноград, грецкий орех, мёд и крекер'],allergens:['Молоко','Орехи','Глютен'],
steps:['Нарезать сыры порционными кусочками.','Подготовить виноград, переложить мёд в соусник.','Разложить сыры, виноград, орехи и крекер отдельными секциями.']},
{id:'meat-assortment',name:'Мясное ассорти с корнишонами',price:3200,pieces:0,
rows:[['salami',180,180],['beef',220,220],['turkey',150,150],['pickle',90,80],['olive',45,40],['mustard',30,30],['sauce-cup',1,1]],
composition:['Салями, готовый ростбиф и ветчина из индейки','Корнишоны, маслины и горчица'],allergens:['Горчица'],
steps:['Нарезать готовые мясные продукты тонкими ломтиками.','Обсушить корнишоны и маслины, переложить горчицу в соусник.','Разложить ассорти секциями, добавить гарниры.']},
{id:'vegetables-hummus',name:'Овощной бокс с хумусом',price:2100,pieces:0,
rows:[['carrot',300,250],['cucumber',275,250],['pepper',250,200],['cherry',165,150],['hummus',150,150],['sauce-cup',1,1]],
composition:['Морковь, огурцы, сладкий перец и черри','Хумус в отдельном соуснике'],allergens:['Кунжут в составе хумуса'],
steps:['Вымыть и подготовить овощи; очистить морковь и перец.','Нарезать овощи палочками, черри оставить целыми.','Переложить хумус в соусник и разложить овощи вокруг него.']},
{id:'berry-dessert',name:'Ягодные мини-десерты',price:2800,pieces:16,
rows:[['biscuit',160,160],['cream',320,320],['cooking-cream',160,160],['strawberry',176,160],['blueberry',84,80],['sugar',80,80],['cup',16,16]],
composition:['16 десертов со сливочным кремом, бисквитом, клубникой и голубикой'],allergens:['Молоко','Глютен','Яйцо в составе бисквита'],
steps:['Подготовить ягоды, разделить готовый бисквит на крошку.','Смешать сливочный сыр, сливки и сахарную пудру в крем.','Собрать 16 стаканчиков слоями: бисквит, крем, ягоды.']}
];
const round=n=>Math.round(n*1000)/1000;
const totals=new Map();
export const boxes=recipes.map((r,index)=>{
const rows=[...r.rows,['box',1,1]].map(([key,gross,net])=>{const p=byKey.get(key),scale=p.unit==='кг'?1000:1;const row={productId:p.id,name:p.name,unit:p.unit,gross:round(gross/scale),net:round(net/scale),unitCost:p.cost};totals.set(key,round((totals.get(key)||0)+row.gross));return row});
const outputGrams=Math.round(rows.filter(p=>p.unit==='кг').reduce((s,p)=>s+p.net*1000,0));
return {id:`demo-v1-${r.id}`,name:r.name,price:r.price,category:0,catalogSection:'Демонстрационные боксы',pieces:r.pieces,weight:`${outputGrams} г`,photo:`demo/images/${r.id}.png`,composition:r.composition,ingredients:rows.map(p=>[p.name,p.gross,p.unit]),demo:true,ttk:{number:`ДЕМО-${String(index+1).padStart(2,'0')}`,basis:'На 1 готовый бокс',outputGrams,pieces:r.pieces,rows,steps:r.steps,allergens:r.allergens,ingredientCost:Math.round(rows.reduce((s,p)=>s+p.gross*p.unitCost,0)*100)/100,note:'Учебные нормы и цены для знакомства с приложением.'}};
});
export const stock=products.map((p,index)=>({id:p.id,name:p.name,unit:p.unit,cost:p.cost,qty:(p.unit==='шт.'?Math.floor:round)((totals.get(p.key)||0)*[0,0.45,2,0.7][index%4]),min:p.unit==='кг'?0.1:2,supplierId:p.supplierId,lastPurchaseDate:'',lastPurchasePrice:0}));
export {suppliers};
export const demo={version:1,batch:'trial-demo-v1',boxes,stock,suppliers,scenario:{lines:[{id:'demo-v1-bruschetta-tomato',qty:2},{id:'demo-v1-salmon-cream',qty:1},{id:'demo-v1-caprese',qty:1}]}};