Commit 0184eb2d authored by Mahmoud Aglan's avatar Mahmoud Aglan

Add comprehensive HR demo seeder with full employee/trainer lifecycle data

Covers: 11 employees (6 staff + 4 trainer-employees + 1 resigned), all 12 trainers
with bios/sports/qualifications/availability, 3 months of compensation history,
2 closed payroll periods with payslips, advances in all states, rate history.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 459ea67c
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class HRDemoSeeder extends Seeder
{
public function run(): void
{
$academyId = 1;
$userId = 1; // admin user
$now = now();
// Enable payroll
DB::table('system_settings')->updateOrInsert(
['academy_id' => $academyId, 'key' => 'payroll_enabled'],
['group' => 'hr', 'value' => '1', 'type' => 'boolean', 'description_ar' => 'تفعيل نظام الرواتب', 'is_public' => false, 'created_at' => $now, 'updated_at' => $now]
);
DB::table('system_settings')->updateOrInsert(
['academy_id' => $academyId, 'key' => 'auto_trainer_compensation_enabled'],
['group' => 'hr', 'value' => '1', 'type' => 'boolean', 'description_ar' => 'تفعيل حساب مستحقات المدربين تلقائياً', 'is_public' => false, 'created_at' => $now, 'updated_at' => $now]
);
// ─── Create new People for employees (non-trainer staff) ───
$staffPeople = [
['name_ar' => 'أحمد وجدي', 'name' => 'Ahmed Wagdy', 'phone' => '01055000001', 'gender' => 'male', 'date_of_birth' => '1985-03-12'],
['name_ar' => 'سمر حسني', 'name' => 'Samar Hosny', 'phone' => '01055000002', 'gender' => 'female', 'date_of_birth' => '1990-07-22'],
['name_ar' => 'محمود عادل', 'name' => 'Mahmoud Adel', 'phone' => '01055000003', 'gender' => 'male', 'date_of_birth' => '1988-11-05'],
['name_ar' => 'هند السعيد', 'name' => 'Hend Elsaeed', 'phone' => '01055000004', 'gender' => 'female', 'date_of_birth' => '1992-01-19'],
['name_ar' => 'عبدالرحمن فوزي', 'name' => 'Abdelrahman F.', 'phone' => '01055000005', 'gender' => 'male', 'date_of_birth' => '1995-06-30'],
['name_ar' => 'نورهان ياسر', 'name' => 'Nourhan Yasser', 'phone' => '01055000006', 'gender' => 'female', 'date_of_birth' => '1993-09-14'],
];
$staffPersonIds = [];
foreach ($staffPeople as $p) {
$staffPersonIds[] = DB::table('people')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'name' => $p['name'],
'name_ar' => $p['name_ar'],
'phone' => $p['phone'],
'gender' => $p['gender'],
'date_of_birth' => $p['date_of_birth'],
'nationality' => 'Egyptian',
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
}
// ─── Create Employees (6 staff + 4 trainers as employees) ───
$employees = [
// Non-trainer staff
['person_id' => $staffPersonIds[0], 'number' => 'EMP-001', 'dept' => 'management', 'position' => 'مدير الأكاديمية', 'type' => 'full_time', 'salary' => 2500000, 'branch_id' => 1, 'start' => '2023-01-15'],
['person_id' => $staffPersonIds[1], 'number' => 'EMP-002', 'dept' => 'reception', 'position' => 'موظفة استقبال', 'type' => 'full_time', 'salary' => 800000, 'branch_id' => 1, 'start' => '2023-03-01'],
['person_id' => $staffPersonIds[2], 'number' => 'EMP-003', 'dept' => 'operations', 'position' => 'مشرف العمليات', 'type' => 'full_time', 'salary' => 1500000, 'branch_id' => 2, 'start' => '2023-02-10'],
['person_id' => $staffPersonIds[3], 'number' => 'EMP-004', 'dept' => 'reception', 'position' => 'موظفة استقبال', 'type' => 'part_time', 'salary' => 500000, 'branch_id' => 2, 'start' => '2023-06-01'],
['person_id' => $staffPersonIds[4], 'number' => 'EMP-005', 'dept' => 'maintenance', 'position' => 'فني صيانة', 'type' => 'full_time', 'salary' => 700000, 'branch_id' => 3, 'start' => '2023-09-15'],
['person_id' => $staffPersonIds[5], 'number' => 'EMP-006', 'dept' => 'accounting', 'position' => 'محاسبة', 'type' => 'full_time', 'salary' => 1200000, 'branch_id' => 1, 'start' => '2024-01-01'],
// Trainers who are also employees (salaried trainers)
['person_id' => 4, 'number' => 'EMP-007', 'dept' => 'training', 'position' => 'مدرب أول', 'type' => 'full_time', 'salary' => 1800000, 'branch_id' => 1, 'start' => '2023-01-15'],
['person_id' => 5, 'number' => 'EMP-008', 'dept' => 'training', 'position' => 'مدرب أول', 'type' => 'full_time', 'salary' => 1600000, 'branch_id' => 1, 'start' => '2023-02-01'],
['person_id' => 9, 'number' => 'EMP-009', 'dept' => 'training', 'position' => 'رئيس مدربين', 'type' => 'full_time', 'salary' => 2200000, 'branch_id' => 2, 'start' => '2022-11-01'],
['person_id' => 13, 'number' => 'EMP-010', 'dept' => 'training', 'position' => 'مدرب', 'type' => 'contract', 'salary' => 1000000, 'branch_id' => 3, 'start' => '2024-03-01'],
];
$employeeIds = [];
$managerId = null;
foreach ($employees as $i => $e) {
$id = DB::table('employees')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'person_id' => $e['person_id'],
'employee_number' => $e['number'],
'department' => $e['dept'],
'position' => $e['position'],
'employment_type' => $e['type'],
'start_date' => $e['start'],
'salary_amount' => $e['salary'],
'salary_frequency' => 'monthly',
'working_hours_per_week' => $e['type'] === 'part_time' ? 20.0 : 40.0,
'branch_id' => $e['branch_id'],
'manager_id' => $i > 0 ? $managerId : null,
'status' => 'active',
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
$employeeIds[$e['number']] = $id;
if ($i === 0) $managerId = $id;
}
// Add one resigned employee
$resignedPerson = DB::table('people')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'name' => 'Tarek Hassan',
'name_ar' => 'طارق حسان',
'phone' => '01055000099',
'gender' => 'male',
'date_of_birth' => '1991-04-11',
'nationality' => 'Egyptian',
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
DB::table('employees')->insert([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'person_id' => $resignedPerson,
'employee_number' => 'EMP-011',
'department' => 'training',
'position' => 'مدرب سباحة',
'employment_type' => 'full_time',
'start_date' => '2023-06-01',
'end_date' => '2025-12-31',
'salary_amount' => 900000,
'salary_frequency' => 'monthly',
'working_hours_per_week' => 40.0,
'branch_id' => 2,
'manager_id' => $managerId,
'status' => 'resigned',
'termination_reason' => 'انتقل لأكاديمية أخرى',
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
// One on-leave employee
DB::table('employees')->where('id', $employeeIds['EMP-004'])->update([
'status' => 'on_leave',
'notes' => 'إجازة أمومة — العودة المتوقعة 2026-09-01',
]);
// ─── Link trainers 1,2,6,10 to their employee records ───
// Trainer 1 (person_id=4) → EMP-007, change to hybrid
DB::table('trainers')->where('id', 1)->update([
'employee_id' => $employeeIds['EMP-007'],
'compensation_model' => 'hybrid',
'session_rate' => 15000,
'hourly_rate' => null,
]);
// Trainer 2 (person_id=5) → EMP-008, salary model
DB::table('trainers')->where('id', 2)->update([
'employee_id' => $employeeIds['EMP-008'],
'compensation_model' => 'salary',
]);
// Trainer 6 (person_id=9) → EMP-009, hybrid model (head trainer)
DB::table('trainers')->where('id', 6)->update([
'employee_id' => $employeeIds['EMP-009'],
'compensation_model' => 'hybrid',
'group_rate' => 25000,
]);
// Trainer 10 (person_id=13) → EMP-010, per_group model
DB::table('trainers')->where('id', 10)->update([
'employee_id' => $employeeIds['EMP-010'],
'compensation_model' => 'per_group',
'group_rate' => 20000,
]);
// Update remaining freelancer trainers with proper rates
DB::table('trainers')->where('id', 3)->update(['session_rate' => 12000, 'hourly_rate' => 15000]); // Dina
DB::table('trainers')->where('id', 4)->update(['session_rate' => 18000]); // Tarek
DB::table('trainers')->where('id', 5)->update(['session_rate' => 14000]); // Mariam
DB::table('trainers')->where('id', 7)->update(['session_rate' => 16000]); // Rania
DB::table('trainers')->where('id', 8)->update(['hourly_rate' => 13000]); // Omar
DB::table('trainers')->where('id', 9)->update(['session_rate' => 11000]); // Salma
DB::table('trainers')->where('id', 11)->update(['hourly_rate' => 14000]); // Laila
DB::table('trainers')->where('id', 12)->update(['session_rate' => 17000, 'compensation_model' => 'per_player', 'player_rate' => 5000]); // Karim
// Update all trainers with bios and sports
$trainerMeta = [
1 => ['bio_ar' => 'مدرب كرة قدم محترف — خبرة 10 سنوات', 'sports' => '["football"]', 'specializations' => '["youth","tactics"]'],
2 => ['bio_ar' => 'مدرب لياقة بدنية معتمد — AFC Level 2', 'sports' => '["fitness"]', 'specializations' => '["strength","cardio"]'],
3 => ['bio_ar' => 'مدربة جمباز — بطلة مصر سابقة', 'sports' => '["gymnastics"]', 'specializations' => '["artistic","rhythm"]'],
4 => ['bio_ar' => 'مدرب سباحة — خبرة أكاديمية وتنافسية', 'sports' => '["swimming"]', 'specializations' => '["freestyle","butterfly"]'],
5 => ['bio_ar' => 'مدربة كاراتيه — حزام أسود دان 3', 'sports' => '["karate"]', 'specializations' => '["kata","kumite"]'],
6 => ['bio_ar' => 'رئيس المدربين — مدرب متعدد الرياضات', 'sports' => '["football","fitness"]', 'specializations' => '["management","planning"]'],
7 => ['bio_ar' => 'مدربة باليه وجمباز إيقاعي', 'sports' => '["ballet","gymnastics"]', 'specializations' => '["ballet","flexibility"]'],
8 => ['bio_ar' => 'مدرب كرة سلة — الدوري الممتاز سابقاً', 'sports' => '["basketball"]', 'specializations' => '["shooting","defense"]'],
9 => ['bio_ar' => 'مدربة يوغا وبيلاتس', 'sports' => '["yoga","pilates"]', 'specializations' => '["vinyasa","rehabilitation"]'],
10 => ['bio_ar' => 'مدرب كيك بوكسينج ولياقة قتالية', 'sports' => '["kickboxing"]', 'specializations' => '["combat_fitness","self_defense"]'],
11 => ['bio_ar' => 'مدربة سباحة أطفال — متخصصة في الأعمار الصغيرة', 'sports' => '["swimming"]', 'specializations' => '["kids","water_safety"]'],
12 => ['bio_ar' => 'مدرب تنس — بطل الجمهورية تحت 18', 'sports' => '["tennis"]', 'specializations' => '["singles","juniors"]'],
];
foreach ($trainerMeta as $tId => $meta) {
DB::table('trainers')->where('id', $tId)->update([
'bio_ar' => $meta['bio_ar'],
'sports' => $meta['sports'],
'specializations' => $meta['specializations'],
'total_sessions_conducted' => rand(40, 200),
'rating' => rand(35, 49) / 10,
'max_daily_sessions' => rand(3, 6),
'max_weekly_hours' => rand(20, 35),
]);
}
// ─── Trainer Qualifications ───
$qualifications = [
['trainer_id' => 1, 'name' => 'AFC C License', 'issuer' => 'اتحاد الكرة المصري', 'issue_date' => '2020-06-15', 'expiry_date' => '2027-06-15', 'is_verified' => true],
['trainer_id' => 1, 'name' => 'First Aid CPR', 'issuer' => 'الهلال الأحمر', 'issue_date' => '2024-01-10', 'expiry_date' => '2026-01-10', 'is_verified' => true],
['trainer_id' => 2, 'name' => 'NASM CPT', 'issuer' => 'NASM', 'issue_date' => '2019-03-20', 'expiry_date' => '2027-03-20', 'is_verified' => true],
['trainer_id' => 3, 'name' => 'شهادة تدريب جمباز', 'issuer' => 'الاتحاد المصري للجمباز', 'issue_date' => '2021-09-01', 'expiry_date' => null, 'is_verified' => true],
['trainer_id' => 4, 'name' => 'FINA Swimming Coach', 'issuer' => 'FINA', 'issue_date' => '2022-05-15', 'expiry_date' => '2026-05-15', 'is_verified' => true],
['trainer_id' => 5, 'name' => 'حزام أسود دان 3', 'issuer' => 'الاتحاد العالمي للكاراتيه', 'issue_date' => '2018-11-20', 'expiry_date' => null, 'is_verified' => true],
['trainer_id' => 6, 'name' => 'AFC B License', 'issuer' => 'الاتحاد الآسيوي', 'issue_date' => '2019-08-01', 'expiry_date' => '2027-08-01', 'is_verified' => true],
['trainer_id' => 6, 'name' => 'NSCA CSCS', 'issuer' => 'NSCA', 'issue_date' => '2020-02-15', 'expiry_date' => '2026-02-15', 'is_verified' => true],
['trainer_id' => 7, 'name' => 'RAD Ballet Teacher', 'issuer' => 'Royal Academy of Dance', 'issue_date' => '2021-03-10', 'expiry_date' => null, 'is_verified' => true],
['trainer_id' => 8, 'name' => 'FIBA Coaching License','issuer' => 'FIBA', 'issue_date' => '2020-10-01', 'expiry_date' => '2026-10-01', 'is_verified' => false],
['trainer_id' => 11, 'name' => 'STA Baby Swimming', 'issuer' => 'STA', 'issue_date' => '2023-07-01', 'expiry_date' => '2025-07-01', 'is_verified' => true],
['trainer_id' => 12, 'name' => 'ITF Coaching Level 2','issuer' => 'ITF', 'issue_date' => '2022-01-15', 'expiry_date' => '2027-01-15', 'is_verified' => true],
];
foreach ($qualifications as $q) {
DB::table('trainer_qualifications')->insert([
'trainer_id' => $q['trainer_id'],
'name' => $q['name'],
'issuer' => $q['issuer'],
'issue_date' => $q['issue_date'],
'expiry_date' => $q['expiry_date'],
'is_verified' => $q['is_verified'],
'verified_by' => $q['is_verified'] ? $userId : null,
'verified_at' => $q['is_verified'] ? $now : null,
'created_at' => $now,
]);
}
// ─── Trainer Availability ───
foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as $tId) {
// Available weekdays
foreach ([0, 1, 2, 3, 4] as $day) { // Sun-Thu
DB::table('trainer_availability')->insert([
'trainer_id' => $tId,
'type' => 'available',
'day_of_week' => $day,
'start_time' => $tId <= 6 ? '08:00' : '14:00',
'end_time' => $tId <= 6 ? '16:00' : '22:00',
'created_at' => $now,
]);
}
// Some prefer specific times
if ($tId % 3 === 0) {
DB::table('trainer_availability')->insert([
'trainer_id' => $tId,
'type' => 'preferred',
'day_of_week' => 5, // Friday
'start_time' => '16:00',
'end_time' => '20:00',
'created_at' => $now,
]);
}
// Some unavailable specific dates
if ($tId % 4 === 0) {
DB::table('trainer_availability')->insert([
'trainer_id' => $tId,
'type' => 'unavailable',
'specific_date' => '2026-07-15',
'start_time' => '08:00',
'end_time' => '22:00',
'reason' => 'إجازة شخصية',
'created_at' => $now,
]);
}
}
// ─── Trainer Compensations (last 3 months of history) ───
$compensationData = [];
foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as $tId) {
$trainer = DB::table('trainers')->where('id', $tId)->first();
$model = $trainer->compensation_model;
for ($monthsAgo = 2; $monthsAgo >= 0; $monthsAgo--) {
$month = now()->subMonths($monthsAgo);
$sessionsThisMonth = rand(12, 24);
for ($s = 0; $s < $sessionsThisMonth; $s++) {
$day = rand(1, min(28, $month->daysInMonth));
$date = $month->copy()->day($day)->toDateString();
$type = match ($model) {
'per_session', 'hybrid' => 'session_pay',
'per_group' => 'group_pay',
'per_player' => 'player_pay',
'hourly' => 'session_pay',
default => 'session_pay',
};
$rate = match ($model) {
'hourly' => $trainer->hourly_rate ?? 12000,
'per_group' => $trainer->group_rate ?? 20000,
'per_player' => $trainer->player_rate ?? 5000,
default => $trainer->session_rate ?? 15000,
};
$quantity = $model === 'per_player' ? rand(5, 15) : 1;
$amount = (int) ($rate * $quantity);
$status = $monthsAgo > 0 ? 'paid' : (rand(0, 3) === 0 ? 'pending' : 'approved');
$compensationData[] = [
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'trainer_id' => $tId,
'date' => $date,
'type' => $type,
'description' => "حصة تدريبية — {$date}",
'quantity' => $quantity,
'rate' => $rate,
'amount' => $amount,
'status' => $status,
'approved_by' => $status !== 'pending' ? $userId : null,
'approved_at' => $status !== 'pending' ? $now : null,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
];
}
// Add a bonus for some trainers
if ($tId % 3 === 1 && $monthsAgo === 1) {
$compensationData[] = [
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'trainer_id' => $tId,
'date' => $month->copy()->day(28)->toDateString(),
'type' => 'bonus',
'description' => 'مكافأة أداء متميز',
'quantity' => 1,
'rate' => 50000,
'amount' => 50000,
'status' => 'paid',
'approved_by' => $userId,
'approved_at' => $now,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
];
}
// Add a penalty for one trainer
if ($tId === 8 && $monthsAgo === 0) {
$compensationData[] = [
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'trainer_id' => $tId,
'date' => $month->copy()->day(5)->toDateString(),
'type' => 'penalty',
'description' => 'خصم تأخير — 3 مرات في الأسبوع',
'quantity' => 1,
'rate' => 10000,
'amount' => 10000,
'status' => 'approved',
'approved_by' => $userId,
'approved_at' => $now,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
];
}
}
}
// Insert in chunks
foreach (array_chunk($compensationData, 100) as $chunk) {
DB::table('trainer_compensations')->insert($chunk);
}
// ─── Payroll Periods (2 closed months + 1 open current) ───
$periods = [];
for ($m = 2; $m >= 0; $m--) {
$start = now()->subMonths($m)->startOfMonth()->toDateString();
$end = now()->subMonths($m)->endOfMonth()->toDateString();
$status = $m > 0 ? 'closed' : 'open';
$periodId = DB::table('payroll_periods')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'period_start' => $start,
'period_end' => $end,
'status' => $status,
'total_gross' => 0,
'total_deductions' => 0,
'total_net' => 0,
'payslip_count' => 0,
'approved_by' => $m > 0 ? $userId : null,
'approved_at' => $m > 0 ? $now : null,
'closed_at' => $m > 0 ? $now : null,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
$periods[$m] = $periodId;
}
// ─── Payslips for closed periods ───
$payslipNum = 1;
foreach ([2, 1] as $m) {
$periodId = $periods[$m];
$periodTotalGross = 0;
$periodTotalDeductions = 0;
$periodTotalNet = 0;
$slipCount = 0;
foreach ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] as $tId) {
$trainer = DB::table('trainers')->where('id', $tId)->first();
$employee = $trainer->employee_id ? DB::table('employees')->where('id', $trainer->employee_id)->first() : null;
$baseSalary = $employee ? ($employee->salary_amount ?? 0) : 0;
$month = now()->subMonths($m);
// Sum session earnings for this trainer/month
$sessionEarnings = DB::table('trainer_compensations')
->where('trainer_id', $tId)
->where('status', 'paid')
->whereIn('type', ['session_pay', 'group_pay', 'player_pay', 'revenue_share', 'overtime', 'substitute'])
->whereBetween('date', [$month->startOfMonth()->toDateString(), $month->endOfMonth()->toDateString()])
->sum('amount');
$bonuses = DB::table('trainer_compensations')
->where('trainer_id', $tId)
->where('status', 'paid')
->where('type', 'bonus')
->whereBetween('date', [$month->startOfMonth()->toDateString(), $month->endOfMonth()->toDateString()])
->sum('amount');
$penalties = DB::table('trainer_compensations')
->where('trainer_id', $tId)
->where('status', '!=', 'cancelled')
->where('type', 'penalty')
->whereBetween('date', [$month->startOfMonth()->toDateString(), $month->endOfMonth()->toDateString()])
->sum('amount');
$gross = $baseSalary + $sessionEarnings + $bonuses;
$taxAmount = (int) ($gross * 0.05);
$insuranceAmount = $employee ? 50000 : 0; // 500 EGP insurance for employees
$totalDeductions = $penalties + $taxAmount + $insuranceAmount;
$net = max(0, $gross - $totalDeductions);
$payslipId = DB::table('payslips')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'trainer_id' => $tId,
'payroll_period_id' => $periodId,
'payslip_number' => 'PS-' . str_pad($payslipNum++, 4, '0', STR_PAD_LEFT),
'base_amount' => $baseSalary,
'session_earnings' => $sessionEarnings,
'bonuses' => $bonuses,
'penalties' => $penalties,
'advances_deducted' => 0,
'tax_amount' => $taxAmount,
'insurance_amount' => $insuranceAmount,
'other_deductions' => 0,
'gross_amount' => $gross,
'total_deductions' => $totalDeductions,
'net_amount' => $net,
'status' => 'paid',
'approved_by' => $userId,
'approved_at' => $now,
'paid_at' => $now,
'payment_method' => $employee ? 'bank_transfer' : 'cash',
'payment_reference' => $employee ? 'TRF-' . now()->format('Ymd') . '-' . $tId : null,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
// Payslip items
$items = [];
$sortOrder = 0;
if ($baseSalary > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'base_salary', 'description' => 'الراتب الأساسي', 'quantity' => 1, 'rate' => $baseSalary, 'amount' => $baseSalary, 'is_deduction' => false, 'metadata' => '{}', 'sort_order' => $sortOrder++, 'created_at' => $now, 'updated_at' => $now];
}
if ($sessionEarnings > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'session_pay', 'description' => 'أجر الحصص', 'quantity' => 1, 'rate' => $sessionEarnings, 'amount' => $sessionEarnings, 'is_deduction' => false, 'metadata' => '{}', 'sort_order' => $sortOrder++, 'created_at' => $now, 'updated_at' => $now];
}
if ($bonuses > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'bonus', 'description' => 'مكافآت', 'quantity' => 1, 'rate' => $bonuses, 'amount' => $bonuses, 'is_deduction' => false, 'metadata' => '{}', 'sort_order' => $sortOrder++, 'created_at' => $now, 'updated_at' => $now];
}
if ($penalties > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'penalty', 'description' => 'خصومات', 'quantity' => 1, 'rate' => $penalties, 'amount' => $penalties, 'is_deduction' => true, 'metadata' => '{}', 'sort_order' => $sortOrder++, 'created_at' => $now, 'updated_at' => $now];
}
if ($taxAmount > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'tax', 'description' => 'ضريبة دخل 5%', 'quantity' => 1, 'rate' => $taxAmount, 'amount' => $taxAmount, 'is_deduction' => true, 'metadata' => '{}', 'sort_order' => $sortOrder++, 'created_at' => $now, 'updated_at' => $now];
}
if ($insuranceAmount > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'insurance', 'description' => 'تأمين اجتماعي', 'quantity' => 1, 'rate' => $insuranceAmount, 'amount' => $insuranceAmount, 'is_deduction' => true, 'metadata' => '{}', 'sort_order' => $sortOrder++, 'created_at' => $now, 'updated_at' => $now];
}
if ($items) {
DB::table('payslip_items')->insert($items);
}
$periodTotalGross += $gross;
$periodTotalDeductions += $totalDeductions;
$periodTotalNet += $net;
$slipCount++;
}
// Update period totals
DB::table('payroll_periods')->where('id', $periodId)->update([
'total_gross' => $periodTotalGross,
'total_deductions' => $periodTotalDeductions,
'total_net' => $periodTotalNet,
'payslip_count' => $slipCount,
]);
}
// ─── Trainer Advances (سلف) ───
$advances = [
// Active advance — trainer 1 took 5000 EGP, paying back in 5 installments
['trainer_id' => 1, 'amount' => 500000, 'remaining' => 300000, 'installment' => 100000, 'count' => 5, 'paid' => 2, 'status' => 'active', 'date' => '2026-05-01', 'reason' => 'سلفة شخصية — مصاريف طبية'],
// Active advance — trainer 4 took 3000 EGP
['trainer_id' => 4, 'amount' => 300000, 'remaining' => 200000, 'installment' => 100000, 'count' => 3, 'paid' => 1, 'status' => 'active', 'date' => '2026-06-01', 'reason' => 'سلفة — مصاريف سفر'],
// Fully deducted advance — trainer 6 repaid everything
['trainer_id' => 6, 'amount' => 200000, 'remaining' => 0, 'installment' => 100000, 'count' => 2, 'paid' => 2, 'status' => 'fully_deducted', 'date' => '2026-03-01', 'reason' => 'سلفة شخصية'],
// Paused advance — trainer 8 paused repayment
['trainer_id' => 8, 'amount' => 400000, 'remaining' => 300000, 'installment' => 100000, 'count' => 4, 'paid' => 1, 'status' => 'paused', 'date' => '2026-04-01', 'reason' => 'سلفة طوارئ'],
// Cancelled advance
['trainer_id' => 12, 'amount' => 150000, 'remaining' => 150000, 'installment' => 75000, 'count' => 2, 'paid' => 0, 'status' => 'cancelled', 'date' => '2026-06-15', 'reason' => 'تم إلغاء الطلب بناءً على رغبة المدرب'],
];
foreach ($advances as $adv) {
DB::table('trainer_advances')->insert([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'trainer_id' => $adv['trainer_id'],
'amount' => $adv['amount'],
'remaining_balance' => $adv['remaining'],
'installment_amount' => $adv['installment'],
'installments_count' => $adv['count'],
'installments_paid' => $adv['paid'],
'reason' => $adv['reason'],
'status' => $adv['status'],
'issued_date' => $adv['date'],
'expected_completion_date' => now()->addMonths($adv['count'] - $adv['paid'])->toDateString(),
'approved_by' => $userId,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
}
// ─── Rate History ───
$rateChanges = [
['trainer_id' => 1, 'field' => 'session_rate', 'old' => '12000', 'new' => '15000', 'date' => '2026-01-01', 'notes' => 'زيادة سنوية'],
['trainer_id' => 3, 'field' => 'hourly_rate', 'old' => '12000', 'new' => '15000', 'date' => '2026-04-01', 'notes' => 'ترقية بعد 6 أشهر'],
['trainer_id' => 6, 'field' => 'group_rate', 'old' => '20000', 'new' => '25000', 'date' => '2026-03-01', 'notes' => 'ترقية لرئيس مدربين'],
['trainer_id' => 12, 'field' => 'player_rate', 'old' => '4000', 'new' => '5000', 'date' => '2026-05-01', 'notes' => 'زيادة بناءً على الأداء'],
['trainer_id' => 4, 'field' => 'session_rate', 'old' => '15000', 'new' => '18000', 'date' => '2026-02-01', 'notes' => 'حصول على شهادة جديدة'],
];
foreach ($rateChanges as $rc) {
DB::table('trainer_rate_history')->insert([
'academy_id' => $academyId,
'trainer_id' => $rc['trainer_id'],
'field' => $rc['field'],
'old_value' => $rc['old'],
'new_value' => $rc['new'],
'effective_from' => $rc['date'],
'changed_by' => $userId,
'notes' => $rc['notes'],
'created_at' => $now,
'updated_at' => $now,
]);
}
$this->command->info('HR Demo data seeded successfully!');
$this->command->info("- 7 non-trainer employees (1 resigned, 1 on-leave)");
$this->command->info("- 4 trainers linked to employee records (salaried/hybrid)");
$this->command->info("- 8 freelancer trainers with various compensation models");
$this->command->info("- 12 trainer qualifications");
$this->command->info("- Availability schedules for all trainers");
$this->command->info("- 3 months of compensation records (~600+ records)");
$this->command->info("- 2 closed payroll periods with payslips + 1 open period");
$this->command->info("- 5 advances (active, paused, fully_deducted, cancelled)");
$this->command->info("- 5 rate change history records");
$this->command->info("- Payroll system ENABLED");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment