Files
dmenu-api/src/seeders/DatabaseSeeder.ts
T
2025-11-25 15:49:08 +03:30

651 lines
20 KiB
TypeScript

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';
import { RestaurantPaymentMethod } from '../modules/payments/entities/restaurant-payment-method.entity';
import { ShipmentMethod } from '../modules/shipments/entities/shipment-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', isSystem: false });
// 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', isSystem: false });
// 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', isSystem: true });
// 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 Shipment Methods (Farsi)
const shipmentMethods = [
{
name: 'dine-in',
title: 'سرو در رستوران',
description: 'سرو غذا در رستوران',
isActive: true,
},
{
name: 'delivery-location',
title: 'تحویل در محل',
description: 'تحویل غذا در محل',
isActive: true,
},
{
name: 'delivery-car',
title: 'تحویل با ماشین',
description: 'تحویل غذا با ماشین',
isActive: true,
},
{
name: 'delivery-courier',
title: 'تحویل با پیک',
description: 'تحویل غذا با پیک',
isActive: true,
},
];
const createdShipmentMethods: ShipmentMethod[] = [];
for (const methodData of shipmentMethods) {
let shipmentMethod = await em.findOne(ShipmentMethod, { name: methodData.name });
if (!shipmentMethod) {
shipmentMethod = em.create(ShipmentMethod, methodData);
em.persist(shipmentMethod);
} else {
// Update existing method if needed
if (shipmentMethod.title !== methodData.title || shipmentMethod.description !== methodData.description) {
shipmentMethod.title = methodData.title;
shipmentMethod.description = methodData.description;
em.persist(shipmentMethod);
}
}
createdShipmentMethods.push(shipmentMethod);
}
await em.flush();
// 5. Create Restaurants (Farsi)
const zhivanRestaurant = await em.findOne(Restaurant, { slug: 'zhivan' });
if (!zhivanRestaurant) {
const restaurant = em.create(Restaurant, {
name: 'ژیوان',
slug: 'zhivan',
isActive: true,
phone: '09123456789',
serviceArea: {
type: 'Polygon',
coordinates: [
[
[51.389, 35.6892],
[51.39, 35.6892],
[51.39, 35.6902],
[51.389, 35.6902],
[51.389, 35.6892],
],
],
},
});
em.persist(restaurant);
}
const booteRestaurant = await em.findOne(Restaurant, { slug: 'boote' });
if (!booteRestaurant) {
const restaurant = em.create(Restaurant, {
name: 'بوته',
slug: 'boote',
isActive: true,
phone: '09123456790',
serviceArea: {
type: 'Polygon',
coordinates: [
[
[51.389, 35.6892],
[51.39, 35.6892],
[51.39, 35.6902],
[51.389, 35.6902],
[51.389, 35.6892],
],
],
},
});
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.5. Create Restaurant Payment Methods
const allRestaurants = [zhivan, boote].filter(Boolean) as Restaurant[];
const allPaymentMethods = await em.find(PaymentMethod, { isActive: true });
for (const restaurant of allRestaurants) {
if (!restaurant) continue;
for (const paymentMethod of allPaymentMethods) {
const existing = await em.findOne(RestaurantPaymentMethod, {
restaurant: { id: restaurant.id },
paymentMethod: { id: paymentMethod.id },
});
if (!existing) {
const restaurantPaymentMethod = em.create(RestaurantPaymentMethod, {
restaurant,
paymentMethod,
isActive: true,
});
em.persist(restaurantPaymentMethod);
}
}
}
await em.flush();
// 6. Create Categories (Farsi)
const categories = [
{ title: 'غذای اصلی', restaurant: zhivan },
{ title: 'پیش غذا', restaurant: zhivan },
{ title: 'دسر', restaurant: zhivan },
{ title: 'نوشیدنی', restaurant: zhivan },
{ title: 'غذای اصلی', restaurant: boote },
{ title: 'پیش غذا', restaurant: boote },
{ title: 'دسر', restaurant: boote },
{ title: 'نوشیدنی', restaurant: boote },
];
const createdCategories: Category[] = [];
for (const catData of categories) {
if (!catData.restaurant) continue;
const existing = await em.findOne(Category, {
title: catData.title,
restaurant: catData.restaurant,
});
if (!existing) {
const category = em.create(Category, {
title: catData.title,
restaurant: catData.restaurant,
isActive: true,
});
em.persist(category);
createdCategories.push(category);
} else {
createdCategories.push(existing);
}
}
await em.flush();
// 7. Create Foods (Farsi)
const foods = [
// Zhivan Restaurant Foods
{
title: 'کباب کوبیده',
desc: 'کباب کوبیده خوشمزه با برنج و کره',
price: 150000,
restaurant: zhivan,
category: createdCategories[0], // غذای اصلی
isActive: true,
stock: 50,
stockDefault: 50,
},
{
title: 'جوجه کباب',
desc: 'جوجه کباب تازه با برنج',
price: 120000,
restaurant: zhivan,
category: createdCategories[0], // غذای اصلی
isActive: true,
stock: 40,
stockDefault: 40,
},
{
title: 'کباب بختیاری',
desc: 'کباب بختیاری با برنج و کره',
price: 180000,
restaurant: zhivan,
category: createdCategories[0], // غذای اصلی
isActive: true,
stock: 35,
stockDefault: 35,
},
{
title: 'کباب برگ',
desc: 'کباب برگ مرغوب با برنج',
price: 160000,
restaurant: zhivan,
category: createdCategories[0], // غذای اصلی
isActive: true,
stock: 30,
stockDefault: 30,
},
{
title: 'سالاد فصل',
desc: 'سالاد تازه با سس مخصوص',
price: 35000,
restaurant: zhivan,
category: createdCategories[1], // پیش غذا
isActive: true,
stock: 30,
stockDefault: 30,
},
{
title: 'ماست و خیار',
desc: 'ماست و خیار تازه',
price: 25000,
restaurant: zhivan,
category: createdCategories[1], // پیش غذا
isActive: true,
stock: 25,
stockDefault: 25,
},
{
title: 'ترشی',
desc: 'ترشی مخلوط خانگی',
price: 20000,
restaurant: zhivan,
category: createdCategories[1], // پیش غذا
isActive: true,
stock: 20,
stockDefault: 20,
},
{
title: 'بستنی',
desc: 'بستنی وانیلی خوشمزه',
price: 25000,
restaurant: zhivan,
category: createdCategories[2], // دسر
isActive: true,
stock: 20,
stockDefault: 20,
},
{
title: 'شیرینی',
desc: 'شیرینی محلی',
price: 30000,
restaurant: zhivan,
category: createdCategories[2], // دسر
isActive: true,
stock: 15,
stockDefault: 15,
},
{
title: 'نوشابه',
desc: 'نوشابه گازدار',
price: 15000,
restaurant: zhivan,
category: createdCategories[3], // نوشیدنی
isActive: true,
stock: 100,
stockDefault: 100,
},
{
title: 'دوغ',
desc: 'دوغ محلی',
price: 20000,
restaurant: zhivan,
category: createdCategories[3], // نوشیدنی
isActive: true,
stock: 50,
stockDefault: 50,
},
{
title: 'آب معدنی',
desc: 'آب معدنی',
price: 10000,
restaurant: zhivan,
category: createdCategories[3], // نوشیدنی
isActive: true,
stock: 80,
stockDefault: 80,
},
// Boote Restaurant Foods
{
title: 'پیتزا مخصوص',
desc: 'پیتزا با پنیر و قارچ',
price: 180000,
restaurant: boote,
category: createdCategories[4], // غذای اصلی
isActive: true,
stock: 30,
stockDefault: 30,
},
{
title: 'پیتزا پپرونی',
desc: 'پیتزا پپرونی تند',
price: 200000,
restaurant: boote,
category: createdCategories[4], // غذای اصلی
isActive: true,
stock: 25,
stockDefault: 25,
},
{
title: 'برگر',
desc: 'برگر با سیب زمینی سرخ کرده',
price: 140000,
restaurant: boote,
category: createdCategories[4], // غذای اصلی
isActive: true,
stock: 25,
stockDefault: 25,
},
{
title: 'برگر مخصوص',
desc: 'برگر دوبل با پنیر',
price: 180000,
restaurant: boote,
category: createdCategories[4], // غذای اصلی
isActive: true,
stock: 20,
stockDefault: 20,
},
{
title: 'سوپ',
desc: 'سوپ گرم و خوشمزه',
price: 45000,
restaurant: boote,
category: createdCategories[5], // پیش غذا
isActive: true,
stock: 15,
stockDefault: 15,
},
{
title: 'سالاد سزار',
desc: 'سالاد سزار با سس مخصوص',
price: 55000,
restaurant: boote,
category: createdCategories[5], // پیش غذا
isActive: true,
stock: 20,
stockDefault: 20,
},
{
title: 'سیب زمینی سرخ کرده',
desc: 'سیب زمینی سرخ کرده ترد',
price: 40000,
restaurant: boote,
category: createdCategories[5], // پیش غذا
isActive: true,
stock: 30,
stockDefault: 30,
},
{
title: 'کیک شکلاتی',
desc: 'کیک شکلاتی خامه‌ای',
price: 60000,
restaurant: boote,
category: createdCategories[6], // دسر
isActive: true,
stock: 10,
stockDefault: 10,
},
{
title: 'چیزکیک',
desc: 'چیزکیک وانیلی',
price: 65000,
restaurant: boote,
category: createdCategories[6], // دسر
isActive: true,
stock: 12,
stockDefault: 12,
},
{
title: 'نوشابه',
desc: 'نوشابه گازدار',
price: 15000,
restaurant: boote,
category: createdCategories[7], // نوشیدنی
isActive: true,
stock: 100,
stockDefault: 100,
},
{
title: 'آبمیوه طبیعی',
desc: 'آبمیوه تازه',
price: 35000,
restaurant: boote,
category: createdCategories[7], // نوشیدنی
isActive: true,
stock: 40,
stockDefault: 40,
},
{
title: 'قهوه',
desc: 'قهوه اسپرسو',
price: 45000,
restaurant: boote,
category: createdCategories[7], // نوشیدنی
isActive: true,
stock: 50,
stockDefault: 50,
},
];
for (const foodData of foods) {
if (foodData.restaurant && foodData.category) {
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,
category: foodData.category,
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,
});
em.persist(food);
}
}
}
await em.flush();
// 8. 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();
// 9. 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();
}
}