651 lines
20 KiB
TypeScript
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();
|
|
}
|
|
}
|