RBAC: Phase 1-3, Total Salary fix, employee creation fix, permission groups, backup script
Made-with: Cursor
This commit is contained in:
@@ -83,7 +83,7 @@ async function main() {
|
||||
|
||||
console.log('\n🌱 Running seed...\n');
|
||||
const backendDir = path.resolve(__dirname, '..');
|
||||
execSync('node prisma/seed-prod.js', {
|
||||
execSync('node prisma/seed.js', {
|
||||
stdio: 'inherit',
|
||||
cwd: backendDir,
|
||||
env: process.env,
|
||||
|
||||
12
backend/prisma/ensure-gm-permissions.sql
Normal file
12
backend/prisma/ensure-gm-permissions.sql
Normal file
@@ -0,0 +1,12 @@
|
||||
-- Ensure GM has all module permissions
|
||||
-- Run: npx prisma db execute --file prisma/ensure-gm-permissions.sql
|
||||
|
||||
INSERT INTO position_permissions (id, "positionId", module, resource, actions, "createdAt", "updatedAt")
|
||||
SELECT gen_random_uuid(), p.id, m.module, '*', '["*"]', NOW(), NOW()
|
||||
FROM positions p
|
||||
CROSS JOIN (VALUES ('contacts'), ('crm'), ('inventory'), ('projects'), ('hr'), ('marketing'), ('admin')) AS m(module)
|
||||
WHERE p.code = 'GM'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM position_permissions pp
|
||||
WHERE pp."positionId" = p.id AND pp.module = m.module AND pp.resource = '*'
|
||||
);
|
||||
@@ -0,0 +1,59 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "roles" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"nameAr" TEXT,
|
||||
"description" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "roles_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "role_permissions" (
|
||||
"id" TEXT NOT NULL,
|
||||
"roleId" TEXT NOT NULL,
|
||||
"module" TEXT NOT NULL,
|
||||
"resource" TEXT NOT NULL,
|
||||
"actions" JSONB NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "role_permissions_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "user_roles" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"roleId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "user_roles_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "roles_name_key" ON "roles"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "role_permissions_roleId_module_resource_key" ON "role_permissions"("roleId", "module", "resource");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_roles_userId_idx" ON "user_roles"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "user_roles_roleId_idx" ON "user_roles"("roleId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "user_roles_userId_roleId_key" ON "user_roles"("userId", "roleId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "role_permissions" ADD CONSTRAINT "role_permissions_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_roleId_fkey" FOREIGN KEY ("roleId") REFERENCES "roles"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -69,10 +69,59 @@ model User {
|
||||
assignedTasks Task[]
|
||||
projectMembers ProjectMember[]
|
||||
campaigns Campaign[]
|
||||
userRoles UserRole[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
// Optional roles - user can belong to multiple permission groups (Phase 3 multi-group)
|
||||
model Role {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
nameAr String?
|
||||
description String?
|
||||
isActive Boolean @default(true)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
permissions RolePermission[]
|
||||
userRoles UserRole[]
|
||||
|
||||
@@map("roles")
|
||||
}
|
||||
|
||||
model RolePermission {
|
||||
id String @id @default(uuid())
|
||||
roleId String
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
module String
|
||||
resource String
|
||||
actions Json // ["read", "create", "update", "delete", ...]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([roleId, module, resource])
|
||||
@@map("role_permissions")
|
||||
}
|
||||
|
||||
model UserRole {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
roleId String
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([userId, roleId])
|
||||
@@index([userId])
|
||||
@@index([roleId])
|
||||
@@map("user_roles")
|
||||
}
|
||||
|
||||
model Employee {
|
||||
id String @id @default(uuid())
|
||||
uniqueEmployeeId String @unique // رقم الموظف الموحد
|
||||
|
||||
146
backend/prisma/seed.js
Normal file
146
backend/prisma/seed.js
Normal file
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Minimal seed - System Administrator only.
|
||||
* Run with: node prisma/seed.js
|
||||
*/
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Starting database seeding (minimal - System Administrator only)...');
|
||||
|
||||
const adminDept = await prisma.department.create({
|
||||
data: {
|
||||
name: 'Administration',
|
||||
nameAr: 'الإدارة',
|
||||
code: 'ADMIN',
|
||||
description: 'System administration and configuration',
|
||||
},
|
||||
});
|
||||
|
||||
const sysAdminPosition = await prisma.position.create({
|
||||
data: {
|
||||
title: 'System Administrator',
|
||||
titleAr: 'مدير النظام',
|
||||
code: 'SYS_ADMIN',
|
||||
departmentId: adminDept.id,
|
||||
level: 1,
|
||||
description: 'Full system access - configure and manage all modules',
|
||||
},
|
||||
});
|
||||
|
||||
const modules = ['contacts', 'crm', 'inventory', 'projects', 'hr', 'marketing', 'admin'];
|
||||
for (const module of modules) {
|
||||
await prisma.positionPermission.create({
|
||||
data: {
|
||||
positionId: sysAdminPosition.id,
|
||||
module,
|
||||
resource: '*',
|
||||
actions: ['*'],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Create Sales Department and restricted positions
|
||||
const salesDept = await prisma.department.create({
|
||||
data: {
|
||||
name: 'Sales',
|
||||
nameAr: 'المبيعات',
|
||||
code: 'SALES',
|
||||
description: 'Sales and business development',
|
||||
},
|
||||
});
|
||||
|
||||
const salesRepPosition = await prisma.position.create({
|
||||
data: {
|
||||
title: 'Sales Representative',
|
||||
titleAr: 'مندوب مبيعات',
|
||||
code: 'SALES_REP',
|
||||
departmentId: salesDept.id,
|
||||
level: 3,
|
||||
description: 'Limited access - Contacts and CRM deals',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.positionPermission.createMany({
|
||||
data: [
|
||||
{ positionId: salesRepPosition.id, module: 'contacts', resource: '*', actions: ['read', 'create', 'update'] },
|
||||
{ positionId: salesRepPosition.id, module: 'crm', resource: 'deals', actions: ['read', 'create', 'update'] },
|
||||
],
|
||||
});
|
||||
|
||||
const accountantPosition = await prisma.position.create({
|
||||
data: {
|
||||
title: 'Accountant',
|
||||
titleAr: 'محاسب',
|
||||
code: 'ACCOUNTANT',
|
||||
departmentId: adminDept.id,
|
||||
level: 2,
|
||||
description: 'HR read, inventory read, contacts read',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.positionPermission.createMany({
|
||||
data: [
|
||||
{ positionId: accountantPosition.id, module: 'contacts', resource: '*', actions: ['read'] },
|
||||
{ positionId: accountantPosition.id, module: 'crm', resource: '*', actions: ['read'] },
|
||||
{ positionId: accountantPosition.id, module: 'inventory', resource: '*', actions: ['read'] },
|
||||
{ positionId: accountantPosition.id, module: 'hr', resource: '*', actions: ['read'] },
|
||||
],
|
||||
});
|
||||
|
||||
console.log('✅ Created position and permissions');
|
||||
|
||||
const sysAdminEmployee = await prisma.employee.create({
|
||||
data: {
|
||||
uniqueEmployeeId: 'SYS-001',
|
||||
firstName: 'System',
|
||||
lastName: 'Administrator',
|
||||
firstNameAr: 'مدير',
|
||||
lastNameAr: 'النظام',
|
||||
email: 'admin@system.local',
|
||||
mobile: '+966500000000',
|
||||
dateOfBirth: new Date('1990-01-01'),
|
||||
gender: 'MALE',
|
||||
nationality: 'Saudi',
|
||||
employmentType: 'Full-time',
|
||||
contractType: 'Unlimited',
|
||||
hireDate: new Date(),
|
||||
departmentId: adminDept.id,
|
||||
positionId: sysAdminPosition.id,
|
||||
basicSalary: 0,
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
|
||||
const hashedPassword = await bcrypt.hash('Admin@123', 10);
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
email: 'admin@system.local',
|
||||
username: 'admin',
|
||||
password: hashedPassword,
|
||||
employeeId: sysAdminEmployee.id,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created System Administrator');
|
||||
console.log('\n🎉 Database seeding completed!\n');
|
||||
console.log('📋 System Administrator:');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log(' Email: admin@system.local');
|
||||
console.log(' Username: admin');
|
||||
console.log(' Password: Admin@123');
|
||||
console.log(' Access: Full system access (all modules)');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error('❌ Error seeding database:', e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
@@ -4,58 +4,50 @@ import bcrypt from 'bcryptjs';
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Starting database seeding...');
|
||||
console.log('🌱 Starting database seeding (minimal - System Administrator only)...');
|
||||
|
||||
// Create Departments
|
||||
// Create Administration Department
|
||||
const adminDept = await prisma.department.create({
|
||||
data: {
|
||||
name: 'Administration',
|
||||
nameAr: 'الإدارة',
|
||||
code: 'ADMIN',
|
||||
description: 'System administration and configuration',
|
||||
},
|
||||
});
|
||||
|
||||
// Create System Administrator Position
|
||||
const sysAdminPosition = await prisma.position.create({
|
||||
data: {
|
||||
title: 'System Administrator',
|
||||
titleAr: 'مدير النظام',
|
||||
code: 'SYS_ADMIN',
|
||||
departmentId: adminDept.id,
|
||||
level: 1,
|
||||
description: 'Full system access - configure and manage all modules',
|
||||
},
|
||||
});
|
||||
|
||||
// Create full permissions for all modules
|
||||
const modules = ['contacts', 'crm', 'inventory', 'projects', 'hr', 'marketing', 'admin'];
|
||||
for (const module of modules) {
|
||||
await prisma.positionPermission.create({
|
||||
data: {
|
||||
positionId: sysAdminPosition.id,
|
||||
module,
|
||||
resource: '*',
|
||||
actions: ['*'],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Create Sales Department and restricted positions
|
||||
const salesDept = await prisma.department.create({
|
||||
data: {
|
||||
name: 'Sales Department',
|
||||
nameAr: 'قسم المبيعات',
|
||||
name: 'Sales',
|
||||
nameAr: 'المبيعات',
|
||||
code: 'SALES',
|
||||
description: 'Sales and Business Development',
|
||||
},
|
||||
});
|
||||
|
||||
const itDept = await prisma.department.create({
|
||||
data: {
|
||||
name: 'IT Department',
|
||||
nameAr: 'قسم تقنية المعلومات',
|
||||
code: 'IT',
|
||||
description: 'Information Technology',
|
||||
},
|
||||
});
|
||||
|
||||
const hrDept = await prisma.department.create({
|
||||
data: {
|
||||
name: 'HR Department',
|
||||
nameAr: 'قسم الموارد البشرية',
|
||||
code: 'HR',
|
||||
description: 'Human Resources',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created departments');
|
||||
|
||||
// Create Positions
|
||||
const gmPosition = await prisma.position.create({
|
||||
data: {
|
||||
title: 'General Manager',
|
||||
titleAr: 'المدير العام',
|
||||
code: 'GM',
|
||||
departmentId: salesDept.id,
|
||||
level: 1,
|
||||
description: 'Chief Executive - Full Access',
|
||||
},
|
||||
});
|
||||
|
||||
const salesManagerPosition = await prisma.position.create({
|
||||
data: {
|
||||
title: 'Sales Manager',
|
||||
titleAr: 'مدير المبيعات',
|
||||
code: 'SALES_MGR',
|
||||
departmentId: salesDept.id,
|
||||
level: 2,
|
||||
description: 'Sales Department Manager',
|
||||
description: 'Sales and business development',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -66,286 +58,83 @@ async function main() {
|
||||
code: 'SALES_REP',
|
||||
departmentId: salesDept.id,
|
||||
level: 3,
|
||||
description: 'Sales Representative',
|
||||
description: 'Limited access - Contacts and CRM deals',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created positions');
|
||||
await prisma.positionPermission.createMany({
|
||||
data: [
|
||||
{ positionId: salesRepPosition.id, module: 'contacts', resource: '*', actions: ['read', 'create', 'update'] },
|
||||
{ positionId: salesRepPosition.id, module: 'crm', resource: 'deals', actions: ['read', 'create', 'update'] },
|
||||
],
|
||||
});
|
||||
|
||||
// Create Permissions for GM (Full Access)
|
||||
const modules = ['contacts', 'crm', 'inventory', 'projects', 'hr', 'marketing'];
|
||||
const resources = ['*'];
|
||||
const actions = ['*'];
|
||||
|
||||
for (const module of modules) {
|
||||
await prisma.positionPermission.create({
|
||||
data: {
|
||||
positionId: gmPosition.id,
|
||||
module,
|
||||
resource: resources[0],
|
||||
actions,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Admin permission for GM
|
||||
await prisma.positionPermission.create({
|
||||
const accountantPosition = await prisma.position.create({
|
||||
data: {
|
||||
positionId: gmPosition.id,
|
||||
module: 'admin',
|
||||
resource: '*',
|
||||
actions: ['*'],
|
||||
title: 'Accountant',
|
||||
titleAr: 'محاسب',
|
||||
code: 'ACCOUNTANT',
|
||||
departmentId: adminDept.id,
|
||||
level: 2,
|
||||
description: 'HR read, inventory read, contacts read',
|
||||
},
|
||||
});
|
||||
|
||||
// Create Permissions for Sales Manager
|
||||
await prisma.positionPermission.createMany({
|
||||
data: [
|
||||
{
|
||||
positionId: salesManagerPosition.id,
|
||||
module: 'contacts',
|
||||
resource: 'contacts',
|
||||
actions: ['create', 'read', 'update', 'merge'],
|
||||
},
|
||||
{
|
||||
positionId: salesManagerPosition.id,
|
||||
module: 'crm',
|
||||
resource: 'deals',
|
||||
actions: ['create', 'read', 'update', 'approve'],
|
||||
},
|
||||
{
|
||||
positionId: salesManagerPosition.id,
|
||||
module: 'crm',
|
||||
resource: 'quotes',
|
||||
actions: ['create', 'read', 'update', 'approve'],
|
||||
},
|
||||
{ positionId: accountantPosition.id, module: 'contacts', resource: '*', actions: ['read'] },
|
||||
{ positionId: accountantPosition.id, module: 'crm', resource: '*', actions: ['read'] },
|
||||
{ positionId: accountantPosition.id, module: 'inventory', resource: '*', actions: ['read'] },
|
||||
{ positionId: accountantPosition.id, module: 'hr', resource: '*', actions: ['read'] },
|
||||
],
|
||||
});
|
||||
|
||||
// Create Permissions for Sales Rep
|
||||
await prisma.positionPermission.createMany({
|
||||
data: [
|
||||
{
|
||||
positionId: salesRepPosition.id,
|
||||
module: 'contacts',
|
||||
resource: 'contacts',
|
||||
actions: ['create', 'read', 'update'],
|
||||
},
|
||||
{
|
||||
positionId: salesRepPosition.id,
|
||||
module: 'crm',
|
||||
resource: 'deals',
|
||||
actions: ['create', 'read', 'update'],
|
||||
},
|
||||
{
|
||||
positionId: salesRepPosition.id,
|
||||
module: 'crm',
|
||||
resource: 'quotes',
|
||||
actions: ['create', 'read'],
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log('✅ Created position and permissions');
|
||||
|
||||
console.log('✅ Created permissions');
|
||||
|
||||
// Create Employees
|
||||
const gmEmployee = await prisma.employee.create({
|
||||
// Create minimal Employee for System Administrator
|
||||
const sysAdminEmployee = await prisma.employee.create({
|
||||
data: {
|
||||
uniqueEmployeeId: 'EMP-2024-0001',
|
||||
firstName: 'Ahmed',
|
||||
lastName: 'Al-Mutairi',
|
||||
firstNameAr: 'أحمد',
|
||||
lastNameAr: 'المطيري',
|
||||
email: 'gm@atmata.com',
|
||||
mobile: '+966500000001',
|
||||
dateOfBirth: new Date('1980-01-01'),
|
||||
uniqueEmployeeId: 'SYS-001',
|
||||
firstName: 'System',
|
||||
lastName: 'Administrator',
|
||||
firstNameAr: 'مدير',
|
||||
lastNameAr: 'النظام',
|
||||
email: 'admin@system.local',
|
||||
mobile: '+966500000000',
|
||||
dateOfBirth: new Date('1990-01-01'),
|
||||
gender: 'MALE',
|
||||
nationality: 'Saudi',
|
||||
employmentType: 'Full-time',
|
||||
contractType: 'Unlimited',
|
||||
hireDate: new Date('2020-01-01'),
|
||||
departmentId: salesDept.id,
|
||||
positionId: gmPosition.id,
|
||||
basicSalary: 50000,
|
||||
hireDate: new Date(),
|
||||
departmentId: adminDept.id,
|
||||
positionId: sysAdminPosition.id,
|
||||
basicSalary: 0,
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
|
||||
const salesManagerEmployee = await prisma.employee.create({
|
||||
data: {
|
||||
uniqueEmployeeId: 'EMP-2024-0002',
|
||||
firstName: 'Fatima',
|
||||
lastName: 'Al-Zahrani',
|
||||
firstNameAr: 'فاطمة',
|
||||
lastNameAr: 'الزهراني',
|
||||
email: 'sales.manager@atmata.com',
|
||||
mobile: '+966500000002',
|
||||
dateOfBirth: new Date('1985-05-15'),
|
||||
gender: 'FEMALE',
|
||||
nationality: 'Saudi',
|
||||
employmentType: 'Full-time',
|
||||
contractType: 'Unlimited',
|
||||
hireDate: new Date('2021-06-01'),
|
||||
departmentId: salesDept.id,
|
||||
positionId: salesManagerPosition.id,
|
||||
reportingToId: gmEmployee.id,
|
||||
basicSalary: 25000,
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
|
||||
const salesRepEmployee = await prisma.employee.create({
|
||||
data: {
|
||||
uniqueEmployeeId: 'EMP-2024-0003',
|
||||
firstName: 'Mohammed',
|
||||
lastName: 'Al-Qahtani',
|
||||
firstNameAr: 'محمد',
|
||||
lastNameAr: 'القحطاني',
|
||||
email: 'sales.rep@atmata.com',
|
||||
mobile: '+966500000003',
|
||||
dateOfBirth: new Date('1992-08-20'),
|
||||
gender: 'MALE',
|
||||
nationality: 'Saudi',
|
||||
employmentType: 'Full-time',
|
||||
contractType: 'Fixed',
|
||||
hireDate: new Date('2023-01-15'),
|
||||
departmentId: salesDept.id,
|
||||
positionId: salesRepPosition.id,
|
||||
reportingToId: salesManagerEmployee.id,
|
||||
basicSalary: 12000,
|
||||
status: 'ACTIVE',
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created employees');
|
||||
|
||||
// Create Users
|
||||
// Create System Administrator User
|
||||
const hashedPassword = await bcrypt.hash('Admin@123', 10);
|
||||
|
||||
const gmUser = await prisma.user.create({
|
||||
await prisma.user.create({
|
||||
data: {
|
||||
email: 'gm@atmata.com',
|
||||
email: 'admin@system.local',
|
||||
username: 'admin',
|
||||
password: hashedPassword,
|
||||
employeeId: gmEmployee.id,
|
||||
employeeId: sysAdminEmployee.id,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
const salesManagerUser = await prisma.user.create({
|
||||
data: {
|
||||
email: 'sales.manager@atmata.com',
|
||||
username: 'salesmanager',
|
||||
password: hashedPassword,
|
||||
employeeId: salesManagerEmployee.id,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
console.log('✅ Created System Administrator');
|
||||
|
||||
const salesRepUser = await prisma.user.create({
|
||||
data: {
|
||||
email: 'sales.rep@atmata.com',
|
||||
username: 'salesrep',
|
||||
password: hashedPassword,
|
||||
employeeId: salesRepEmployee.id,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created users');
|
||||
|
||||
// Create Contact Categories
|
||||
await prisma.contactCategory.createMany({
|
||||
data: [
|
||||
{ name: 'Customer', nameAr: 'عميل', description: 'Paying customers' },
|
||||
{ name: 'Supplier', nameAr: 'مورد', description: 'Product/Service suppliers' },
|
||||
{ name: 'Partner', nameAr: 'شريك', description: 'Business partners' },
|
||||
{ name: 'Lead', nameAr: 'عميل محتمل', description: 'Potential customers' },
|
||||
{ name: 'Company Employee', nameAr: 'موظف الشركة', description: 'Internal company staff' },
|
||||
],
|
||||
});
|
||||
|
||||
console.log('✅ Created contact categories');
|
||||
|
||||
// Create Product Categories
|
||||
await prisma.productCategory.createMany({
|
||||
data: [
|
||||
{ name: 'Electronics', nameAr: 'إلكترونيات', code: 'ELEC' },
|
||||
{ name: 'Software', nameAr: 'برمجيات', code: 'SOFT' },
|
||||
{ name: 'Services', nameAr: 'خدمات', code: 'SERV' },
|
||||
],
|
||||
});
|
||||
|
||||
console.log('✅ Created product categories');
|
||||
|
||||
// Create Pipelines
|
||||
await prisma.pipeline.create({
|
||||
data: {
|
||||
name: 'B2B Sales Pipeline',
|
||||
nameAr: 'مسار مبيعات الشركات',
|
||||
structure: 'B2B',
|
||||
stages: [
|
||||
{ name: 'OPEN', nameAr: 'مفتوحة', order: 1 },
|
||||
{ name: 'QUALIFIED', nameAr: 'مؤهلة', order: 2 },
|
||||
{ name: 'NEGOTIATION', nameAr: 'تفاوض', order: 3 },
|
||||
{ name: 'PROPOSAL', nameAr: 'عرض سعر', order: 4 },
|
||||
{ name: 'WON', nameAr: 'فازت', order: 5 },
|
||||
{ name: 'LOST', nameAr: 'خسرت', order: 6 },
|
||||
],
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.pipeline.create({
|
||||
data: {
|
||||
name: 'B2C Sales Pipeline',
|
||||
nameAr: 'مسار مبيعات الأفراد',
|
||||
structure: 'B2C',
|
||||
stages: [
|
||||
{ name: 'LEAD', nameAr: 'عميل محتمل', order: 1 },
|
||||
{ name: 'CONTACTED', nameAr: 'تم التواصل', order: 2 },
|
||||
{ name: 'QUALIFIED', nameAr: 'مؤهل', order: 3 },
|
||||
{ name: 'WON', nameAr: 'بيع', order: 4 },
|
||||
{ name: 'LOST', nameAr: 'خسارة', order: 5 },
|
||||
],
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created pipelines');
|
||||
|
||||
// Create sample warehouse
|
||||
await prisma.warehouse.create({
|
||||
data: {
|
||||
code: 'WH-MAIN',
|
||||
name: 'Main Warehouse',
|
||||
nameAr: 'المستودع الرئيسي',
|
||||
type: 'MAIN',
|
||||
city: 'Riyadh',
|
||||
country: 'Saudi Arabia',
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('✅ Created warehouse');
|
||||
|
||||
console.log('\n🎉 Database seeding completed successfully!\n');
|
||||
console.log('📋 Default Users Created:');
|
||||
console.log('\n🎉 Database seeding completed!\n');
|
||||
console.log('📋 System Administrator:');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
||||
console.log('1. General Manager');
|
||||
console.log(' Email: gm@atmata.com');
|
||||
console.log(' Email: admin@system.local');
|
||||
console.log(' Username: admin');
|
||||
console.log(' Password: Admin@123');
|
||||
console.log(' Access: Full System Access');
|
||||
console.log('');
|
||||
console.log('2. Sales Manager');
|
||||
console.log(' Email: sales.manager@atmata.com');
|
||||
console.log(' Password: Admin@123');
|
||||
console.log(' Access: Contacts, CRM with approvals');
|
||||
console.log('');
|
||||
console.log('3. Sales Representative');
|
||||
console.log(' Email: sales.rep@atmata.com');
|
||||
console.log(' Password: Admin@123');
|
||||
console.log(' Access: Basic Contacts and CRM');
|
||||
console.log(' Access: Full system access (all modules)');
|
||||
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
|
||||
}
|
||||
|
||||
@@ -357,4 +146,3 @@ main()
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user