import type { EntityManager } from '@mikro-orm/core'; import { Seeder } from '@mikro-orm/seeder'; import { Category } from '../modules/foods/entities/category.entity'; import { Food } from '../modules/foods/entities/food.entity'; import { Admin } from '../modules/admin/entities/admin.entity'; import { AdminRole } from '../modules/admin/entities/adminRole.entity'; import { Permission as PermissionEntity } from '../modules/roles/entities/permission.entity'; import { Role } from '../modules/roles/entities/role.entity'; import { Restaurant } from '../modules/restaurants/entities/restaurant.entity'; import { User } from '../modules/users/entities/user.entity'; import { Permission, PermissionTitles } from '../common/enums/permission.enum'; import { PaymentMethod } from '../modules/payments/entities/payment-method.entity'; export class DatabaseSeeder extends Seeder { async run(em: EntityManager) { // 1. Create Permissions (English) const specialPermissions = [ Permission.CREATE_RESTAURANT, Permission.DELETE_RESTAURANT, Permission.UPDATE_RESTAURANT, ]; const permissions = Object.values(Permission).map(name => ({ name, title: PermissionTitles[name], group: specialPermissions.includes(name) ? 'special' : 'general', })); const createdPermissions: PermissionEntity[] = []; for (const permData of permissions) { let permission = await em.findOne(PermissionEntity, { name: permData.name }); if (!permission) { permission = em.create(PermissionEntity, permData); em.persist(permission); } else { // Update existing permission's group if it changed if (permission.group !== permData.group) { permission.group = permData.group; em.persist(permission); } } createdPermissions.push(permission); } // 2. Create Roles (English) let restaurantRole = await em.findOne(Role, { name: 'restaurant' }); if (!restaurantRole) { const role = em.create(Role, { name: 'restaurant' }); // Add all general permissions to restaurant role (excluding special permissions) const generalPermissions = createdPermissions.filter(p => p.group === 'general'); generalPermissions.forEach(p => role.permissions.add(p)); em.persist(role); restaurantRole = role; } const accountantRole = await em.findOne(Role, { name: 'accountant' }); if (!accountantRole) { const role = em.create(Role, { name: 'accountant' }); // Add financial permissions to accountant const financialPerms = createdPermissions.filter( p => (p.name as Permission) === Permission.VIEW_REPORTS || (p.name as Permission) === Permission.MANAGE_FINANCES || (p.name as Permission) === Permission.MANAGE_ORDERS, ); financialPerms.forEach(p => role.permissions.add(p)); em.persist(role); } const superAdminRole = await em.findOne(Role, { name: 'superAdmin' }); if (!superAdminRole) { const role = em.create(Role, { name: 'superAdmin' }); // Add restaurant management permissions to superAdmin const restaurantPerms = createdPermissions.filter( p => (p.name as Permission) === Permission.CREATE_RESTAURANT || (p.name as Permission) === Permission.DELETE_RESTAURANT || (p.name as Permission) === Permission.UPDATE_RESTAURANT, ); restaurantPerms.forEach(p => role.permissions.add(p)); em.persist(role); } await em.flush(); // Get roles after flush (refresh to ensure they're loaded) if (!restaurantRole) { restaurantRole = await em.findOne(Role, { name: 'restaurant' }); } await em.findOne(Role, { name: 'accountant' }); const superAdmin = await em.findOne(Role, { name: 'superAdmin' }); // 3. Create Payment Methods const zarinpalPaymentMethod = await em.findOne(PaymentMethod, { keyName: 'zarinpal' }); if (!zarinpalPaymentMethod) { const paymentMethod = em.create(PaymentMethod, { name: 'زرین‌پال', keyName: 'zarinpal', description: 'درگاه پرداخت زرین‌پال', isActive: true, order: 1, }); em.persist(paymentMethod); } await em.flush(); // 4. Create Restaurants (Farsi) const zhivanRestaurant = await em.findOne(Restaurant, { slug: 'zhivan' }); if (!zhivanRestaurant) { const restaurant = em.create(Restaurant, { name: 'ژیوان', slug: 'zhivan', isActive: true, }); em.persist(restaurant); } const booteRestaurant = await em.findOne(Restaurant, { slug: 'boote' }); if (!booteRestaurant) { const restaurant = em.create(Restaurant, { name: 'بوته', slug: 'boote', isActive: true, }); em.persist(restaurant); } await em.flush(); // Get restaurants after flush const zhivan = await em.findOne(Restaurant, { slug: 'zhivan' }); const boote = await em.findOne(Restaurant, { slug: 'boote' }); // 5. Create Categories (Farsi) const categories = [ { title: 'غذای اصلی', restId: zhivan?.id }, { title: 'پیش غذا', restId: zhivan?.id }, { title: 'دسر', restId: zhivan?.id }, { title: 'نوشیدنی', restId: zhivan?.id }, { title: 'غذای اصلی', restId: boote?.id }, { title: 'پیش غذا', restId: boote?.id }, { title: 'دسر', restId: boote?.id }, { title: 'نوشیدنی', restId: boote?.id }, ]; const createdCategories: Category[] = []; for (const catData of categories) { const existing = await em.findOne(Category, { title: catData.title, restId: catData.restId }); if (!existing) { const category = em.create(Category, { title: catData.title, restId: catData.restId, isActive: true, }); em.persist(category); createdCategories.push(category); } else { createdCategories.push(existing); } } await em.flush(); // 6. Create Foods (Farsi) const foods = [ // Zhivan Restaurant Foods { title: 'کباب کوبیده', desc: 'کباب کوبیده خوشمزه با برنج و کره', price: 150000, restaurant: zhivan, categories: [createdCategories[0]], // غذای اصلی isActive: true, stock: 50, stockDefault: 50, }, { title: 'جوجه کباب', desc: 'جوجه کباب تازه با برنج', price: 120000, restaurant: zhivan, categories: [createdCategories[0]], // غذای اصلی isActive: true, stock: 40, stockDefault: 40, }, { title: 'کباب بختیاری', desc: 'کباب بختیاری با برنج و کره', price: 180000, restaurant: zhivan, categories: [createdCategories[0]], // غذای اصلی isActive: true, stock: 35, stockDefault: 35, }, { title: 'کباب برگ', desc: 'کباب برگ مرغوب با برنج', price: 160000, restaurant: zhivan, categories: [createdCategories[0]], // غذای اصلی isActive: true, stock: 30, stockDefault: 30, }, { title: 'سالاد فصل', desc: 'سالاد تازه با سس مخصوص', price: 35000, restaurant: zhivan, categories: [createdCategories[1]], // پیش غذا isActive: true, stock: 30, stockDefault: 30, }, { title: 'ماست و خیار', desc: 'ماست و خیار تازه', price: 25000, restaurant: zhivan, categories: [createdCategories[1]], // پیش غذا isActive: true, stock: 25, stockDefault: 25, }, { title: 'ترشی', desc: 'ترشی مخلوط خانگی', price: 20000, restaurant: zhivan, categories: [createdCategories[1]], // پیش غذا isActive: true, stock: 20, stockDefault: 20, }, { title: 'بستنی', desc: 'بستنی وانیلی خوشمزه', price: 25000, restaurant: zhivan, categories: [createdCategories[2]], // دسر isActive: true, stock: 20, stockDefault: 20, }, { title: 'شیرینی', desc: 'شیرینی محلی', price: 30000, restaurant: zhivan, categories: [createdCategories[2]], // دسر isActive: true, stock: 15, stockDefault: 15, }, { title: 'نوشابه', desc: 'نوشابه گازدار', price: 15000, restaurant: zhivan, categories: [createdCategories[3]], // نوشیدنی isActive: true, stock: 100, stockDefault: 100, }, { title: 'دوغ', desc: 'دوغ محلی', price: 20000, restaurant: zhivan, categories: [createdCategories[3]], // نوشیدنی isActive: true, stock: 50, stockDefault: 50, }, { title: 'آب معدنی', desc: 'آب معدنی', price: 10000, restaurant: zhivan, categories: [createdCategories[3]], // نوشیدنی isActive: true, stock: 80, stockDefault: 80, }, // Boote Restaurant Foods { title: 'پیتزا مخصوص', desc: 'پیتزا با پنیر و قارچ', price: 180000, restaurant: boote, categories: [createdCategories[4]], // غذای اصلی isActive: true, stock: 30, stockDefault: 30, }, { title: 'پیتزا پپرونی', desc: 'پیتزا پپرونی تند', price: 200000, restaurant: boote, categories: [createdCategories[4]], // غذای اصلی isActive: true, stock: 25, stockDefault: 25, }, { title: 'برگر', desc: 'برگر با سیب زمینی سرخ کرده', price: 140000, restaurant: boote, categories: [createdCategories[4]], // غذای اصلی isActive: true, stock: 25, stockDefault: 25, }, { title: 'برگر مخصوص', desc: 'برگر دوبل با پنیر', price: 180000, restaurant: boote, categories: [createdCategories[4]], // غذای اصلی isActive: true, stock: 20, stockDefault: 20, }, { title: 'سوپ', desc: 'سوپ گرم و خوشمزه', price: 45000, restaurant: boote, categories: [createdCategories[5]], // پیش غذا isActive: true, stock: 15, stockDefault: 15, }, { title: 'سالاد سزار', desc: 'سالاد سزار با سس مخصوص', price: 55000, restaurant: boote, categories: [createdCategories[5]], // پیش غذا isActive: true, stock: 20, stockDefault: 20, }, { title: 'سیب زمینی سرخ کرده', desc: 'سیب زمینی سرخ کرده ترد', price: 40000, restaurant: boote, categories: [createdCategories[5]], // پیش غذا isActive: true, stock: 30, stockDefault: 30, }, { title: 'کیک شکلاتی', desc: 'کیک شکلاتی خامه‌ای', price: 60000, restaurant: boote, categories: [createdCategories[6]], // دسر isActive: true, stock: 10, stockDefault: 10, }, { title: 'چیزکیک', desc: 'چیزکیک وانیلی', price: 65000, restaurant: boote, categories: [createdCategories[6]], // دسر isActive: true, stock: 12, stockDefault: 12, }, { title: 'نوشابه', desc: 'نوشابه گازدار', price: 15000, restaurant: boote, categories: [createdCategories[7]], // نوشیدنی isActive: true, stock: 100, stockDefault: 100, }, { title: 'آبمیوه طبیعی', desc: 'آبمیوه تازه', price: 35000, restaurant: boote, categories: [createdCategories[7]], // نوشیدنی isActive: true, stock: 40, stockDefault: 40, }, { title: 'قهوه', desc: 'قهوه اسپرسو', price: 45000, restaurant: boote, categories: [createdCategories[7]], // نوشیدنی isActive: true, stock: 50, stockDefault: 50, }, ]; for (const foodData of foods) { if (foodData.restaurant) { const existing = await em.findOne(Food, { title: foodData.title, restaurant: foodData.restaurant, }); if (!existing) { const food = em.create(Food, { title: foodData.title, desc: foodData.desc, price: foodData.price, restaurant: foodData.restaurant, isActive: foodData.isActive, stock: foodData.stock, stockDefault: foodData.stockDefault, sat: false, sun: false, mon: false, breakfast: false, noon: false, dinner: false, discount: 0, rate: 0, inPlaceServe: false, pickupServe: false, }); // Add categories if (foodData.categories) { foodData.categories.forEach(cat => food.categories.add(cat)); } em.persist(food); } } } await em.flush(); // 7. Create Admins (Farsi) const adminMorteza = await em.findOne(Admin, { phone: '09362532122' }); if (!adminMorteza && restaurantRole && zhivan) { const admin = em.create(Admin, { phone: '09362532122', firstName: 'مرتضی', lastName: 'مرتضایی', }); em.persist(admin); // Create AdminRole linking admin to role and restaurant const adminRole = em.create(AdminRole, { admin, role: restaurantRole, restaurant: zhivan, }); em.persist(adminRole); admin.roles.add(adminRole); } const adminHamid = await em.findOne(Admin, { phone: '09185290775' }); if (!adminHamid && restaurantRole && boote) { const admin = em.create(Admin, { phone: '09185290775', firstName: 'حمید', lastName: 'ضرقامی', }); em.persist(admin); // Create AdminRole linking admin to role and restaurant const adminRole = em.create(AdminRole, { admin, role: restaurantRole, restaurant: boote, }); em.persist(adminRole); admin.roles.add(adminRole); } const adminMehrdad = await em.findOne(Admin, { phone: '0912928395' }); if (!adminMehrdad && superAdmin) { const admin = em.create(Admin, { phone: '0912928395', firstName: 'مهرداد', lastName: 'مظفری', }); em.persist(admin); // Create AdminRole linking admin to role (no restaurant for superAdmin) const adminRole = em.create(AdminRole, { admin, role: superAdmin, restaurant: null, // SuperAdmin doesn't belong to a specific restaurant }); em.persist(adminRole); admin.roles.add(adminRole); } await em.flush(); // 8. Create Users (Farsi) const userMorteza = await em.findOne(User, { phone: '09362532122' }); if (!userMorteza && zhivan) { const user = em.create(User, { phone: '09362532122', firstName: 'مرتضی', lastName: 'مرتضایی', restaurant: zhivan, birthDate: new Date('1990-01-01'), marriageDate: new Date('2015-01-01'), isActive: true, gender: true, wallet: 0, points: 0, }); em.persist(user); } const userHamid = await em.findOne(User, { phone: '09185290775' }); if (!userHamid && boote) { const user = em.create(User, { phone: '09185290775', firstName: 'حمید', lastName: 'زرگامی', restaurant: boote, birthDate: new Date('1992-01-01'), marriageDate: new Date('2017-01-01'), isActive: true, gender: true, wallet: 0, points: 0, }); em.persist(user); } // Final flush await em.flush(); } }