-- Generated by ops/demo/build-trial-demo.mjs. Fictional training catalog only. begin; create or replace function public.caterium_trial_demo_seed_v1() returns jsonb language sql immutable security definer set search_path=public,pg_temp as $fn$ select $demo${"version":1,"batch":"trial-demo-v1","boxes":[{"id":"demo-v1-bruschetta-tomato","name":"Брускетты с томатами и базиликом","price":2200,"category":0,"catalogSection":"Демонстрационные боксы","pieces":24,"weight":"840 г","photo":"demo/images/bruschetta-tomato.png","composition":["24 брускетты с томатами, базиликом и оливковым маслом"],"ingredients":[["Багет",0.48,"кг"],["Томаты",0.33,"кг"],["Базилик",0.026,"кг"],["Масло оливковое",0.036,"кг"],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-01","basis":"На 1 готовый бокс","outputGrams":840,"pieces":24,"rows":[{"productId":"demo-v1-stock-baguette","name":"Багет","unit":"кг","gross":0.48,"net":0.48,"unitCost":240},{"productId":"demo-v1-stock-tomato","name":"Томаты","unit":"кг","gross":0.33,"net":0.3,"unitCost":260},{"productId":"demo-v1-stock-basil","name":"Базилик","unit":"кг","gross":0.026,"net":0.024,"unitCost":1500},{"productId":"demo-v1-stock-oil","name":"Масло оливковое","unit":"кг","gross":0.036,"net":0.036,"unitCost":1100},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Нарезать багет на 24 одинаковых ломтика и подсушить.","Подготовить томаты и базилик, смешать с маслом.","Распределить начинку по ломтикам, уложить в коробку."],"allergens":["Глютен"],"ingredientCost":344.6,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-salmon-cream","name":"Канапе с лососем и сливочным сыром","price":3200,"category":0,"catalogSection":"Демонстрационные боксы","pieces":16,"weight":"720 г","photo":"demo/images/salmon-cream.png","composition":["16 канапе на ржаном хлебе с лососем, сливочным сыром и огурцом"],"ingredients":[["Хлеб ржаной",0.24,"кг"],["Лосось слабосолёный",0.24,"кг"],["Сыр сливочный",0.16,"кг"],["Огурцы",0.084,"кг"],["Укроп",0.01,"кг"],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-02","basis":"На 1 готовый бокс","outputGrams":720,"pieces":16,"rows":[{"productId":"demo-v1-stock-rye","name":"Хлеб ржаной","unit":"кг","gross":0.24,"net":0.24,"unitCost":220},{"productId":"demo-v1-stock-salmon","name":"Лосось слабосолёный","unit":"кг","gross":0.24,"net":0.24,"unitCost":2400},{"productId":"demo-v1-stock-cream","name":"Сыр сливочный","unit":"кг","gross":0.16,"net":0.16,"unitCost":850},{"productId":"demo-v1-stock-cucumber","name":"Огурцы","unit":"кг","gross":0.084,"net":0.072,"unitCost":220},{"productId":"demo-v1-stock-dill","name":"Укроп","unit":"кг","gross":0.01,"net":0.008,"unitCost":700},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Вырезать из ржаного хлеба 16 основ.","Нанести сливочный сыр, добавить ломтики огурца и лосося.","Украсить укропом и уложить в коробку."],"allergens":["Рыба","Молоко","Глютен"],"ingredientCost":855.28,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-chicken-sandwich","name":"Мини-сэндвичи с курицей","price":2400,"category":0,"catalogSection":"Демонстрационные боксы","pieces":12,"weight":"840 г","photo":"demo/images/chicken-sandwich.png","composition":["12 мини-сэндвичей с готовым куриным филе, томатами, салатом и сливочным сыром"],"ingredients":[["Хлеб тостовый",0.36,"кг"],["Филе курицы готовое",0.24,"кг"],["Сыр сливочный",0.12,"кг"],["Томаты",0.092,"кг"],["Салат листовой",0.045,"кг"],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-03","basis":"На 1 готовый бокс","outputGrams":840,"pieces":12,"rows":[{"productId":"demo-v1-stock-toast","name":"Хлеб тостовый","unit":"кг","gross":0.36,"net":0.36,"unitCost":240},{"productId":"demo-v1-stock-chicken","name":"Филе курицы готовое","unit":"кг","gross":0.24,"net":0.24,"unitCost":850},{"productId":"demo-v1-stock-cream","name":"Сыр сливочный","unit":"кг","gross":0.12,"net":0.12,"unitCost":850},{"productId":"demo-v1-stock-tomato","name":"Томаты","unit":"кг","gross":0.092,"net":0.084,"unitCost":260},{"productId":"demo-v1-stock-lettuce","name":"Салат листовой","unit":"кг","gross":0.045,"net":0.036,"unitCost":700},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Нарезать готовое куриное филе, подготовить овощи и салат.","Собрать сэндвичи из тостового хлеба, сыра, курицы и овощей.","Нарезать на 12 одинаковых мини-сэндвичей и упаковать."],"allergens":["Глютен","Молоко"],"ingredientCost":512.82,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-caprese","name":"Канапе «Капрезе»","price":2100,"category":0,"catalogSection":"Демонстрационные боксы","pieces":20,"weight":"700 г","photo":"demo/images/caprese.png","composition":["20 шпажек с моцареллой, черри и базиликом"],"ingredients":[["Моцарелла мини",0.36,"кг"],["Томаты черри",0.308,"кг"],["Базилик",0.022,"кг"],["Масло оливковое",0.04,"кг"],["Шпажка бамбуковая",20,"шт."],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-04","basis":"На 1 готовый бокс","outputGrams":700,"pieces":20,"rows":[{"productId":"demo-v1-stock-mozzarella","name":"Моцарелла мини","unit":"кг","gross":0.36,"net":0.36,"unitCost":950},{"productId":"demo-v1-stock-cherry","name":"Томаты черри","unit":"кг","gross":0.308,"net":0.28,"unitCost":450},{"productId":"demo-v1-stock-basil","name":"Базилик","unit":"кг","gross":0.022,"net":0.02,"unitCost":1500},{"productId":"demo-v1-stock-oil","name":"Масло оливковое","unit":"кг","gross":0.04,"net":0.04,"unitCost":1100},{"productId":"demo-v1-stock-skewer","name":"Шпажка бамбуковая","unit":"шт.","gross":20,"net":20,"unitCost":2},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Подготовить черри и базилик, обсушить моцареллу.","Собрать 20 шпажек, распределив ингредиенты поровну.","Добавить оливковое масло, уложить в коробку."],"allergens":["Молоко"],"ingredientCost":662.6,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-mushroom-tartlet","name":"Тарталетки с грибами и сыром","price":2300,"category":0,"catalogSection":"Демонстрационные боксы","pieces":20,"weight":"800 г","photo":"demo/images/mushroom-tartlet.png","composition":["20 тарталеток с шампиньонами, сливками и сыром"],"ingredients":[["Тарталетки готовые",0.2,"кг"],["Шампиньоны",0.44,"кг"],["Сливки",0.1,"кг"],["Сыр гауда",0.12,"кг"],["Лук репчатый",0.088,"кг"],["Масло оливковое",0.02,"кг"],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-05","basis":"На 1 готовый бокс","outputGrams":800,"pieces":20,"rows":[{"productId":"demo-v1-stock-tartlet","name":"Тарталетки готовые","unit":"кг","gross":0.2,"net":0.2,"unitCost":750},{"productId":"demo-v1-stock-mushroom","name":"Шампиньоны","unit":"кг","gross":0.44,"net":0.3,"unitCost":340},{"productId":"demo-v1-stock-cooking-cream","name":"Сливки","unit":"кг","gross":0.1,"net":0.1,"unitCost":500},{"productId":"demo-v1-stock-gouda","name":"Сыр гауда","unit":"кг","gross":0.12,"net":0.12,"unitCost":900},{"productId":"demo-v1-stock-onion","name":"Лук репчатый","unit":"кг","gross":0.088,"net":0.06,"unitCost":80},{"productId":"demo-v1-stock-oil","name":"Масло оливковое","unit":"кг","gross":0.02,"net":0.02,"unitCost":1100},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Подготовить и обжарить лук с грибами на масле; в расчёте учтены потери массы.","Добавить сливки и распределить начинку по 20 тарталеткам.","Добавить сыр, запечь до расплавления и упаковать после охлаждения."],"allergens":["Глютен","Молоко"],"ingredientCost":551.64,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-turkey-wrap","name":"Роллы из тортильи с индейкой","price":2700,"category":0,"catalogSection":"Демонстрационные боксы","pieces":25,"weight":"1000 г","photo":"demo/images/turkey-wrap.png","composition":["25 мини-роллов с ветчиной из индейки, сливочным сыром, перцем и салатом"],"ingredients":[["Тортилья",0.32,"кг"],["Ветчина из индейки",0.32,"кг"],["Сыр сливочный",0.18,"кг"],["Салат листовой",0.075,"кг"],["Перец сладкий",0.15,"кг"],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-06","basis":"На 1 готовый бокс","outputGrams":1000,"pieces":25,"rows":[{"productId":"demo-v1-stock-tortilla","name":"Тортилья","unit":"кг","gross":0.32,"net":0.32,"unitCost":450},{"productId":"demo-v1-stock-turkey","name":"Ветчина из индейки","unit":"кг","gross":0.32,"net":0.32,"unitCost":1000},{"productId":"demo-v1-stock-cream","name":"Сыр сливочный","unit":"кг","gross":0.18,"net":0.18,"unitCost":850},{"productId":"demo-v1-stock-lettuce","name":"Салат листовой","unit":"кг","gross":0.075,"net":0.06,"unitCost":700},{"productId":"demo-v1-stock-pepper","name":"Перец сладкий","unit":"кг","gross":0.15,"net":0.12,"unitCost":380},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Подготовить салат и перец, нарезать ветчину.","Нанести сыр на тортильи, распределить начинку и свернуть плотные рулеты.","Нарезать на 25 порций и уложить срезом вверх."],"allergens":["Глютен","Молоко"],"ingredientCost":791.5,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-cheese-fruit","name":"Сырный бокс с виноградом и орехами","price":2900,"category":0,"catalogSection":"Демонстрационные боксы","pieces":0,"weight":"800 г","photo":"demo/images/cheese-fruit.png","composition":["Бри, гауда и сыр с голубой плесенью","Виноград, грецкий орех, мёд и крекер"],"ingredients":[["Сыр бри",0.2,"кг"],["Сыр гауда",0.18,"кг"],["Сыр с голубой плесенью",0.12,"кг"],["Виноград",0.176,"кг"],["Орех грецкий очищенный",0.05,"кг"],["Мёд",0.04,"кг"],["Крекер",0.05,"кг"],["Соусник",1,"шт."],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-07","basis":"На 1 готовый бокс","outputGrams":800,"pieces":0,"rows":[{"productId":"demo-v1-stock-brie","name":"Сыр бри","unit":"кг","gross":0.2,"net":0.2,"unitCost":1600},{"productId":"demo-v1-stock-gouda","name":"Сыр гауда","unit":"кг","gross":0.18,"net":0.18,"unitCost":900},{"productId":"demo-v1-stock-blue","name":"Сыр с голубой плесенью","unit":"кг","gross":0.12,"net":0.12,"unitCost":1700},{"productId":"demo-v1-stock-grape","name":"Виноград","unit":"кг","gross":0.176,"net":0.16,"unitCost":420},{"productId":"demo-v1-stock-walnut","name":"Орех грецкий очищенный","unit":"кг","gross":0.05,"net":0.05,"unitCost":1000},{"productId":"demo-v1-stock-honey","name":"Мёд","unit":"кг","gross":0.04,"net":0.04,"unitCost":800},{"productId":"demo-v1-stock-cracker","name":"Крекер","unit":"кг","gross":0.05,"net":0.05,"unitCost":500},{"productId":"demo-v1-stock-sauce-cup","name":"Соусник","unit":"шт.","gross":1,"net":1,"unitCost":7},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Нарезать сыры порционными кусочками.","Подготовить виноград, переложить мёд в соусник.","Разложить сыры, виноград, орехи и крекер отдельными секциями."],"allergens":["Молоко","Орехи","Глютен"],"ingredientCost":938.92,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-meat-assortment","name":"Мясное ассорти с корнишонами","price":3200,"category":0,"catalogSection":"Демонстрационные боксы","pieces":0,"weight":"700 г","photo":"demo/images/meat-assortment.png","composition":["Салями, готовый ростбиф и ветчина из индейки","Корнишоны, маслины и горчица"],"ingredients":[["Салями",0.18,"кг"],["Ростбиф готовый",0.22,"кг"],["Ветчина из индейки",0.15,"кг"],["Корнишоны",0.09,"кг"],["Маслины без косточек",0.045,"кг"],["Горчица",0.03,"кг"],["Соусник",1,"шт."],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-08","basis":"На 1 готовый бокс","outputGrams":700,"pieces":0,"rows":[{"productId":"demo-v1-stock-salami","name":"Салями","unit":"кг","gross":0.18,"net":0.18,"unitCost":1400},{"productId":"demo-v1-stock-beef","name":"Ростбиф готовый","unit":"кг","gross":0.22,"net":0.22,"unitCost":2000},{"productId":"demo-v1-stock-turkey","name":"Ветчина из индейки","unit":"кг","gross":0.15,"net":0.15,"unitCost":1000},{"productId":"demo-v1-stock-pickle","name":"Корнишоны","unit":"кг","gross":0.09,"net":0.08,"unitCost":400},{"productId":"demo-v1-stock-olive","name":"Маслины без косточек","unit":"кг","gross":0.045,"net":0.04,"unitCost":650},{"productId":"demo-v1-stock-mustard","name":"Горчица","unit":"кг","gross":0.03,"net":0.03,"unitCost":350},{"productId":"demo-v1-stock-sauce-cup","name":"Соусник","unit":"шт.","gross":1,"net":1,"unitCost":7},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Нарезать готовые мясные продукты тонкими ломтиками.","Обсушить корнишоны и маслины, переложить горчицу в соусник.","Разложить ассорти секциями, добавить гарниры."],"allergens":["Горчица"],"ingredientCost":989.75,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-vegetables-hummus","name":"Овощной бокс с хумусом","price":2100,"category":0,"catalogSection":"Демонстрационные боксы","pieces":0,"weight":"1000 г","photo":"demo/images/vegetables-hummus.png","composition":["Морковь, огурцы, сладкий перец и черри","Хумус в отдельном соуснике"],"ingredients":[["Морковь",0.3,"кг"],["Огурцы",0.275,"кг"],["Перец сладкий",0.25,"кг"],["Томаты черри",0.165,"кг"],["Хумус готовый",0.15,"кг"],["Соусник",1,"шт."],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-09","basis":"На 1 готовый бокс","outputGrams":1000,"pieces":0,"rows":[{"productId":"demo-v1-stock-carrot","name":"Морковь","unit":"кг","gross":0.3,"net":0.25,"unitCost":90},{"productId":"demo-v1-stock-cucumber","name":"Огурцы","unit":"кг","gross":0.275,"net":0.25,"unitCost":220},{"productId":"demo-v1-stock-pepper","name":"Перец сладкий","unit":"кг","gross":0.25,"net":0.2,"unitCost":380},{"productId":"demo-v1-stock-cherry","name":"Томаты черри","unit":"кг","gross":0.165,"net":0.15,"unitCost":450},{"productId":"demo-v1-stock-hummus","name":"Хумус готовый","unit":"кг","gross":0.15,"net":0.15,"unitCost":600},{"productId":"demo-v1-stock-sauce-cup","name":"Соусник","unit":"шт.","gross":1,"net":1,"unitCost":7},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Вымыть и подготовить овощи; очистить морковь и перец.","Нарезать овощи палочками, черри оставить целыми.","Переложить хумус в соусник и разложить овощи вокруг него."],"allergens":["Кунжут в составе хумуса"],"ingredientCost":418.75,"note":"Учебные нормы и цены для знакомства с приложением."}},{"id":"demo-v1-berry-dessert","name":"Ягодные мини-десерты","price":2800,"category":0,"catalogSection":"Демонстрационные боксы","pieces":16,"weight":"960 г","photo":"demo/images/berry-dessert.png","composition":["16 десертов со сливочным кремом, бисквитом, клубникой и голубикой"],"ingredients":[["Крошка бисквитная",0.16,"кг"],["Сыр сливочный",0.32,"кг"],["Сливки",0.16,"кг"],["Клубника",0.176,"кг"],["Голубика",0.084,"кг"],["Пудра сахарная",0.08,"кг"],["Стаканчик десертный",16,"шт."],["Коробка для кейтеринга",1,"шт."]],"demo":true,"ttk":{"number":"ДЕМО-10","basis":"На 1 готовый бокс","outputGrams":960,"pieces":16,"rows":[{"productId":"demo-v1-stock-biscuit","name":"Крошка бисквитная","unit":"кг","gross":0.16,"net":0.16,"unitCost":500},{"productId":"demo-v1-stock-cream","name":"Сыр сливочный","unit":"кг","gross":0.32,"net":0.32,"unitCost":850},{"productId":"demo-v1-stock-cooking-cream","name":"Сливки","unit":"кг","gross":0.16,"net":0.16,"unitCost":500},{"productId":"demo-v1-stock-strawberry","name":"Клубника","unit":"кг","gross":0.176,"net":0.16,"unitCost":750},{"productId":"demo-v1-stock-blueberry","name":"Голубика","unit":"кг","gross":0.084,"net":0.08,"unitCost":1300},{"productId":"demo-v1-stock-sugar","name":"Пудра сахарная","unit":"кг","gross":0.08,"net":0.08,"unitCost":160},{"productId":"demo-v1-stock-cup","name":"Стаканчик десертный","unit":"шт.","gross":16,"net":16,"unitCost":9},{"productId":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","gross":1,"net":1,"unitCost":65}],"steps":["Подготовить ягоды, разделить готовый бисквит на крошку.","Смешать сливочный сыр, сливки и сахарную пудру в крем.","Собрать 16 стаканчиков слоями: бисквит, крем, ягоды."],"allergens":["Молоко","Глютен","Яйцо в составе бисквита"],"ingredientCost":895,"note":"Учебные нормы и цены для знакомства с приложением."}}],"stock":[{"id":"demo-v1-stock-baguette","name":"Багет","unit":"кг","cost":240,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-tomato","name":"Томаты","unit":"кг","cost":260,"qty":0.19,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-basil","name":"Базилик","unit":"кг","cost":1500,"qty":0.096,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-oil","name":"Масло оливковое","unit":"кг","cost":1100,"qty":0.067,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-rye","name":"Хлеб ржаной","unit":"кг","cost":220,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-salmon","name":"Лосось слабосолёный","unit":"кг","cost":2400,"qty":0.108,"min":0.1,"supplierId":"demo-v1-supplier-protein","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-cream","name":"Сыр сливочный","unit":"кг","cost":850,"qty":1.56,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-cucumber","name":"Огурцы","unit":"кг","cost":220,"qty":0.251,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-dill","name":"Укроп","unit":"кг","cost":700,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-toast","name":"Хлеб тостовый","unit":"кг","cost":240,"qty":0.162,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-chicken","name":"Филе курицы готовое","unit":"кг","cost":850,"qty":0.48,"min":0.1,"supplierId":"demo-v1-supplier-protein","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-lettuce","name":"Салат листовой","unit":"кг","cost":700,"qty":0.084,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-mozzarella","name":"Моцарелла мини","unit":"кг","cost":950,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-cherry","name":"Томаты черри","unit":"кг","cost":450,"qty":0.213,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-tartlet","name":"Тарталетки готовые","unit":"кг","cost":750,"qty":0.4,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-mushroom","name":"Шампиньоны","unit":"кг","cost":340,"qty":0.308,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-cooking-cream","name":"Сливки","unit":"кг","cost":500,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-gouda","name":"Сыр гауда","unit":"кг","cost":900,"qty":0.135,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-onion","name":"Лук репчатый","unit":"кг","cost":80,"qty":0.176,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-tortilla","name":"Тортилья","unit":"кг","cost":450,"qty":0.224,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-turkey","name":"Ветчина из индейки","unit":"кг","cost":1000,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-protein","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-pepper","name":"Перец сладкий","unit":"кг","cost":380,"qty":0.18,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-brie","name":"Сыр бри","unit":"кг","cost":1600,"qty":0.4,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-blue","name":"Сыр с голубой плесенью","unit":"кг","cost":1700,"qty":0.084,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-grape","name":"Виноград","unit":"кг","cost":420,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-walnut","name":"Орех грецкий очищенный","unit":"кг","cost":1000,"qty":0.023,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-honey","name":"Мёд","unit":"кг","cost":800,"qty":0.08,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-cracker","name":"Крекер","unit":"кг","cost":500,"qty":0.035,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-salami","name":"Салями","unit":"кг","cost":1400,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-protein","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-beef","name":"Ростбиф готовый","unit":"кг","cost":2000,"qty":0.099,"min":0.1,"supplierId":"demo-v1-supplier-protein","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-pickle","name":"Корнишоны","unit":"кг","cost":400,"qty":0.18,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-olive","name":"Маслины без косточек","unit":"кг","cost":650,"qty":0.032,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-mustard","name":"Горчица","unit":"кг","cost":350,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-carrot","name":"Морковь","unit":"кг","cost":90,"qty":0.135,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-hummus","name":"Хумус готовый","unit":"кг","cost":600,"qty":0.3,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-biscuit","name":"Крошка бисквитная","unit":"кг","cost":500,"qty":0.112,"min":0.1,"supplierId":"demo-v1-supplier-bakery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-strawberry","name":"Клубника","unit":"кг","cost":750,"qty":0,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-blueberry","name":"Голубика","unit":"кг","cost":1300,"qty":0.038,"min":0.1,"supplierId":"demo-v1-supplier-fresh","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-sugar","name":"Пудра сахарная","unit":"кг","cost":160,"qty":0.16,"min":0.1,"supplierId":"demo-v1-supplier-grocery","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-box","name":"Коробка для кейтеринга","unit":"шт.","cost":65,"qty":7,"min":2,"supplierId":"demo-v1-supplier-pack","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-skewer","name":"Шпажка бамбуковая","unit":"шт.","cost":2,"qty":0,"min":2,"supplierId":"demo-v1-supplier-pack","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-cup","name":"Стаканчик десертный","unit":"шт.","cost":9,"qty":7,"min":2,"supplierId":"demo-v1-supplier-pack","lastPurchaseDate":"","lastPurchasePrice":0},{"id":"demo-v1-stock-sauce-cup","name":"Соусник","unit":"шт.","cost":7,"qty":6,"min":2,"supplierId":"demo-v1-supplier-pack","lastPurchaseDate":"","lastPurchasePrice":0}],"suppliers":[{"id":"demo-v1-supplier-fresh","name":"Демо: овощи и молочные продукты","active":true,"category":"Учебный поставщик","contact":"","phone":"","email":"","address":"","deliveryDays":"По договорённости","minOrder":0,"note":"Вымышленный поставщик для знакомства с приложением."},{"id":"demo-v1-supplier-protein","name":"Демо: мясо и рыба","active":true,"category":"Учебный поставщик","contact":"","phone":"","email":"","address":"","deliveryDays":"По договорённости","minOrder":0,"note":"Вымышленный поставщик для знакомства с приложением."},{"id":"demo-v1-supplier-bakery","name":"Демо: пекарня","active":true,"category":"Учебный поставщик","contact":"","phone":"","email":"","address":"","deliveryDays":"По договорённости","minOrder":0,"note":"Вымышленный поставщик для знакомства с приложением."},{"id":"demo-v1-supplier-grocery","name":"Демо: бакалея","active":true,"category":"Учебный поставщик","contact":"","phone":"","email":"","address":"","deliveryDays":"По договорённости","minOrder":0,"note":"Вымышленный поставщик для знакомства с приложением."},{"id":"demo-v1-supplier-pack","name":"Демо: упаковка","active":true,"category":"Учебный поставщик","contact":"","phone":"","email":"","address":"","deliveryDays":"По договорённости","minOrder":0,"note":"Вымышленный поставщик для знакомства с приложением."}],"scenario":{"lines":[{"id":"demo-v1-bruschetta-tomato","qty":2},{"id":"demo-v1-salmon-cream","qty":1},{"id":"demo-v1-caprese","qty":1}]}}$demo$::jsonb $fn$; revoke all on function public.caterium_trial_demo_seed_v1() from public,anon,authenticated; create or replace function public.caterium_trial_demo_status(p_workspace uuid) returns jsonb language plpgsql stable security definer set search_path=public,pg_temp as $fn$ declare v_storage jsonb; v_empty boolean:=true; v_key text; v_value jsonb; v_allowed boolean; v_installed boolean; begin if auth.uid() is null or public.sun_member_role(p_workspace) is null then raise exception 'Access denied'; end if; select coalesce(payload->'storage','{}'::jsonb) into v_storage from public.sun_app_state where workspace_id=p_workspace; v_installed:=coalesce(v_storage#>>'{sunTrialDemoV1,v,version}','')='1'; foreach v_key in array array['sunBoxes','sunStock','sunSuppliers','sunStockMoves'] loop v_value:=v_storage#>array[v_key,'v']; if v_value is not null and v_value<>'[]'::jsonb then v_empty:=false; end if; if v_storage ? v_key and (jsonb_typeof(v_storage->v_key)<>'object' or v_value is null) then v_empty:=false; end if; end loop; v_allowed:=public.sun_member_role(p_workspace)='admin' and public.sun_subscription_access_mode(p_workspace)='full' and (exists(select 1 from public.sun_workspace_subscriptions where workspace_id=p_workspace and status='trialing') or public.sun_is_platform_admin()) and public.sun_workspace_has_feature(p_workspace,'catalog_edit') and public.sun_workspace_has_feature(p_workspace,'stock') and public.sun_workspace_has_feature(p_workspace,'suppliers') and not exists(select 1 from public.sun_workspace_members m join public.caterium_sidebar_brand_assignment a on a.user_id=m.user_id where m.workspace_id=p_workspace); return jsonb_build_object('eligible',coalesce(v_allowed,false),'installed',v_installed,'empty',v_empty,'canInstall',coalesce(v_allowed,false) and v_empty and not v_installed); end $fn$; revoke all on function public.caterium_trial_demo_status(uuid) from public,anon; grant execute on function public.caterium_trial_demo_status(uuid) to authenticated; create or replace function public.caterium_install_trial_demo(p_workspace uuid) returns jsonb language plpgsql security definer set search_path=public,pg_temp as $fn$ declare v_state public.sun_app_state%rowtype; v_status jsonb; v_seed jsonb; v_storage jsonb; v_moves jsonb; v_marker jsonb; begin if auth.uid() is null or public.sun_member_role(p_workspace) is distinct from 'admin' then raise exception 'Administrator membership required'; end if; perform 1 from public.sun_workspaces where id=p_workspace for update; v_status:=public.caterium_trial_demo_status(p_workspace); if not (v_status->>'eligible')::boolean then raise exception 'Демонстрационная база доступна в пробной или собственной тестовой компании разработчика'; end if; if (v_status->>'installed')::boolean then return v_status; end if; if not (v_status->>'empty')::boolean then raise exception 'Каталог, склад или поставщики уже заполнены. Данные сохранены без изменений'; end if; select * into v_state from public.sun_app_state where workspace_id=p_workspace for update; if not found then raise exception 'Рабочая база не найдена'; end if; v_seed:=public.caterium_trial_demo_seed_v1(); select coalesce(jsonb_agg(jsonb_build_object('id','demo-v1-opening-'||(p->>'id'),'productId',p->>'id','productName',p->>'name','unit',p->>'unit', 'type','set','qty',p->'qty','setTo',p->'qty','cost',p->'cost','date',current_date::text,'createdAt',now(), 'supplierId',p->>'supplierId','note','Учебный начальный остаток')),'[]'::jsonb) into v_moves from jsonb_array_elements(v_seed->'stock') p where (p->>'qty')::numeric>0; v_marker:=jsonb_build_object('version',1,'batch','trial-demo-v1','installedAt',now(),'scenario',v_seed->'scenario'); v_storage:=coalesce(v_state.payload->'storage','{}'::jsonb)||jsonb_build_object( 'sunBoxes',jsonb_build_object('t','j','v',v_seed->'boxes'), 'sunStock',jsonb_build_object('t','j','v',v_seed->'stock'), 'sunSuppliers',jsonb_build_object('t','j','v',v_seed->'suppliers'), 'sunStockMoves',jsonb_build_object('t','j','v',v_moves), 'sunTrialDemoV1',jsonb_build_object('t','j','v',v_marker)); perform public.sun_save_app_state_v17(p_workspace,jsonb_set(v_state.payload,'{storage}',v_storage),'trial-demo-v1',v_state.revision); insert into public.sun_platform_audit_events(actor_user_id,action,target_workspace_id,details) values(auth.uid(),'trial_demo.install',p_workspace,jsonb_build_object('version',1,'boxes',10)); return public.caterium_trial_demo_status(p_workspace); end $fn$; revoke all on function public.caterium_install_trial_demo(uuid) from public,anon; grant execute on function public.caterium_install_trial_demo(uuid) to authenticated; create or replace function public.caterium_seed_new_trial() returns trigger language plpgsql security definer set search_path=public,pg_temp as $fn$ begin if coalesce((public.caterium_trial_demo_status(new.workspace_id)->>'canInstall')::boolean,false) then perform public.caterium_install_trial_demo(new.workspace_id); end if; return new; end $fn$; revoke all on function public.caterium_seed_new_trial() from public,anon,authenticated; drop trigger if exists caterium_seed_new_trial on public.caterium_trial_redemptions; create trigger caterium_seed_new_trial after insert on public.caterium_trial_redemptions for each row execute function public.caterium_seed_new_trial(); notify pgrst,'reload schema'; commit;