Commit 0efcf003 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Fix HR seeder: create branches/people/trainers from scratch, idempotent cleanup

Production had no trainers/employees and only 1 branch. Rewrote seeder to be
fully self-contained: creates 2 new branches, 19 people, 11 employees, 12 trainers,
then populates all HR tables. Cleans up prior data on re-run.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 0184eb2d
......@@ -11,10 +11,22 @@ class HRDemoSeeder extends Seeder
public function run(): void
{
$academyId = 1;
$userId = 1; // admin user
$userId = 1;
$now = now();
// Enable payroll
// Clean up any orphan data from previous failed runs
DB::table('trainer_rate_history')->where('academy_id', $academyId)->delete();
DB::table('trainer_advances')->where('academy_id', $academyId)->delete();
DB::table('payslip_items')->whereIn('payslip_id', DB::table('payslips')->where('academy_id', $academyId)->pluck('id'))->delete();
DB::table('payslips')->where('academy_id', $academyId)->delete();
DB::table('payroll_periods')->where('academy_id', $academyId)->delete();
DB::table('trainer_compensations')->where('academy_id', $academyId)->delete();
DB::table('trainer_availability')->whereIn('trainer_id', DB::table('trainers')->where('academy_id', $academyId)->pluck('id'))->delete();
DB::table('trainer_qualifications')->whereIn('trainer_id', DB::table('trainers')->where('academy_id', $academyId)->pluck('id'))->delete();
DB::table('trainers')->where('academy_id', $academyId)->delete();
DB::table('employees')->where('academy_id', $academyId)->delete();
// ─── Enable payroll settings ───
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]
......@@ -24,47 +36,137 @@ public function run(): void
['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'],
];
// ─── Create branches if missing ───
$branch1 = DB::table('branches')->where('academy_id', $academyId)->where('name_ar', 'المعادي')->first();
if (!$branch1) {
$branch1Id = DB::table('branches')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'name' => 'Maadi',
'name_ar' => 'المعادي',
'code' => 'MAA',
'phone' => '0225123456',
'address' => 'شارع 9 — المعادي',
'city' => 'القاهرة',
'governorate' => 'القاهرة',
'is_active' => true,
'created_at' => $now,
'updated_at' => $now,
]);
} else {
$branch1Id = $branch1->id;
}
$staffPersonIds = [];
foreach ($staffPeople as $p) {
$staffPersonIds[] = DB::table('people')->insertGetId([
$branch2 = DB::table('branches')->where('academy_id', $academyId)->where('name_ar', 'مصر الجديدة')->first();
if (!$branch2) {
$branch2Id = DB::table('branches')->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,
'name' => 'Heliopolis',
'name_ar' => 'مصر الجديدة',
'code' => 'HEL',
'phone' => '0224567890',
'address' => 'شارع الميرغني — مصر الجديدة',
'city' => 'القاهرة',
'governorate' => 'القاهرة',
'is_active' => true,
'created_at' => $now,
'updated_at' => $now,
]);
} else {
$branch2Id = $branch2->id;
}
// Use existing branch 3 (Sheikh Zayed)
$branch3Id = 3;
$branchIds = [$branch1Id, $branch2Id, $branch3Id];
// ─── Create People for staff (non-trainers) ───
$staffData = [
['name_ar' => 'أحمد وجدي حسن', 'name' => 'Ahmed Wagdy', 'phone' => '01055000001', 'gender' => 'male', 'dob' => '1985-03-12'],
['name_ar' => 'سمر حسني إبراهيم', 'name' => 'Samar Hosny', 'phone' => '01055000002', 'gender' => 'female', 'dob' => '1990-07-22'],
['name_ar' => 'محمود عادل سيد', 'name' => 'Mahmoud Adel', 'phone' => '01055000003', 'gender' => 'male', 'dob' => '1988-11-05'],
['name_ar' => 'هند السعيد محمد', 'name' => 'Hend Elsaeed', 'phone' => '01055000004', 'gender' => 'female', 'dob' => '1992-01-19'],
['name_ar' => 'عبدالرحمن فوزي خالد', 'name' => 'Abdelrahman F.', 'phone' => '01055000005', 'gender' => 'male', 'dob' => '1995-06-30'],
['name_ar' => 'نورهان ياسر أحمد', 'name' => 'Nourhan Yasser', 'phone' => '01055000006', 'gender' => 'female', 'dob' => '1993-09-14'],
['name_ar' => 'طارق حسان محمود', 'name' => 'Tarek Hassan', 'phone' => '01055000099', 'gender' => 'male', 'dob' => '1991-04-11'],
];
$staffPersonIds = [];
foreach ($staffData as $s) {
$existing = DB::table('people')->where('academy_id', $academyId)->where('phone', $s['phone'])->first();
if ($existing) {
$staffPersonIds[] = $existing->id;
} else {
$staffPersonIds[] = DB::table('people')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'name' => $s['name'],
'name_ar' => $s['name_ar'],
'phone' => $s['phone'],
'gender' => $s['gender'],
'date_of_birth' => $s['dob'],
'nationality' => 'Egyptian',
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
// ─── Create Employees (6 staff + 4 trainers as employees) ───
// ─── Create People for trainers ───
$trainerPeople = [
['name_ar' => 'كريم عبدالله حسن', 'name' => 'Karim Abdullah', 'phone' => '01099000001', 'gender' => 'male', 'dob' => '1990-05-20'],
['name_ar' => 'أحمد سمير فتحي', 'name' => 'Ahmed Samir', 'phone' => '01099000002', 'gender' => 'male', 'dob' => '1988-08-15'],
['name_ar' => 'دينا محمد علي', 'name' => 'Dina Mohamed', 'phone' => '01099000003', 'gender' => 'female', 'dob' => '1992-03-10'],
['name_ar' => 'طارق حسام الدين', 'name' => 'Tarek Hossam', 'phone' => '01099000004', 'gender' => 'male', 'dob' => '1985-12-01'],
['name_ar' => 'مريم خالد إبراهيم', 'name' => 'Mariam Khaled', 'phone' => '01099000005', 'gender' => 'female', 'dob' => '1994-07-25'],
['name_ar' => 'حسام الدين محمود', 'name' => 'Hossam Mahmoud', 'phone' => '01099000006', 'gender' => 'male', 'dob' => '1983-02-14'],
['name_ar' => 'رانيا سعيد أحمد', 'name' => 'Rania Saeed', 'phone' => '01099000007', 'gender' => 'female', 'dob' => '1991-11-30'],
['name_ar' => 'عمر حسن محمد', 'name' => 'Omar Hassan', 'phone' => '01099000008', 'gender' => 'male', 'dob' => '1989-06-18'],
['name_ar' => 'سلمى يوسف علي', 'name' => 'Salma Youssef', 'phone' => '01099000009', 'gender' => 'female', 'dob' => '1995-09-05'],
['name_ar' => 'يوسف عماد حسين', 'name' => 'Youssef Emad', 'phone' => '01099000010', 'gender' => 'male', 'dob' => '1993-01-22'],
['name_ar' => 'ليلى أسامة فتحي', 'name' => 'Laila Osama', 'phone' => '01099000011', 'gender' => 'female', 'dob' => '1996-04-16'],
['name_ar' => 'كريم وليد سامي', 'name' => 'Karim Waleed', 'phone' => '01099000012', 'gender' => 'male', 'dob' => '1991-10-08'],
];
$trainerPersonIds = [];
foreach ($trainerPeople as $t) {
$existing = DB::table('people')->where('academy_id', $academyId)->where('phone', $t['phone'])->first();
if ($existing) {
$trainerPersonIds[] = $existing->id;
} else {
$trainerPersonIds[] = DB::table('people')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'name' => $t['name'],
'name_ar' => $t['name_ar'],
'phone' => $t['phone'],
'gender' => $t['gender'],
'date_of_birth' => $t['dob'],
'nationality' => 'Egyptian',
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
}
}
// ─── Create Employees ───
// 6 staff employees + 4 trainer-employees = 10 active + 1 resigned
$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'],
['person_id' => $staffPersonIds[0], 'number' => 'EMP-001', 'dept' => 'management', 'position' => 'مدير الأكاديمية', 'type' => 'full_time', 'salary' => 2500000, 'branch' => $branch1Id, 'start' => '2023-01-15'],
['person_id' => $staffPersonIds[1], 'number' => 'EMP-002', 'dept' => 'reception', 'position' => 'موظفة استقبال', 'type' => 'full_time', 'salary' => 800000, 'branch' => $branch1Id, 'start' => '2023-03-01'],
['person_id' => $staffPersonIds[2], 'number' => 'EMP-003', 'dept' => 'operations', 'position' => 'مشرف العمليات', 'type' => 'full_time', 'salary' => 1500000, 'branch' => $branch2Id, 'start' => '2023-02-10'],
['person_id' => $staffPersonIds[3], 'number' => 'EMP-004', 'dept' => 'reception', 'position' => 'موظفة استقبال', 'type' => 'part_time', 'salary' => 500000, 'branch' => $branch2Id, 'start' => '2023-06-01'],
['person_id' => $staffPersonIds[4], 'number' => 'EMP-005', 'dept' => 'maintenance', 'position' => 'فني صيانة', 'type' => 'full_time', 'salary' => 700000, 'branch' => $branch3Id, 'start' => '2023-09-15'],
['person_id' => $staffPersonIds[5], 'number' => 'EMP-006', 'dept' => 'accounting', 'position' => 'محاسبة', 'type' => 'full_time', 'salary' => 1200000, 'branch' => $branch1Id, 'start' => '2024-01-01'],
// Trainer-employees (salaried trainers)
['person_id' => $trainerPersonIds[0], 'number' => 'EMP-007', 'dept' => 'training', 'position' => 'مدرب أول', 'type' => 'full_time', 'salary' => 1800000, 'branch' => $branch1Id, 'start' => '2023-01-15'],
['person_id' => $trainerPersonIds[1], 'number' => 'EMP-008', 'dept' => 'training', 'position' => 'مدرب أول', 'type' => 'full_time', 'salary' => 1600000, 'branch' => $branch1Id, 'start' => '2023-02-01'],
['person_id' => $trainerPersonIds[5], 'number' => 'EMP-009', 'dept' => 'training', 'position' => 'رئيس مدربين', 'type' => 'full_time', 'salary' => 2200000, 'branch' => $branch2Id, 'start' => '2022-11-01'],
['person_id' => $trainerPersonIds[9], 'number' => 'EMP-010', 'dept' => 'training', 'position' => 'مدرب', 'type' => 'contract', 'salary' => 1000000, 'branch' => $branch3Id, 'start' => '2024-03-01'],
];
$employeeIds = [];
......@@ -82,7 +184,7 @@ public function run(): void
'salary_amount' => $e['salary'],
'salary_frequency' => 'monthly',
'working_hours_per_week' => $e['type'] === 'part_time' ? 20.0 : 40.0,
'branch_id' => $e['branch_id'],
'branch_id' => $e['branch'],
'manager_id' => $i > 0 ? $managerId : null,
'status' => 'active',
'created_by' => $userId,
......@@ -93,24 +195,11 @@ public function run(): void
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,
]);
// Add resigned employee
DB::table('employees')->insert([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'person_id' => $resignedPerson,
'person_id' => $staffPersonIds[6],
'employee_number' => 'EMP-011',
'department' => 'training',
'position' => 'مدرب سباحة',
......@@ -120,7 +209,7 @@ public function run(): void
'salary_amount' => 900000,
'salary_frequency' => 'monthly',
'working_hours_per_week' => 40.0,
'branch_id' => 2,
'branch_id' => $branch2Id,
'manager_id' => $managerId,
'status' => 'resigned',
'termination_reason' => 'انتقل لأكاديمية أخرى',
......@@ -129,130 +218,126 @@ public function run(): void
'updated_at' => $now,
]);
// One on-leave employee
// Set one on-leave
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,
]);
// ─── Create Trainers ───
// 4 employee-based + 8 freelancers = 12 total
$trainerDefs = [
// Employee-based trainers (indices 0, 1, 5, 9 of trainerPersonIds → linked to EMP-007..010)
['idx' => 0, 'emp' => 'EMP-007', 'num' => 'TR-001', 'model' => 'hybrid', 'session' => 15000, 'hourly' => null, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 1, 'emp' => 'EMP-008', 'num' => 'TR-002', 'model' => 'salary', 'session' => null, 'hourly' => null, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 5, 'emp' => 'EMP-009', 'num' => 'TR-003', 'model' => 'hybrid', 'session' => null, 'hourly' => null, 'group' => 25000, 'player' => null, 'rev' => null],
['idx' => 9, 'emp' => 'EMP-010', 'num' => 'TR-004', 'model' => 'per_group', 'session' => null, 'hourly' => null, 'group' => 20000, 'player' => null, 'rev' => null],
// Freelancer trainers (indices 2,3,4,6,7,8,10,11)
['idx' => 2, 'emp' => null, 'num' => 'TR-005', 'model' => 'per_session', 'session' => 12000, 'hourly' => 15000, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 3, 'emp' => null, 'num' => 'TR-006', 'model' => 'per_session', 'session' => 18000, 'hourly' => null, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 4, 'emp' => null, 'num' => 'TR-007', 'model' => 'per_session', 'session' => 14000, 'hourly' => null, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 6, 'emp' => null, 'num' => 'TR-008', 'model' => 'per_session', 'session' => 16000, 'hourly' => null, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 7, 'emp' => null, 'num' => 'TR-009', 'model' => 'hourly', 'session' => null, 'hourly' => 13000, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 8, 'emp' => null, 'num' => 'TR-010', 'model' => 'per_session', 'session' => 11000, 'hourly' => null, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 10, 'emp' => null, 'num' => 'TR-011', 'model' => 'hourly', 'session' => null, 'hourly' => 14000, 'group' => null, 'player' => null, 'rev' => null],
['idx' => 11, 'emp' => null, 'num' => 'TR-012', 'model' => 'per_player', 'session' => 17000, 'hourly' => null, 'group' => null, 'player' => 5000, 'rev' => null],
];
// 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"]'],
$trainerBios = [
0 => ['bio_ar' => 'مدرب كرة قدم محترف — خبرة 10 سنوات', 'sports' => '["football"]', 'spec' => '["youth","tactics"]'],
1 => ['bio_ar' => 'مدرب لياقة بدنية معتمد — AFC Level 2', 'sports' => '["fitness"]', 'spec' => '["strength","cardio"]'],
2 => ['bio_ar' => 'مدربة جمباز — بطلة مصر سابقة', 'sports' => '["gymnastics"]', 'spec' => '["artistic","rhythm"]'],
3 => ['bio_ar' => 'مدرب سباحة — خبرة أكاديمية وتنافسية', 'sports' => '["swimming"]', 'spec' => '["freestyle","butterfly"]'],
4 => ['bio_ar' => 'مدربة كاراتيه — حزام أسود دان 3', 'sports' => '["karate"]', 'spec' => '["kata","kumite"]'],
5 => ['bio_ar' => 'رئيس المدربين — مدرب متعدد الرياضات', 'sports' => '["football","fitness"]', 'spec' => '["management","planning"]'],
6 => ['bio_ar' => 'مدربة باليه وجمباز إيقاعي', 'sports' => '["ballet","gymnastics"]','spec' => '["ballet","flexibility"]'],
7 => ['bio_ar' => 'مدرب كرة سلة — الدوري الممتاز سابقاً', 'sports' => '["basketball"]', 'spec' => '["shooting","defense"]'],
8 => ['bio_ar' => 'مدربة يوغا وبيلاتس', 'sports' => '["yoga","pilates"]', 'spec' => '["vinyasa","rehabilitation"]'],
9 => ['bio_ar' => 'مدرب كيك بوكسينج ولياقة قتالية', 'sports' => '["kickboxing"]', 'spec' => '["combat_fitness","self_defense"]'],
10 => ['bio_ar' => 'مدربة سباحة أطفال — متخصصة في الأعمار الصغيرة', 'sports' => '["swimming"]', 'spec' => '["kids","water_safety"]'],
11 => ['bio_ar' => 'مدرب تنس — بطل الجمهورية تحت 18', 'sports' => '["tennis"]', 'spec' => '["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),
$trainerIds = [];
foreach ($trainerDefs as $i => $td) {
$bio = $trainerBios[$i];
$trainerIds[$i] = DB::table('trainers')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'employee_id' => $td['emp'] ? $employeeIds[$td['emp']] : null,
'person_id' => $trainerPersonIds[$td['idx']],
'trainer_number' => $td['num'],
'bio_ar' => $bio['bio_ar'],
'sports' => $bio['sports'],
'specializations' => $bio['spec'],
'compensation_model' => $td['model'],
'session_rate' => $td['session'],
'hourly_rate' => $td['hourly'],
'group_rate' => $td['group'],
'player_rate' => $td['player'],
'revenue_share_percent' => $td['rev'],
'rating' => rand(35, 49) / 10,
'total_sessions_conducted' => rand(40, 200),
'max_daily_sessions' => rand(3, 6),
'max_weekly_hours' => rand(20, 35),
'status' => 'active',
'created_at' => $now,
'updated_at' => $now,
]);
}
// ─── 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],
[0, 'AFC C License', 'اتحاد الكرة المصري', '2020-06-15', '2027-06-15', true],
[0, 'First Aid CPR', 'الهلال الأحمر', '2024-01-10', '2026-01-10', true],
[1, 'NASM CPT', 'NASM', '2019-03-20', '2027-03-20', true],
[2, 'شهادة تدريب جمباز', 'الاتحاد المصري للجمباز', '2021-09-01', null, true],
[3, 'FINA Swimming Coach', 'FINA', '2022-05-15', '2026-05-15', true],
[4, 'حزام أسود دان 3', 'الاتحاد العالمي للكاراتيه', '2018-11-20', null, true],
[5, 'AFC B License', 'الاتحاد الآسيوي', '2019-08-01', '2027-08-01', true],
[5, 'NSCA CSCS', 'NSCA', '2020-02-15', '2026-02-15', true],
[6, 'RAD Ballet Teacher', 'Royal Academy of Dance', '2021-03-10', null, true],
[7, 'FIBA Coaching License','FIBA', '2020-10-01', '2026-10-01', false],
[10,'STA Baby Swimming', 'STA', '2023-07-01', '2025-07-01', true],
[11,'ITF Coaching Level 2', 'ITF', '2022-01-15', '2027-01-15', true],
];
foreach ($qualifications as $q) {
foreach ($qualifications as [$idx, $name, $issuer, $issued, $expiry, $verified]) {
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,
'trainer_id' => $trainerIds[$idx],
'name' => $name,
'issuer' => $issuer,
'issue_date' => $issued,
'expiry_date' => $expiry,
'is_verified' => $verified,
'verified_by' => $verified ? $userId : null,
'verified_at' => $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
foreach ($trainerIds as $i => $tId) {
foreach ([0, 1, 2, 3, 4] as $day) {
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',
'start_time' => $i < 6 ? '08:00' : '14:00',
'end_time' => $i < 6 ? '16:00' : '22:00',
'created_at' => $now,
]);
}
// Some prefer specific times
if ($tId % 3 === 0) {
if ($i % 3 === 0) {
DB::table('trainer_availability')->insert([
'trainer_id' => $tId,
'type' => 'preferred',
'day_of_week' => 5, // Friday
'day_of_week' => 5,
'start_time' => '16:00',
'end_time' => '20:00',
'created_at' => $now,
]);
}
// Some unavailable specific dates
if ($tId % 4 === 0) {
if ($i % 4 === 0) {
DB::table('trainer_availability')->insert([
'trainer_id' => $tId,
'type' => 'unavailable',
......@@ -265,17 +350,17 @@ public function run(): void
}
}
// ─── Trainer Compensations (last 3 months of history) ───
// ─── Trainer Compensations (3 months 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;
foreach ($trainerIds as $i => $tId) {
$td = $trainerDefs[$i];
$model = $td['model'];
for ($monthsAgo = 2; $monthsAgo >= 0; $monthsAgo--) {
$month = now()->subMonths($monthsAgo);
$sessionsThisMonth = rand(12, 24);
$sessions = rand(12, 24);
for ($s = 0; $s < $sessionsThisMonth; $s++) {
for ($s = 0; $s < $sessions; $s++) {
$day = rand(1, min(28, $month->daysInMonth));
$date = $month->copy()->day($day)->toDateString();
......@@ -288,15 +373,14 @@ public function run(): void
};
$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,
'hourly' => $td['hourly'] ?? 12000,
'per_group' => $td['group'] ?? 20000,
'per_player' => $td['player'] ?? 5000,
default => $td['session'] ?? 15000,
};
$quantity = $model === 'per_player' ? rand(5, 15) : 1;
$amount = (int) ($rate * $quantity);
$status = $monthsAgo > 0 ? 'paid' : (rand(0, 3) === 0 ? 'pending' : 'approved');
$compensationData[] = [
......@@ -318,8 +402,8 @@ public function run(): void
];
}
// Add a bonus for some trainers
if ($tId % 3 === 1 && $monthsAgo === 1) {
// Bonus for some
if ($i % 3 === 0 && $monthsAgo === 1) {
$compensationData[] = [
'uuid' => Str::uuid(),
'academy_id' => $academyId,
......@@ -339,8 +423,8 @@ public function run(): void
];
}
// Add a penalty for one trainer
if ($tId === 8 && $monthsAgo === 0) {
// Penalty for trainer 7 (basketball)
if ($i === 7 && $monthsAgo === 0) {
$compensationData[] = [
'uuid' => Str::uuid(),
'academy_id' => $academyId,
......@@ -362,19 +446,18 @@ public function run(): void
}
}
// Insert in chunks
foreach (array_chunk($compensationData, 100) as $chunk) {
DB::table('trainer_compensations')->insert($chunk);
}
// ─── Payroll Periods (2 closed months + 1 open current) ───
// ─── Payroll Periods ───
$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([
$periods[$m] = DB::table('payroll_periods')->insertGetId([
'uuid' => Str::uuid(),
'academy_id' => $academyId,
'period_start' => $start,
......@@ -391,52 +474,55 @@ public function run(): void
'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;
$periodGross = 0;
$periodDed = 0;
$periodNet = 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;
foreach ($trainerIds as $i => $tId) {
$td = $trainerDefs[$i];
$empId = $td['emp'] ? $employeeIds[$td['emp']] : null;
$baseSalary = 0;
if ($empId) {
$emp = DB::table('employees')->where('id', $empId)->first();
$baseSalary = $emp->salary_amount ?? 0;
}
$baseSalary = $employee ? ($employee->salary_amount ?? 0) : 0;
$month = now()->subMonths($m);
$monthStart = $month->copy()->startOfMonth()->toDateString();
$monthEnd = $month->copy()->endOfMonth()->toDateString();
// Sum session earnings for this trainer/month
$sessionEarnings = DB::table('trainer_compensations')
$sessionEarnings = (int) 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()])
->whereIn('type', ['session_pay', 'group_pay', 'player_pay'])
->whereBetween('date', [$monthStart, $monthEnd])
->sum('amount');
$bonuses = DB::table('trainer_compensations')
->where('trainer_id', $tId)
->where('status', 'paid')
$bonuses = (int) DB::table('trainer_compensations')
->where('trainer_id', $tId)->where('status', 'paid')
->where('type', 'bonus')
->whereBetween('date', [$month->startOfMonth()->toDateString(), $month->endOfMonth()->toDateString()])
->whereBetween('date', [$monthStart, $monthEnd])
->sum('amount');
$penalties = DB::table('trainer_compensations')
$penalties = (int) DB::table('trainer_compensations')
->where('trainer_id', $tId)
->where('status', '!=', 'cancelled')
->whereIn('status', ['approved', 'paid'])
->where('type', 'penalty')
->whereBetween('date', [$month->startOfMonth()->toDateString(), $month->endOfMonth()->toDateString()])
->whereBetween('date', [$monthStart, $monthEnd])
->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);
$tax = (int) ($gross * 0.05);
$insurance = $empId ? 50000 : 0;
$totalDed = $penalties + $tax + $insurance;
$net = max(0, $gross - $totalDed);
$payslipId = DB::table('payslips')->insertGetId([
'uuid' => Str::uuid(),
......@@ -449,92 +535,84 @@ public function run(): void
'bonuses' => $bonuses,
'penalties' => $penalties,
'advances_deducted' => 0,
'tax_amount' => $taxAmount,
'insurance_amount' => $insuranceAmount,
'tax_amount' => $tax,
'insurance_amount' => $insurance,
'other_deductions' => 0,
'gross_amount' => $gross,
'total_deductions' => $totalDeductions,
'total_deductions' => $totalDed,
'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,
'payment_method' => $empId ? 'bank_transfer' : 'cash',
'payment_reference' => $empId ? 'TRF-' . $month->format('Ym') . '-' . ($i + 1) : null,
'created_by' => $userId,
'created_at' => $now,
'updated_at' => $now,
]);
// Payslip items
$items = [];
$sortOrder = 0;
$sort = 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];
$items[] = ['payslip_id' => $payslipId, 'type' => 'base_salary', 'description' => 'الراتب الأساسي', 'quantity' => 1, 'rate' => $baseSalary, 'amount' => $baseSalary, 'is_deduction' => false, 'metadata' => '{}', 'sort_order' => $sort++, '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];
$items[] = ['payslip_id' => $payslipId, 'type' => 'session_pay', 'description' => 'أجر الحصص', 'quantity' => 1, 'rate' => $sessionEarnings, 'amount' => $sessionEarnings, 'is_deduction' => false, 'metadata' => '{}', 'sort_order' => $sort++, '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];
$items[] = ['payslip_id' => $payslipId, 'type' => 'bonus', 'description' => 'مكافآت', 'quantity' => 1, 'rate' => $bonuses, 'amount' => $bonuses, 'is_deduction' => false, 'metadata' => '{}', 'sort_order' => $sort++, '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];
$items[] = ['payslip_id' => $payslipId, 'type' => 'penalty', 'description' => 'خصومات', 'quantity' => 1, 'rate' => $penalties, 'amount' => $penalties, 'is_deduction' => true, 'metadata' => '{}', 'sort_order' => $sort++, '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 ($tax > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'tax', 'description' => 'ضريبة دخل 5%', 'quantity' => 1, 'rate' => $tax, 'amount' => $tax, 'is_deduction' => true, 'metadata' => '{}', 'sort_order' => $sort++, '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 ($insurance > 0) {
$items[] = ['payslip_id' => $payslipId, 'type' => 'insurance', 'description' => 'تأمين اجتماعي', 'quantity' => 1, 'rate' => $insurance, 'amount' => $insurance, 'is_deduction' => true, 'metadata' => '{}', 'sort_order' => $sort++, 'created_at' => $now, 'updated_at' => $now];
}
if ($items) {
DB::table('payslip_items')->insert($items);
}
$periodTotalGross += $gross;
$periodTotalDeductions += $totalDeductions;
$periodTotalNet += $net;
$periodGross += $gross;
$periodDed += $totalDed;
$periodNet += $net;
$slipCount++;
}
// Update period totals
DB::table('payroll_periods')->where('id', $periodId)->update([
'total_gross' => $periodTotalGross,
'total_deductions' => $periodTotalDeductions,
'total_net' => $periodTotalNet,
'total_gross' => $periodGross,
'total_deductions' => $periodDed,
'total_net' => $periodNet,
'payslip_count' => $slipCount,
]);
}
// ─── Trainer Advances (سلف) ───
// ─── 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' => 'تم إلغاء الطلب بناءً على رغبة المدرب'],
['idx' => 0, 'amount' => 500000, 'rem' => 300000, 'inst' => 100000, 'cnt' => 5, 'paid' => 2, 'status' => 'active', 'date' => '2026-05-01', 'reason' => 'سلفة شخصية — مصاريف طبية'],
['idx' => 3, 'amount' => 300000, 'rem' => 200000, 'inst' => 100000, 'cnt' => 3, 'paid' => 1, 'status' => 'active', 'date' => '2026-06-01', 'reason' => 'سلفة — مصاريف سفر'],
['idx' => 5, 'amount' => 200000, 'rem' => 0, 'inst' => 100000, 'cnt' => 2, 'paid' => 2, 'status' => 'fully_deducted', 'date' => '2026-03-01', 'reason' => 'سلفة شخصية'],
['idx' => 7, 'amount' => 400000, 'rem' => 300000, 'inst' => 100000, 'cnt' => 4, 'paid' => 1, 'status' => 'paused', 'date' => '2026-04-01', 'reason' => 'سلفة طوارئ'],
['idx' => 11,'amount' => 150000, 'rem' => 150000, 'inst' => 75000, 'cnt' => 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'],
'trainer_id' => $trainerIds[$adv['idx']],
'amount' => $adv['amount'],
'remaining_balance' => $adv['remaining'],
'installment_amount' => $adv['installment'],
'installments_count' => $adv['count'],
'remaining_balance' => $adv['rem'],
'installment_amount' => $adv['inst'],
'installments_count' => $adv['cnt'],
'installments_paid' => $adv['paid'],
'reason' => $adv['reason'],
'status' => $adv['status'],
'issued_date' => $adv['date'],
'expected_completion_date' => now()->addMonths($adv['count'] - $adv['paid'])->toDateString(),
'expected_completion_date' => now()->addMonths($adv['cnt'] - $adv['paid'])->toDateString(),
'approved_by' => $userId,
'created_by' => $userId,
'created_at' => $now,
......@@ -544,38 +622,35 @@ public function run(): void
// ─── 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' => 'حصول على شهادة جديدة'],
[0, 'session_rate', '12000', '15000', '2026-01-01', 'زيادة سنوية'],
[2, 'hourly_rate', '12000', '15000', '2026-04-01', 'ترقية بعد 6 أشهر'],
[5, 'group_rate', '20000', '25000', '2026-03-01', 'ترقية لرئيس مدربين'],
[11,'player_rate', '4000', '5000', '2026-05-01', 'زيادة بناءً على الأداء'],
[3, 'session_rate', '15000', '18000', '2026-02-01', 'حصول على شهادة جديدة'],
];
foreach ($rateChanges as $rc) {
foreach ($rateChanges as [$idx, $field, $old, $new, $date, $notes]) {
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'],
'trainer_id' => $trainerIds[$idx],
'field' => $field,
'old_value' => $old,
'new_value' => $new,
'effective_from' => $date,
'changed_by' => $userId,
'notes' => $rc['notes'],
'notes' => $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");
$this->command?->info('HR Demo data seeded successfully!');
$this->command?->info("- 11 employees (6 staff + 4 trainer-employees + 1 resigned, 1 on-leave)");
$this->command?->info("- 12 trainers (4 employee-based + 8 freelancers)");
$this->command?->info("- 12 qualifications, availability for all");
$this->command?->info("- ~600+ compensation records (3 months)");
$this->command?->info("- 3 payroll periods (2 closed with payslips, 1 open)");
$this->command?->info("- 5 advances (active, paused, fully_deducted, cancelled)");
$this->command?->info("- 5 rate 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