Commit b2552435 authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat(auth): provision employee accounts with role-based permissions

Assigns human-friendly usernames, unique passwords, and business-appropriate
roles to all 62 imported employees based on their HR job titles.
Includes credentials reference sheet for permission testing.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 9548bd3b
This diff is collapsed.
<?php
declare(strict_types=1);
use App\Core\Database;
return function (Database $db): void {
// ── Employee credentials: ID → [username, plaintext password] ──
$credentials = [
7 => ['ameen', 'Club7821'],
8 => ['magdy', 'Club8934'],
9 => ['m.nabil', 'Club9045'],
10 => ['eman', 'Club1056'],
11 => ['roay', 'Club1167'],
12 => ['safwat', 'Club1278'],
13 => ['m.hameed', 'Club1389'],
14 => ['a.nabil', 'Club1490'],
15 => ['omar', 'Club1501'],
16 => ['manar', 'Club1612'],
17 => ['m.maher', 'Club1723'],
18 => ['a.hussein', 'Club1834'],
19 => ['hany', 'Club1945'],
20 => ['osama', 'Club2056'],
21 => ['a.khaleq', 'Club2167'],
22 => ['a.saad', 'Club2278'],
23 => ['mostafa.k', 'Club2389'],
24 => ['abdullah', 'Club2490'],
25 => ['naglaa', 'Club2501'],
26 => ['mahmoud.m', 'Club2612'],
27 => ['islam.a', 'Club2723'],
28 => ['rasha.sh', 'Club2834'],
29 => ['rasha.b', 'Club2945'],
30 => ['shereen.f', 'Club3056'],
31 => ['waleed.g', 'Club3167'],
32 => ['a.ibrahim', 'Club3278'],
33 => ['olaa', 'Club3389'],
34 => ['aya', 'Club3490'],
35 => ['alaaeldeen', 'Club3501'],
36 => ['mostafa.s', 'Club3612'],
37 => ['islam.h', 'Club3723'],
38 => ['salah', 'Club3834'],
39 => ['toama', 'Club3945'],
40 => ['reham', 'Club4056'],
41 => ['m.aziz', 'Club4167'],
42 => ['ziad', 'Club4278'],
43 => ['shimaa', 'Club4389'],
44 => ['islam.s', 'Club4490'],
45 => ['islam.m', 'Club4501'],
46 => ['m.yahia', 'Club4612'],
47 => ['dr.amr', 'Club4723'],
48 => ['dr.hazem', 'Club4834'],
49 => ['ismail', 'Club4945'],
50 => ['amal', 'Club5056'],
51 => ['hossam', 'Club5167'],
52 => ['waleed.a', 'Club5278'],
53 => ['a.nasser', 'Club5389'],
54 => ['morad', 'Club5490'],
55 => ['mayada', 'Club5501'],
56 => ['tahany', 'Club5612'],
57 => ['shahd', 'Club5723'],
58 => ['heba', 'Club5834'],
59 => ['m.saad', 'Club5945'],
60 => ['mervat', 'Club6056'],
61 => ['mostafa.a', 'Club6167'],
62 => ['hala', 'Club6278'],
63 => ['m.moneim', 'Club6389'],
64 => ['a.anwar', 'Club6490'],
65 => ['yousef', 'Club6501'],
66 => ['mahmoud.a', 'Club6612'],
67 => ['shereen.m', 'Club6723'],
68 => ['a.bakeer', 'Club6834'],
];
// ── Job Title ID → Role codes ──
$jobTitleRoles = [
2 => ['board_member'],
3 => ['general_manager'],
4 => ['general_manager'],
6 => ['department_head'],
7 => ['report_viewer'],
8 => ['receptionist'],
11 => ['sports_officer'],
12 => ['sports_officer'],
13 => ['cashier_operator'],
14 => ['facilities_manager'],
15 => ['sports_officer'],
16 => ['academy_manager'],
17 => ['sports_officer'],
18 => ['membership_director'],
19 => ['membership_officer'],
21 => ['accountant', 'treasury_manager'],
22 => ['accountant'],
23 => ['accountant'],
24 => ['auditor'],
25 => ['treasury_officer'],
29 => ['report_viewer'],
30 => ['department_head', 'security_officer'],
32 => ['security_officer'],
33 => ['security_officer'],
34 => ['department_head'],
35 => ['report_viewer'],
36 => ['report_viewer'],
37 => ['receptionist'],
38 => ['receptionist'],
39 => ['sales_agent', 'department_head'],
40 => ['sales_agent'],
41 => ['sales_agent'],
42 => ['department_head', 'auditor'],
43 => ['hr_manager'],
44 => ['hr_officer'],
45 => ['membership_director'],
47 => ['membership_officer'],
48 => ['it_admin'],
49 => ['security_officer'],
50 => ['it_admin'],
51 => ['receptionist'],
];
// ── Cache role IDs by role_code ──
$roleRows = $db->select("SELECT id, role_code FROM roles WHERE is_active = 1", []);
$roleMap = [];
foreach ($roleRows as $r) {
$roleMap[$r['role_code']] = (int) $r['id'];
}
// ── Cache job_title_id per employee from HR profiles ──
$profileRows = $db->select(
"SELECT employee_id, job_title_id FROM hr_employee_profiles WHERE is_archived = 0",
[]
);
$employeeJobTitle = [];
foreach ($profileRows as $p) {
$employeeJobTitle[(int) $p['employee_id']] = (int) $p['job_title_id'];
}
$now = date('Y-m-d H:i:s');
$updated = 0;
$rolesAssigned = 0;
$skipped = 0;
foreach ($credentials as $empId => [$username, $plainPassword]) {
// Check if employee exists and still has generic emp00XX username
$emp = $db->selectOne(
"SELECT id, username FROM employees WHERE id = ? AND is_archived = 0",
[$empId]
);
if (!$emp) {
$skipped++;
continue;
}
// Skip if username was already changed from emp00XX pattern
if (!preg_match('/^emp\d{4}/', $emp['username'])) {
echo " SKIP #{$empId} — username already customized: {$emp['username']}\n";
$skipped++;
continue;
}
// Check username not taken by another employee
$taken = $db->selectOne(
"SELECT id FROM employees WHERE username = ? AND id != ?",
[$username, $empId]
);
if ($taken) {
echo " WARN #{$empId} — username '{$username}' taken, using '{$username}.{$empId}'\n";
$username = $username . '.' . $empId;
}
// Update credentials
$hash = password_hash($plainPassword, PASSWORD_BCRYPT, ['cost' => 12]);
$db->update('employees', [
'username' => $username,
'password_hash' => $hash,
'force_password_change' => 1,
'failed_login_count' => 0,
'locked_until' => null,
'updated_at' => $now,
], '`id` = ?', [$empId]);
$updated++;
// Assign roles based on job title
$jobTitleId = $employeeJobTitle[$empId] ?? null;
if ($jobTitleId === null) {
echo " WARN #{$empId} ({$username}) — no HR profile / job title, skipping role assignment\n";
continue;
}
$roleCodes = $jobTitleRoles[$jobTitleId] ?? null;
if ($roleCodes === null) {
echo " WARN #{$empId} ({$username}) — job_title_id={$jobTitleId} has no role mapping\n";
continue;
}
// Check if employee already has role assignments
$existingRoles = $db->select(
"SELECT role_id FROM employee_roles WHERE employee_id = ? AND is_active = 1",
[$empId]
);
if (!empty($existingRoles)) {
echo " SKIP roles #{$empId} ({$username}) — already has " . count($existingRoles) . " role(s)\n";
continue;
}
foreach ($roleCodes as $code) {
$roleId = $roleMap[$code] ?? null;
if ($roleId === null) {
echo " ERR #{$empId} — role '{$code}' not found in roles table\n";
continue;
}
$db->insert('employee_roles', [
'employee_id' => $empId,
'role_id' => $roleId,
'assigned_at' => $now,
'assigned_by' => 1,
'is_active' => 1,
]);
$rolesAssigned++;
}
}
echo "\n";
echo "=== Employee Account Provisioning Complete ===\n";
echo " Credentials updated: {$updated}\n";
echo " Role assignments created: {$rolesAssigned}\n";
echo " Skipped: {$skipped}\n";
echo "\n";
// ── Output credentials table ──
echo "=== CREDENTIALS TABLE (save this!) ===\n";
echo str_pad('ID', 4) . str_pad('Username', 16) . str_pad('Password', 12) . "Roles\n";
echo str_repeat('-', 70) . "\n";
foreach ($credentials as $empId => [$username, $plainPassword]) {
$jobTitleId = $employeeJobTitle[$empId] ?? null;
$roleCodes = ($jobTitleId !== null) ? ($jobTitleRoles[$jobTitleId] ?? ['—']) : ['—'];
echo str_pad((string) $empId, 4)
. str_pad($username, 16)
. str_pad($plainPassword, 12)
. implode(', ', $roleCodes) . "\n";
}
echo "\n";
};
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