import { PrismaClient } from '@prisma/client'; import bcrypt from 'bcryptjs'; const prisma = new PrismaClient(); async function main() { console.log('🌱 Seeding database...'); // ─── Categories ────────────────────────────────────── const categories = await Promise.all([ prisma.category.upsert({ where: { title: 'Закуски' }, update: {}, create: { title: 'Закуски' } }), prisma.category.upsert({ where: { title: 'Салаты' }, update: {}, create: { title: 'Салаты' } }), prisma.category.upsert({ where: { title: 'Супы' }, update: {}, create: { title: 'Супы' } }), prisma.category.upsert({ where: { title: 'Горячее' }, update: {}, create: { title: 'Горячее' } }), prisma.category.upsert({ where: { title: 'Бургеры' }, update: {}, create: { title: 'Бургеры' } }), prisma.category.upsert({ where: { title: 'Пицца' }, update: {}, create: { title: 'Пицца' } }), prisma.category.upsert({ where: { title: 'Десерты' }, update: {}, create: { title: 'Десерты' } }), prisma.category.upsert({ where: { title: 'Пиво' }, update: {}, create: { title: 'Пиво' } }), prisma.category.upsert({ where: { title: 'Коктейли' }, update: {}, create: { title: 'Коктейли' } }), prisma.category.upsert({ where: { title: 'Безалкогольные' }, update: {}, create: { title: 'Безалкогольные' } }), prisma.category.upsert({ where: { title: 'Бизнес-ланч' }, update: {}, create: { title: 'Бизнес-ланч' } }), ]); const [snacks, salads, soups, main, burgers, pizza, desserts, beer, cocktails, soft, lunch] = categories; // ─── Pubs ──────────────────────────────────────────── const pub1 = await prisma.pub.upsert({ where: { address: 'пр. Мира, 7А, Красноярск' }, update: {}, create: { name: "Harat's Irish Pub Красноярск", address: 'пр. Мира, 7А, Красноярск', phone: '+7 (391) 227-78-18', }, }); const pub2 = await prisma.pub.upsert({ where: { address: 'ул. Красной Гвардии, 24, Красноярск' }, update: {}, create: { name: "Harat's Irish Pub Красноярск", address: 'ул. Красной Гвардии, 24, Красноярск', phone: '+7 (391) 214-68-17', }, }); const pub3 = await prisma.pub.upsert({ where: { address: 'Влетная ул., 6А, Красноярск' }, update: {}, create: { name: "Harat's Irish Pub Санкт-Петербург", address: 'Влетная ул., 6А, Красноярск', phone: '+7 (391) 271-77-54', }, }); const pub4 = await prisma.pub.upsert({ where: { address: 'пр. Мира, 81, Красноярск' }, update: {}, create: { name: "Harat's Irish Pub Красноярск", address: 'пр. Мира, 81, Красноярск', phone: '+7 (391) 223-22-22', }, }); const pub5 = await prisma.pub.upsert({ where: { address: 'ул. Перенсона, 26, Красноярск' }, update: {}, create: { name: "Harat's Irish Pub Красноярск", address: 'ул. Перенсона, 26, Красноярск', phone: '+7 (391) 214-07-99', }, }); // ─── Tables for Pub 1 (main pub with full layout) ─── const tablesData = [ // Main hall { pubId: pub1.id, number: 1, capacity: 2, posX: 80, posY: 100, width: 55, height: 55, shape: 'rect', zone: 'main' }, { pubId: pub1.id, number: 2, capacity: 2, posX: 180, posY: 100, width: 55, height: 55, shape: 'rect', zone: 'main' }, { pubId: pub1.id, number: 3, capacity: 4, posX: 280, posY: 100, width: 70, height: 55, shape: 'rect', zone: 'main' }, { pubId: pub1.id, number: 4, capacity: 4, posX: 400, posY: 100, width: 70, height: 55, shape: 'rect', zone: 'main' }, { pubId: pub1.id, number: 5, capacity: 6, posX: 80, posY: 220, width: 90, height: 60, shape: 'rect', zone: 'main' }, { pubId: pub1.id, number: 6, capacity: 6, posX: 230, posY: 220, width: 90, height: 60, shape: 'rect', zone: 'main' }, { pubId: pub1.id, number: 7, capacity: 4, posX: 380, posY: 220, width: 70, height: 55, shape: 'rect', zone: 'main' }, // Bar zone { pubId: pub1.id, number: 8, capacity: 2, posX: 560, posY: 80, width: 50, height: 50, shape: 'circle', zone: 'bar' }, { pubId: pub1.id, number: 9, capacity: 2, posX: 560, posY: 160, width: 50, height: 50, shape: 'circle', zone: 'bar' }, { pubId: pub1.id, number: 10, capacity: 2, posX: 560, posY: 240, width: 50, height: 50, shape: 'circle', zone: 'bar' }, // VIP { pubId: pub1.id, number: 11, capacity: 8, posX: 80, posY: 360, width: 120, height: 70, shape: 'rect', zone: 'vip' }, { pubId: pub1.id, number: 12, capacity: 8, posX: 260, posY: 360, width: 120, height: 70, shape: 'rect', zone: 'vip' }, // Terrace { pubId: pub1.id, number: 13, capacity: 4, posX: 460, posY: 360, width: 65, height: 55, shape: 'rect', zone: 'terrace' }, { pubId: pub1.id, number: 14, capacity: 4, posX: 560, posY: 360, width: 65, height: 55, shape: 'rect', zone: 'terrace' }, ]; for (const t of tablesData) { await prisma.table.upsert({ where: { pubId_number: { pubId: t.pubId, number: t.number } }, update: {}, create: t, }); } // Simple tables for pub2, pub3, and pub4 for (const pub of [pub2, pub3, pub4, pub5]) { for (let i = 1; i <= 8; i++) { await prisma.table.upsert({ where: { pubId_number: { pubId: pub.id, number: i } }, update: {}, create: { pubId: pub.id, number: i, capacity: i <= 4 ? 2 : 4, posX: 80 + ((i - 1) % 4) * 140, posY: 100 + Math.floor((i - 1) / 4) * 140, width: i <= 4 ? 55 : 70, height: 55, shape: i <= 4 ? 'circle' : 'rect', zone: 'main', }, }); } } // ─── Dishes ────────────────────────────────────────── const dishesData = [ // Snacks { title: 'Ирландские колбаски', categoryId: snacks.id, grams: 250, price: 490, description: 'Ассорти из трёх видов домашних колбасок с горчичным соусом' }, { title: 'Начос с соусами', categoryId: snacks.id, grams: 300, price: 420, description: 'Кукурузные чипсы с гуакамоле, сальсой и сырным соусом' }, { title: 'Луковые кольца', categoryId: snacks.id, grams: 200, price: 350, description: 'Хрустящие луковые кольца в пивном кляре' }, { title: 'Куриные крылья BBQ', categoryId: snacks.id, grams: 350, price: 520, description: 'Крылышки в фирменном соусе BBQ с сельдереем' }, { title: 'Картофель фри', categoryId: snacks.id, grams: 250, price: 280, description: 'Золотистый картофель фри с паприкой' }, { title: 'Сырные палочки', categoryId: snacks.id, grams: 200, price: 390, description: 'Моцарелла в панировке с томатным соусом' }, // Salads { title: 'Цезарь с курицей', categoryId: salads.id, grams: 280, price: 450, description: 'Классический салат с куриной грудкой, пармезаном и гренками' }, { title: 'Греческий', categoryId: salads.id, grams: 260, price: 380, description: 'Свежие овощи с фетой и оливковым маслом' }, { title: 'Коул-слоу', categoryId: salads.id, grams: 200, price: 250, description: 'Капустный салат с морковью в сливочной заправке' }, // Soups { title: 'Ирландское рагу', categoryId: soups.id, grams: 350, price: 420, description: 'Традиционное рагу из баранины с картофелем и овощами' }, { title: 'Крем-суп из шампиньонов', categoryId: soups.id, grams: 300, price: 350, description: 'Нежный крем-суп с гренками и трюфельным маслом' }, { title: 'Томатный суп', categoryId: soups.id, grams: 300, price: 320, description: 'Густой томатный суп с базиликом' }, // Main { title: 'Стейк Рибай', categoryId: main.id, grams: 300, price: 1490, description: 'Стейк рибай medium rare с овощами гриль' }, { title: 'Fish & Chips', categoryId: main.id, grams: 350, price: 590, description: 'Треска в пивном кляре с картофелем фри и соусом тартар' }, { title: 'Shepherd\'s Pie', categoryId: main.id, grams: 400, price: 520, description: 'Пастуший пирог с бараниной и картофельным пюре' }, { title: 'Свиная рулька', categoryId: main.id, grams: 500, price: 890, description: 'Томлёная свиная рулька с квашеной капустой' }, // Burgers { title: 'Classic Burger', categoryId: burgers.id, grams: 350, price: 550, description: 'Говяжья котлета, чеддер, томат, салат, фирменный соус' }, { title: 'Irish Burger', categoryId: burgers.id, grams: 400, price: 650, description: 'Двойная котлета, бекон, яйцо, жареный лук, BBQ соус' }, { title: 'Chicken Burger', categoryId: burgers.id, grams: 330, price: 490, description: 'Куриная котлета, авокадо, руккола, медово-горчичный соус' }, // Pizza { title: 'Маргарита', categoryId: pizza.id, grams: 450, price: 490, description: 'Томатный соус, моцарелла, базилик' }, { title: 'Пепперони', categoryId: pizza.id, grams: 480, price: 590, description: 'Томатный соус, моцарелла, пепперони' }, { title: 'Четыре сыра', categoryId: pizza.id, grams: 460, price: 620, description: 'Моцарелла, горгонзола, пармезан, дор блю' }, // Desserts { title: 'Чизкейк', categoryId: desserts.id, grams: 180, price: 350, description: 'Классический нью-йоркский чизкейк' }, { title: 'Брауни', categoryId: desserts.id, grams: 150, price: 320, description: 'Шоколадный брауни с ванильным мороженым' }, { title: 'Apple Crumble', categoryId: desserts.id, grams: 200, price: 380, description: 'Тёплый яблочный крамбл с корицей и мороженым' }, // Beer { title: 'Guinness (0.5)', categoryId: beer.id, grams: 500, price: 450, description: 'Ирландский тёмный стаут' }, { title: 'Kilkenny (0.5)', categoryId: beer.id, grams: 500, price: 420, description: 'Ирландский красный эль' }, { title: 'Harp Lager (0.5)', categoryId: beer.id, grams: 500, price: 380, description: 'Ирландский лагер' }, { title: 'Крафт IPA (0.4)', categoryId: beer.id, grams: 400, price: 390, description: 'Крафтовый индийский пэйл эль' }, // Cocktails { title: 'Irish Coffee', categoryId: cocktails.id, grams: 250, price: 450, description: 'Кофе, ирландский виски, сливки' }, { title: 'Whiskey Sour', categoryId: cocktails.id, grams: 200, price: 520, description: 'Виски, лимонный сок, сахарный сироп, яичный белок' }, { title: 'Mojito', categoryId: cocktails.id, grams: 300, price: 480, description: 'Ром, лайм, мята, содовая, сахар' }, { title: 'Long Island', categoryId: cocktails.id, grams: 350, price: 590, description: 'Водка, ром, текила, джин, трипл сек, кола' }, // Soft drinks { title: 'Лимонад домашний', categoryId: soft.id, grams: 400, price: 250, description: 'Свежевыжатый лимонад с мятой' }, { title: 'Морс клюквенный', categoryId: soft.id, grams: 400, price: 220, description: 'Домашний морс из свежей клюквы' }, { title: 'Сок апельсиновый', categoryId: soft.id, grams: 300, price: 280, description: 'Свежевыжатый апельсиновый сок' }, // Lunch { title: 'Ланч: Борщ + хлеб', categoryId: lunch.id, grams: 350, price: 220, description: 'Домашний борщ с пампушкой' }, { title: 'Ланч: Котлета с пюре', categoryId: lunch.id, grams: 300, price: 280, description: 'Куриная котлета с картофельным пюре и подливой' }, { title: 'Ланч: Паста болоньезе', categoryId: lunch.id, grams: 300, price: 260, description: 'Спагетти с мясным соусом болоньезе' }, { title: 'Ланч: Комплекс (суп + горячее + напиток)', categoryId: lunch.id, grams: null, price: 390, description: 'Суп дня, горячее дня, компот' }, ]; const createdDishes: any[] = []; for (const d of dishesData) { const dish = await prisma.dish.upsert({ where: { id: createdDishes.length + 1 }, update: {}, create: d, }); createdDishes.push(dish); } // ─── Menu (link dishes to pubs, except lunch category) ── for (const pub of [pub1, pub2, pub3, pub4, pub5]) { for (const dish of createdDishes) { if (dish.categoryId === lunch.id) continue; // lunch is separate await prisma.menu.upsert({ where: { pubId_dishId: { pubId: pub.id, dishId: dish.id } }, update: {}, create: { pubId: pub.id, dishId: dish.id }, }); } } // ─── Lunch Menu (current week) ───────────────────── const now = new Date(); const monday = new Date(now); monday.setDate(now.getDate() - ((now.getDay() + 6) % 7)); monday.setHours(0, 0, 0, 0); const sunday = new Date(monday); sunday.setDate(monday.getDate() + 6); const lunchDishes = createdDishes.filter(d => d.categoryId === lunch.id); for (const pub of [pub1, pub2, pub3, pub4, pub5]) { for (const dish of lunchDishes) { await prisma.lunchMenu.upsert({ where: { pubId_dishId_weekStart: { pubId: pub.id, dishId: dish.id, weekStart: monday } }, update: {}, create: { pubId: pub.id, dishId: dish.id, weekStart: monday, weekEnd: sunday, }, }); } } // ─── Billboard ───────────────────────────────────── const billboards = [ { title: 'Live Rock Night', artist: 'The Wild Rovers', pubId: pub1.id, datetime: new Date('2026-04-12T20:00:00'), poster: null }, { title: 'Jazz Friday', artist: 'Smooth Quartet', pubId: pub1.id, datetime: new Date('2026-04-11T19:30:00'), poster: null }, { title: 'Irish Folk Evening', artist: 'Celtic Storm', pubId: pub1.id, datetime: new Date('2026-04-13T18:00:00'), poster: null }, { title: 'Stand-Up Comedy', artist: 'Андрей Бебуришвили', pubId: pub2.id, datetime: new Date('2026-04-12T19:00:00'), poster: null }, { title: 'Karaoke Night', artist: 'DJ Shamrock', pubId: pub2.id, datetime: new Date('2026-04-10T21:00:00'), poster: null }, { title: 'Acoustic Session', artist: 'Indie Folk Band', pubId: pub3.id, datetime: new Date('2026-04-11T20:00:00'), poster: null }, ]; for (const b of billboards) { await prisma.billboard.create({ data: b }); } // ─── Admin User ──────────────────────────────────── const hashedPassword = await bcrypt.hash('admin123', 12); await prisma.user.upsert({ where: { phone: '+79001234567' }, update: {}, create: { phone: '+79001234567', password: hashedPassword, name: 'Администратор', role: 'ADMIN', email: 'admin@harats.com', }, }); // Demo user const userPassword = await bcrypt.hash('user123', 12); await prisma.user.upsert({ where: { phone: '+79009876543' }, update: {}, create: { phone: '+79009876543', password: userPassword, name: 'Иван', surname: 'Петров', role: 'USER', email: 'ivan@example.com', }, }); console.log('✅ Seed complete!'); } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });