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

Fix retroactive wizard: parse NID for date_of_birth and gender

The members table has date_of_birth as NOT NULL, but the wizard passed
null when no explicit DOB was entered. Now NationalIdParser extracts
DOB and gender from the 14-digit national ID for the main member,
spouses, children, and temporary members.

If no NID and no DOB provided, returns a clear validation error instead
of letting the DB constraint violation propagate.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 30062682
...@@ -6,6 +6,7 @@ namespace App\Modules\Members\Services; ...@@ -6,6 +6,7 @@ namespace App\Modules\Members\Services;
use App\Core\App; use App\Core\App;
use App\Core\EventBus; use App\Core\EventBus;
use App\Core\Logger; use App\Core\Logger;
use App\Modules\Members\Services\NationalIdParser;
final class RetroactiveMembershipService final class RetroactiveMembershipService
{ {
...@@ -24,14 +25,33 @@ final class RetroactiveMembershipService ...@@ -24,14 +25,33 @@ final class RetroactiveMembershipService
$formDate = $data['form_date'] ?? $joinDate; $formDate = $data['form_date'] ?? $joinDate;
$nationalId = self::emptyToNull($data['national_id'] ?? null); $nationalId = self::emptyToNull($data['national_id'] ?? null);
$dateOfBirth = self::emptyToNull($data['date_of_birth'] ?? null);
$gender = $data['gender'] ?? 'male';
if ($nationalId && strlen($nationalId) === 14) {
$nidParsed = NationalIdParser::parse($nationalId);
if ($nidParsed['is_valid']) {
if (!$dateOfBirth && $nidParsed['dob']) {
$dateOfBirth = $nidParsed['dob'];
}
if ($nidParsed['gender']) {
$gender = $nidParsed['gender'];
}
}
}
if (!$dateOfBirth) {
return ['success' => false, 'error' => 'تاريخ الميلاد مطلوب — أدخل الرقم القومي (14 رقم) أو تاريخ الميلاد يدوياً'];
}
$memberData = [ $memberData = [
'full_name_ar' => $data['full_name_ar'], 'full_name_ar' => $data['full_name_ar'],
'full_name_en' => self::emptyToNull($data['full_name_en'] ?? null), 'full_name_en' => self::emptyToNull($data['full_name_en'] ?? null),
'national_id' => $nationalId, 'national_id' => $nationalId,
'passport_number' => self::emptyToNull($data['passport_number'] ?? null), 'passport_number' => self::emptyToNull($data['passport_number'] ?? null),
'id_type' => $nationalId ? 'national_id' : 'passport', 'id_type' => $nationalId ? 'national_id' : 'passport',
'date_of_birth' => self::emptyToNull($data['date_of_birth'] ?? null), 'date_of_birth' => $dateOfBirth,
'gender' => $data['gender'] ?? 'male', 'gender' => $gender,
'phone_mobile' => self::emptyToNull($data['phone_mobile'] ?? null), 'phone_mobile' => self::emptyToNull($data['phone_mobile'] ?? null),
'phone_home' => self::emptyToNull($data['phone_home'] ?? null), 'phone_home' => self::emptyToNull($data['phone_home'] ?? null),
'email' => self::emptyToNull($data['email'] ?? null), 'email' => self::emptyToNull($data['email'] ?? null),
...@@ -154,11 +174,17 @@ final class RetroactiveMembershipService ...@@ -154,11 +174,17 @@ final class RetroactiveMembershipService
if (!empty($data['spouses'])) { if (!empty($data['spouses'])) {
foreach ($data['spouses'] as $spouse) { foreach ($data['spouses'] as $spouse) {
$spouseJoinDate = self::emptyToNull($spouse['join_date'] ?? null) ?? $joinDate; $spouseJoinDate = self::emptyToNull($spouse['join_date'] ?? null) ?? $joinDate;
$spouseNid = self::emptyToNull($spouse['national_id'] ?? null);
$spouseDob = self::emptyToNull($spouse['date_of_birth'] ?? null);
if (!$spouseDob && $spouseNid && strlen($spouseNid) === 14) {
$parsed = NationalIdParser::parse($spouseNid);
if ($parsed['is_valid'] && $parsed['dob']) $spouseDob = $parsed['dob'];
}
$spouseId = $db->insert('spouses', [ $spouseId = $db->insert('spouses', [
'member_id' => $memberId, 'member_id' => $memberId,
'full_name_ar' => $spouse['full_name_ar'], 'full_name_ar' => $spouse['full_name_ar'],
'national_id' => self::emptyToNull($spouse['national_id'] ?? null), 'national_id' => $spouseNid,
'date_of_birth' => self::emptyToNull($spouse['date_of_birth'] ?? null), 'date_of_birth' => $spouseDob,
'nationality' => self::emptyToNull($spouse['nationality'] ?? null) ?? 'مصري', 'nationality' => self::emptyToNull($spouse['nationality'] ?? null) ?? 'مصري',
'marriage_date' => self::emptyToNull($spouse['marriage_date'] ?? null) ?? $joinDate, 'marriage_date' => self::emptyToNull($spouse['marriage_date'] ?? null) ?? $joinDate,
'phone_mobile' => self::emptyToNull($spouse['phone_mobile'] ?? null), 'phone_mobile' => self::emptyToNull($spouse['phone_mobile'] ?? null),
...@@ -191,12 +217,22 @@ final class RetroactiveMembershipService ...@@ -191,12 +217,22 @@ final class RetroactiveMembershipService
if (!empty($data['children'])) { if (!empty($data['children'])) {
foreach ($data['children'] as $child) { foreach ($data['children'] as $child) {
$childJoinDate = self::emptyToNull($child['join_date'] ?? null) ?? $joinDate; $childJoinDate = self::emptyToNull($child['join_date'] ?? null) ?? $joinDate;
$childNid = self::emptyToNull($child['national_id'] ?? null);
$childDob = self::emptyToNull($child['date_of_birth'] ?? null);
$childGender = $child['gender'] ?? 'male';
if ($childNid && strlen($childNid) === 14) {
$parsed = NationalIdParser::parse($childNid);
if ($parsed['is_valid']) {
if (!$childDob && $parsed['dob']) $childDob = $parsed['dob'];
if ($parsed['gender']) $childGender = $parsed['gender'];
}
}
$childId = $db->insert('children', [ $childId = $db->insert('children', [
'member_id' => $memberId, 'member_id' => $memberId,
'full_name_ar' => $child['full_name_ar'], 'full_name_ar' => $child['full_name_ar'],
'national_id' => self::emptyToNull($child['national_id'] ?? null), 'national_id' => $childNid,
'date_of_birth' => self::emptyToNull($child['date_of_birth'] ?? null), 'date_of_birth' => $childDob,
'gender' => $child['gender'] ?? 'male', 'gender' => $childGender,
'status' => 'active', 'status' => 'active',
'join_date' => $childJoinDate, 'join_date' => $childJoinDate,
'addition_fee' => $child['addition_fee'] ?? '0.00', 'addition_fee' => $child['addition_fee'] ?? '0.00',
...@@ -226,12 +262,22 @@ final class RetroactiveMembershipService ...@@ -226,12 +262,22 @@ final class RetroactiveMembershipService
if (!empty($data['temporary_members'])) { if (!empty($data['temporary_members'])) {
foreach ($data['temporary_members'] as $temp) { foreach ($data['temporary_members'] as $temp) {
$tempJoinDate = self::emptyToNull($temp['join_date'] ?? null) ?? $joinDate; $tempJoinDate = self::emptyToNull($temp['join_date'] ?? null) ?? $joinDate;
$tempNid = self::emptyToNull($temp['national_id'] ?? null);
$tempDob = self::emptyToNull($temp['date_of_birth'] ?? null);
$tempGender = $temp['gender'] ?? 'male';
if ($tempNid && strlen($tempNid) === 14) {
$parsed = NationalIdParser::parse($tempNid);
if ($parsed['is_valid']) {
if (!$tempDob && $parsed['dob']) $tempDob = $parsed['dob'];
if ($parsed['gender']) $tempGender = $parsed['gender'];
}
}
$tempId = $db->insert('temporary_members', [ $tempId = $db->insert('temporary_members', [
'member_id' => $memberId, 'member_id' => $memberId,
'full_name_ar' => $temp['full_name_ar'], 'full_name_ar' => $temp['full_name_ar'],
'national_id' => self::emptyToNull($temp['national_id'] ?? null), 'national_id' => $tempNid,
'date_of_birth' => self::emptyToNull($temp['date_of_birth'] ?? null), 'date_of_birth' => $tempDob,
'gender' => $temp['gender'] ?? 'male', 'gender' => $tempGender,
'category' => $temp['category'] ?? 'parent', 'category' => $temp['category'] ?? 'parent',
'relationship_to_member' => self::emptyToNull($temp['relationship_to_member'] ?? null), 'relationship_to_member' => self::emptyToNull($temp['relationship_to_member'] ?? null),
'status' => 'active', 'status' => 'active',
......
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