$row=$db->selectOne("SELECT name_ar FROM branches WHERE id = ?",[$this->branch_id]);
return$row['name_ar']??'—';
}
publicfunctiongetQualificationName():string
{
if(!$this->qualification_id)return'—';
$db=App::getInstance()->db();
$row=$db->selectOne("SELECT name_ar FROM qualifications WHERE id = ?",[$this->qualification_id]);
return$row['name_ar']??'—';
}
publicfunctiongetStatusLabel():string
{
$labels=[
'potential'=>'عضوية محتملة',
'under_review'=>'تحت المراجعة',
'interview_scheduled'=>'في انتظار المقابلة',
'accepted'=>'مقبول',
'rejected'=>'مرفوض',
'payment_pending'=>'في انتظار السداد',
'active'=>'فعال',
'frozen'=>'مجمد',
'suspended'=>'موقوف',
'dropped'=>'مسقط',
'expired'=>'منتهي',
'terminated'=>'منتهي بقرار',
];
return$labels[$this->status]??$this->status;
}
publicfunctiongetStatusColor():string
{
$colors=[
'potential'=>'#6B7280',
'under_review'=>'#D97706',
'interview_scheduled'=>'#0284C7',
'accepted'=>'#059669',
'rejected'=>'#DC2626',
'payment_pending'=>'#D97706',
'active'=>'#059669',
'frozen'=>'#6B7280',
'suspended'=>'#DC2626',
'dropped'=>'#DC2626',
'expired'=>'#9CA3AF',
'terminated'=>'#DC2626',
];
return$colors[$this->status]??'#6B7280';
}
publicstaticfunctiongetStatusOptions():array
{
return[
'potential'=>'عضوية محتملة',
'under_review'=>'تحت المراجعة',
'interview_scheduled'=>'في انتظار المقابلة',
'accepted'=>'مقبول',
'rejected'=>'مرفوض',
'payment_pending'=>'في انتظار السداد',
'active'=>'فعال',
'frozen'=>'مجمد',
'suspended'=>'موقوف',
'dropped'=>'مسقط',
'expired'=>'منتهي',
];
}
publicstaticfunctiongetMembershipTypes():array
{
return[
'working'=>'عامل',
'seasonal'=>'موسمي',
'sports'=>'رياضي',
'honorary'=>'شرفي',
'foreign'=>'أجنبي',
];
}
publicfunctiongetNotes():array
{
$db=App::getInstance()->db();
return$db->select(
"SELECT mn.*, e.full_name_ar as employee_name FROM member_notes mn LEFT JOIN employees e ON e.id = mn.created_by WHERE mn.member_id = ? ORDER BY mn.created_at DESC",
* Sequential, gap-free, atomic to prevent duplicates.
* Only called after payment confirmation.
*/
publicstaticfunctionnext():string
{
$db=App::getInstance()->db();
// Use a transaction with locking to prevent concurrent duplicates
$db->beginTransaction();
try{
// Get the current maximum membership number
$row=$db->selectOne(
"SELECT MAX(CAST(membership_number AS UNSIGNED)) as max_num FROM members WHERE membership_number IS NOT NULL AND membership_number REGEXP '^[0-9]+$' FOR UPDATE"
);
$startNumber=10012;// Default starting number (1001/2 per spec — interpreted as 10012)
// Check system config for starting number
$configRow=$db->selectOne("SELECT config_value FROM system_config WHERE config_key = 'membership_start_number'");
$where.=" AND (m.full_name_ar LIKE ? OR m.full_name_en LIKE ? OR m.national_id LIKE ? OR m.membership_number LIKE ? OR m.phone_mobile LIKE ? OR m.form_number LIKE ? OR m.passport_number LIKE ?)";
<inputtype="text"name="q"class="form-input"placeholder="الاسم بالعربي، الرقم القومي، رقم العضوية، رقم المحمول، رقم الاستمارة..."style="font-size:16px;padding:12px;"autofocus>