Initial commit: Harat's Booking monorepo with deploy setup
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Role" AS ENUM ('USER', 'ADMIN');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ReservationStatus" AS ENUM ('PENDING', 'CONFIRMED', 'CANCELLED', 'COMPLETED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "DishAvailability" AS ENUM ('AVAILABLE', 'STOPPED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"phone" VARCHAR(20) NOT NULL,
|
||||
"password" VARCHAR(255) NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
"surname" VARCHAR(100),
|
||||
"email" VARCHAR(255),
|
||||
"role" "Role" NOT NULL DEFAULT 'USER',
|
||||
"cardToken" VARCHAR(255),
|
||||
"cardLastFour" VARCHAR(4),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Pub" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"address" VARCHAR(255) NOT NULL,
|
||||
"phone" VARCHAR(20) NOT NULL,
|
||||
"name" VARCHAR(100) NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Pub_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Table" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"pubId" INTEGER NOT NULL,
|
||||
"number" INTEGER NOT NULL,
|
||||
"capacity" INTEGER NOT NULL,
|
||||
"posX" DOUBLE PRECISION NOT NULL,
|
||||
"posY" DOUBLE PRECISION NOT NULL,
|
||||
"width" DOUBLE PRECISION NOT NULL DEFAULT 60,
|
||||
"height" DOUBLE PRECISION NOT NULL DEFAULT 60,
|
||||
"shape" VARCHAR(20) NOT NULL DEFAULT 'rect',
|
||||
"zone" VARCHAR(50),
|
||||
|
||||
CONSTRAINT "Table_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Category" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"title" VARCHAR(100) NOT NULL,
|
||||
|
||||
CONSTRAINT "Category_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Dish" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"title" VARCHAR(100) NOT NULL,
|
||||
"description" TEXT,
|
||||
"categoryId" INTEGER NOT NULL,
|
||||
"grams" INTEGER,
|
||||
"price" DECIMAL(10,2) NOT NULL,
|
||||
"photo" VARCHAR(255),
|
||||
"availability" "DishAvailability" NOT NULL DEFAULT 'AVAILABLE',
|
||||
|
||||
CONSTRAINT "Dish_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Menu" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"pubId" INTEGER NOT NULL,
|
||||
"dishId" INTEGER NOT NULL,
|
||||
|
||||
CONSTRAINT "Menu_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LunchMenu" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"pubId" INTEGER NOT NULL,
|
||||
"dishId" INTEGER NOT NULL,
|
||||
"weekStart" DATE NOT NULL,
|
||||
"weekEnd" DATE NOT NULL,
|
||||
|
||||
CONSTRAINT "LunchMenu_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Billboard" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"title" VARCHAR(200) NOT NULL,
|
||||
"artist" VARCHAR(100) NOT NULL,
|
||||
"pubId" INTEGER NOT NULL,
|
||||
"datetime" TIMESTAMP(3) NOT NULL,
|
||||
"poster" VARCHAR(255),
|
||||
|
||||
CONSTRAINT "Billboard_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Reservation" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"userId" INTEGER NOT NULL,
|
||||
"pubId" INTEGER NOT NULL,
|
||||
"tableId" INTEGER NOT NULL,
|
||||
"date" DATE NOT NULL,
|
||||
"time" TIME NOT NULL,
|
||||
"numPeople" INTEGER NOT NULL,
|
||||
"status" "ReservationStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"totalCost" DECIMAL(10,2),
|
||||
"prepaid" DECIMAL(10,2),
|
||||
"paymentId" VARCHAR(255),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Reservation_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ReservationDish" (
|
||||
"id" SERIAL NOT NULL,
|
||||
"reservationId" INTEGER NOT NULL,
|
||||
"dishId" INTEGER NOT NULL,
|
||||
"quantity" INTEGER NOT NULL DEFAULT 1,
|
||||
"priceAtOrder" DECIMAL(10,2) NOT NULL,
|
||||
|
||||
CONSTRAINT "ReservationDish_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_phone_key" ON "User"("phone");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Pub_address_key" ON "Pub"("address");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Table_pubId_number_key" ON "Table"("pubId", "number");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Category_title_key" ON "Category"("title");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Menu_pubId_dishId_key" ON "Menu"("pubId", "dishId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LunchMenu_pubId_dishId_weekStart_key" ON "LunchMenu"("pubId", "dishId", "weekStart");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ReservationDish_reservationId_dishId_key" ON "ReservationDish"("reservationId", "dishId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Table" ADD CONSTRAINT "Table_pubId_fkey" FOREIGN KEY ("pubId") REFERENCES "Pub"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Dish" ADD CONSTRAINT "Dish_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "Category"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Menu" ADD CONSTRAINT "Menu_pubId_fkey" FOREIGN KEY ("pubId") REFERENCES "Pub"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Menu" ADD CONSTRAINT "Menu_dishId_fkey" FOREIGN KEY ("dishId") REFERENCES "Dish"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LunchMenu" ADD CONSTRAINT "LunchMenu_pubId_fkey" FOREIGN KEY ("pubId") REFERENCES "Pub"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "LunchMenu" ADD CONSTRAINT "LunchMenu_dishId_fkey" FOREIGN KEY ("dishId") REFERENCES "Dish"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Billboard" ADD CONSTRAINT "Billboard_pubId_fkey" FOREIGN KEY ("pubId") REFERENCES "Pub"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Reservation" ADD CONSTRAINT "Reservation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Reservation" ADD CONSTRAINT "Reservation_pubId_fkey" FOREIGN KEY ("pubId") REFERENCES "Pub"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Reservation" ADD CONSTRAINT "Reservation_tableId_fkey" FOREIGN KEY ("tableId") REFERENCES "Table"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ReservationDish" ADD CONSTRAINT "ReservationDish_reservationId_fkey" FOREIGN KEY ("reservationId") REFERENCES "Reservation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ReservationDish" ADD CONSTRAINT "ReservationDish_dishId_fkey" FOREIGN KEY ("dishId") REFERENCES "Dish"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
@@ -0,0 +1,155 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum Role {
|
||||
USER
|
||||
ADMIN
|
||||
}
|
||||
|
||||
enum ReservationStatus {
|
||||
PENDING
|
||||
CONFIRMED
|
||||
CANCELLED
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
enum DishAvailability {
|
||||
AVAILABLE
|
||||
STOPPED
|
||||
}
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
phone String @unique @db.VarChar(20)
|
||||
password String @db.VarChar(255)
|
||||
name String @db.VarChar(100)
|
||||
surname String? @db.VarChar(100)
|
||||
email String? @db.VarChar(255)
|
||||
role Role @default(USER)
|
||||
cardToken String? @db.VarChar(255)
|
||||
cardLastFour String? @db.VarChar(4)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
reservations Reservation[]
|
||||
}
|
||||
|
||||
model Pub {
|
||||
id Int @id @default(autoincrement())
|
||||
address String @unique @db.VarChar(255)
|
||||
phone String @db.VarChar(20)
|
||||
name String @db.VarChar(100)
|
||||
createdAt DateTime @default(now())
|
||||
tables Table[]
|
||||
menus Menu[]
|
||||
lunchMenus LunchMenu[]
|
||||
billboards Billboard[]
|
||||
reservations Reservation[]
|
||||
}
|
||||
|
||||
model Table {
|
||||
id Int @id @default(autoincrement())
|
||||
pubId Int
|
||||
number Int
|
||||
capacity Int
|
||||
posX Float
|
||||
posY Float
|
||||
width Float @default(60)
|
||||
height Float @default(60)
|
||||
shape String @default("rect") @db.VarChar(20)
|
||||
zone String? @db.VarChar(50)
|
||||
pub Pub @relation(fields: [pubId], references: [id])
|
||||
reservations Reservation[]
|
||||
|
||||
@@unique([pubId, number])
|
||||
}
|
||||
|
||||
model Category {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @unique @db.VarChar(100)
|
||||
dishes Dish[]
|
||||
}
|
||||
|
||||
model Dish {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @db.VarChar(100)
|
||||
description String? @db.Text
|
||||
categoryId Int
|
||||
grams Int?
|
||||
price Decimal @db.Decimal(10, 2)
|
||||
photo String? @db.VarChar(255)
|
||||
availability DishAvailability @default(AVAILABLE)
|
||||
category Category @relation(fields: [categoryId], references: [id])
|
||||
menus Menu[]
|
||||
lunchMenus LunchMenu[]
|
||||
orderItems ReservationDish[]
|
||||
}
|
||||
|
||||
model Menu {
|
||||
id Int @id @default(autoincrement())
|
||||
pubId Int
|
||||
dishId Int
|
||||
pub Pub @relation(fields: [pubId], references: [id])
|
||||
dish Dish @relation(fields: [dishId], references: [id])
|
||||
|
||||
@@unique([pubId, dishId])
|
||||
}
|
||||
|
||||
model LunchMenu {
|
||||
id Int @id @default(autoincrement())
|
||||
pubId Int
|
||||
dishId Int
|
||||
weekStart DateTime @db.Date
|
||||
weekEnd DateTime @db.Date
|
||||
pub Pub @relation(fields: [pubId], references: [id])
|
||||
dish Dish @relation(fields: [dishId], references: [id])
|
||||
|
||||
@@unique([pubId, dishId, weekStart])
|
||||
}
|
||||
|
||||
model Billboard {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @db.VarChar(200)
|
||||
artist String @db.VarChar(100)
|
||||
pubId Int
|
||||
datetime DateTime
|
||||
poster String? @db.VarChar(255)
|
||||
pub Pub @relation(fields: [pubId], references: [id])
|
||||
}
|
||||
|
||||
model Reservation {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
pubId Int
|
||||
tableId Int
|
||||
date DateTime @db.Date
|
||||
time DateTime @db.Time()
|
||||
numPeople Int
|
||||
status ReservationStatus @default(PENDING)
|
||||
totalCost Decimal? @db.Decimal(10, 2)
|
||||
prepaid Decimal? @db.Decimal(10, 2)
|
||||
paymentId String? @db.VarChar(255)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
pub Pub @relation(fields: [pubId], references: [id])
|
||||
table Table @relation(fields: [tableId], references: [id])
|
||||
dishes ReservationDish[]
|
||||
}
|
||||
|
||||
model ReservationDish {
|
||||
id Int @id @default(autoincrement())
|
||||
reservationId Int
|
||||
dishId Int
|
||||
quantity Int @default(1)
|
||||
priceAtOrder Decimal @db.Decimal(10, 2)
|
||||
reservation Reservation @relation(fields: [reservationId], references: [id], onDelete: Cascade)
|
||||
dish Dish @relation(fields: [dishId], references: [id])
|
||||
|
||||
@@unique([reservationId, dishId])
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
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: 'ул. Карла Маркса, 26, Иркутск' },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Harat's Irish Pub Иркутск",
|
||||
address: 'ул. Карла Маркса, 26, Иркутск',
|
||||
phone: '+7 (3952) 48-68-76',
|
||||
},
|
||||
});
|
||||
|
||||
const pub2 = await prisma.pub.upsert({
|
||||
where: { address: 'ул. Ленина, 15, Новосибирск' },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Harat's Irish Pub Новосибирск",
|
||||
address: 'ул. Ленина, 15, Новосибирск',
|
||||
phone: '+7 (383) 230-01-20',
|
||||
},
|
||||
});
|
||||
|
||||
const pub3 = await prisma.pub.upsert({
|
||||
where: { address: 'Невский проспект, 88, Санкт-Петербург' },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Harat's Irish Pub Санкт-Петербург",
|
||||
address: 'Невский проспект, 88, Санкт-Петербург',
|
||||
phone: '+7 (812) 640-16-16',
|
||||
},
|
||||
});
|
||||
|
||||
const pub4 = await prisma.pub.upsert({
|
||||
where: { address: 'пр. Мира, 81, Красноярск' },
|
||||
update: {},
|
||||
create: {
|
||||
name: "Harat's Irish Pub Красноярск",
|
||||
address: 'пр. Мира, 81, Красноярск',
|
||||
phone: '+7 (391) 223-22-22',
|
||||
},
|
||||
});
|
||||
|
||||
// ─── 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]) {
|
||||
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]) {
|
||||
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]) {
|
||||
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();
|
||||
});
|
||||
Reference in New Issue
Block a user