Commit ca7312ce authored by Administrator's avatar Administrator

Update 1 files via Son of Anton

parent 44998953
...@@ -22,21 +22,29 @@ class SpouseController extends Controller ...@@ -22,21 +22,29 @@ class SpouseController extends Controller
return $this->redirect('/members')->withError('العضو غير موجود'); return $this->redirect('/members')->withError('العضو غير موجود');
} }
// BLOCK: membership_value must be set
$membershipValue = $member['membership_value'] ?? '0.00';
if (bccomp($membershipValue, '0.01', 2) < 0) {
return $this->redirect('/members/' . $memberId)
->withError('⚠ يجب ملء الاستمارة وتحديد المؤهل أولاً لحساب قيمة العضوية قبل إضافة زوج/ة');
}
$qualifications = $db->select("SELECT id, name_ar FROM qualifications WHERE is_active = 1 ORDER BY sort_order"); $qualifications = $db->select("SELECT id, name_ar FROM qualifications WHERE is_active = 1 ORDER BY sort_order");
$countries = $db->select("SELECT nationality_ar FROM countries WHERE is_active = 1 ORDER BY name_ar"); $countries = $db->select("SELECT nationality_ar FROM countries WHERE is_active = 1 ORDER BY name_ar");
$currentSpouseCount = Spouse::countActiveForMember((int) $memberId); $spouseOrder = Spouse::getNextOrder((int) $memberId);
// Check max spouses // Pre-calculate fee estimate for display
$maxSpouses = ($member['gender'] === 'male') ? 4 : 1; $feeEstimate = SpouseFeeCalculator::calculate((int) $memberId, [
if ($currentSpouseCount >= $maxSpouses) { 'nationality' => 'مصري',
return $this->redirect('/members/' . $memberId)->withError('تم الوصول للحد الأقصى لعدد الأزواج'); 'marriage_date' => date('Y-m-d'),
} ]);
return $this->view('Spouses.Views.create', [ return $this->view('Spouses.Views.create', [
'member' => $member, 'member' => $member,
'qualifications' => $qualifications, 'qualifications' => $qualifications,
'countries' => $countries, 'countries' => $countries,
'spouseOrder' => $currentSpouseCount + 1, 'spouseOrder' => $spouseOrder,
'feeEstimate' => $feeEstimate,
]); ]);
} }
...@@ -48,22 +56,28 @@ class SpouseController extends Controller ...@@ -48,22 +56,28 @@ class SpouseController extends Controller
return $this->redirect('/members')->withError('العضو غير موجود'); return $this->redirect('/members')->withError('العضو غير موجود');
} }
// BLOCK: membership_value must be set
$membershipValue = $member['membership_value'] ?? '0.00';
if (bccomp($membershipValue, '0.01', 2) < 0) {
return $this->redirect('/members/' . $memberId)
->withError('⚠ يجب تحديد قيمة العضوية قبل إضافة زوج/ة');
}
$data = $request->all(); $data = $request->all();
unset($data['_csrf_token']); unset($data['_csrf_token']);
$errors = []; $errors = [];
// Required fields if (empty(trim($data['full_name_ar'] ?? ''))) $errors[] = 'اسم الزوج/ة مطلوب';
if (empty(trim($data['full_name_ar'] ?? ''))) $errors[] = 'اسم الزوج/الزوجة مطلوب';
if (empty($data['date_of_birth'] ?? '')) $errors[] = 'تاريخ الميلاد مطلوب'; if (empty($data['date_of_birth'] ?? '')) $errors[] = 'تاريخ الميلاد مطلوب';
if (empty($data['gender'] ?? '')) $errors[] = 'النوع مطلوب'; if (empty($data['gender'] ?? '')) $errors[] = 'النوع مطلوب';
if (empty($data['marriage_date'] ?? '')) $errors[] = 'تاريخ الزواج مطلوب'; if (empty($data['marriage_date'] ?? '')) $errors[] = 'تاريخ الزواج مطلوب';
// Check max spouses // Max spouse check
$currentCount = Spouse::countActiveForMember((int) $memberId); $existingCount = Spouse::countActiveForMember((int) $memberId);
$maxSpouses = ($member['gender'] === 'male') ? 4 : 1; $maxSpouses = ($member['gender'] === 'male') ? 4 : 1;
if ($currentCount >= $maxSpouses) { if ($existingCount >= $maxSpouses) {
$errors[] = 'تم الوصول للحد الأقصى لعدد الأزواج (' . $maxSpouses . ')'; $errors[] = 'تم بلوغ الحد الأقصى لعدد الزوجات (' . $maxSpouses . ')';
} }
// Parse NID if provided // Parse NID if provided
...@@ -79,35 +93,33 @@ class SpouseController extends Controller ...@@ -79,35 +93,33 @@ class SpouseController extends Controller
$data['gender'] = $parsed['gender']; $data['gender'] = $parsed['gender'];
} }
// Cannot be own spouse // Cannot be the member themselves
if ($nid === ($member['national_id'] ?? '')) { if ($nid === ($member['national_id'] ?? '')) {
$errors[] = 'لا يمكن إضافة العضو نفسه كزوج'; $errors[] = 'لا يمكن إضافة العضو نفسه كزوج';
} }
// Duplicate NID check // Check duplicate
$dup = Spouse::nidExistsForOtherMember($nid, (int) $memberId); $dup = Spouse::nidExistsForOtherMember($nid, (int) $memberId);
if ($dup) { if ($dup) {
$dupName = $dup['data']['full_name_ar'] ?? ''; $errors[] = 'الرقم القومي مسجل بالفعل: ' . ($dup['data']['full_name_ar'] ?? '');
$dupNum = $dup['data']['membership_number'] ?? '';
$errors[] = "الرقم القومي مسجل بالفعل: {$dupName} ({$dupNum})";
} }
} }
// Marriage date validation // Calculate age
if (!empty($data['marriage_date'])) { if (!empty($data['date_of_birth']) && empty($data['age_years'])) {
$marriageTs = strtotime($data['marriage_date']); $age = age_from_dob($data['date_of_birth']);
if ($marriageTs > time()) { $data['age_years'] = $age['years'];
$errors[] = 'تاريخ الزواج لا يمكن أن يكون في المستقبل'; $data['age_months'] = $age['months'];
}
// Both must be >= 18 at marriage
if (!empty($data['date_of_birth']) && !empty($member['date_of_birth'])) {
$spouseAgeAtMarriage = (int) (((new \DateTime($data['date_of_birth']))->diff(new \DateTime($data['marriage_date'])))->y);
$memberAgeAtMarriage = (int) (((new \DateTime($member['date_of_birth']))->diff(new \DateTime($data['marriage_date'])))->y);
if ($spouseAgeAtMarriage < 18) {
$errors[] = 'عمر الزوج/الزوجة عند الزواج يجب أن يكون 18 سنة على الأقل';
} }
if ($memberAgeAtMarriage < 18) {
$errors[] = 'عمر العضو عند الزواج يجب أن يكون 18 سنة على الأقل'; // Both must be at least 18 at marriage
if (!empty($data['date_of_birth']) && !empty($data['marriage_date'])) {
$dobTs = strtotime($data['date_of_birth']);
$marriageTs = strtotime($data['marriage_date']);
if ($marriageTs && $dobTs) {
$ageAtMarriage = (int) (($marriageTs - $dobTs) / (365.25 * 86400));
if ($ageAtMarriage < 18) {
$errors[] = 'يجب أن يكون عمر الزوج/ة 18 سنة على الأقل وقت الزواج';
} }
} }
} }
...@@ -119,20 +131,16 @@ class SpouseController extends Controller ...@@ -119,20 +131,16 @@ class SpouseController extends Controller
return $this->redirect("/members/{$memberId}/spouses/create"); return $this->redirect("/members/{$memberId}/spouses/create");
} }
// Calculate age
if (!empty($data['date_of_birth']) && empty($data['age_years'])) {
$age = age_from_dob($data['date_of_birth']);
$data['age_years'] = $age['years'];
$data['age_months'] = $age['months'];
}
// Determine classification
$spouseAge = (int) ($data['age_years'] ?? 0);
$classification = $spouseAge >= 21 ? 'working' : 'dependent';
// Calculate fee // Calculate fee
$feeCalc = SpouseFeeCalculator::calculate((int) $memberId, $data); $feeCalc = SpouseFeeCalculator::calculate((int) $memberId, $data);
$spouseOrder = $feeCalc['spouse_order'] ?? ($currentCount + 1);
if (!empty($feeCalc['error'])) {
return $this->redirect("/members/{$memberId}/spouses/create")
->withError($feeCalc['error']);
}
$spouseOrder = $feeCalc['spouse_order'] ?? Spouse::getNextOrder((int) $memberId);
$joinDate = date('Y-m-d');
$spouse = Spouse::create([ $spouse = Spouse::create([
'member_id' => (int) $memberId, 'member_id' => (int) $memberId,
...@@ -147,49 +155,58 @@ class SpouseController extends Controller ...@@ -147,49 +155,58 @@ class SpouseController extends Controller
'gender' => $data['gender'], 'gender' => $data['gender'],
'nationality' => $data['nationality'] ?? 'مصري', 'nationality' => $data['nationality'] ?? 'مصري',
'religion' => $data['religion'] ?? null, 'religion' => $data['religion'] ?? null,
'qualification_id' => !empty($data['qualification_id']) ? (int) $data['qualification_id'] : null, 'qualification_id' => ($data['qualification_id'] ?? '') !== '' ? (int) $data['qualification_id'] : null,
'occupation' => $data['occupation'] ?? null, 'occupation' => $data['occupation'] ?? null,
'work_address' => $data['work_address'] ?? null, 'work_address' => $data['work_address'] ?? null,
'work_phone' => $data['work_phone'] ?? null, 'work_phone' => $data['work_phone'] ?? null,
'mobile' => $data['mobile'] ?? null, 'mobile' => $data['mobile'] ?? null,
'marriage_date' => $data['marriage_date'], 'marriage_date' => $data['marriage_date'],
'join_date' => date('Y-m-d'), 'join_date' => $joinDate,
'classification' => $classification, 'classification' => 'working',
'addition_fee' => $feeCalc['spouse_fee'] ?? '0.00', 'addition_fee' => $feeCalc['total_fee'] ?? '0.00',
'status' => 'active', 'status' => 'active',
]); ]);
EventBus::dispatch('spouse.added', [ EventBus::dispatch('spouse.added', [
'member_id' => (int) $memberId, 'member_id' => (int) $memberId,
'spouse_id' => (int) $spouse->id, 'spouse_id' => (int) $spouse->id,
'fee' => $feeCalc['spouse_fee'] ?? '0.00', 'spouse_order' => $spouseOrder,
'fee' => $feeCalc['total_fee'] ?? '0.00',
]); ]);
// Build success message with full breakdown
$breakdown = $feeCalc['breakdown'] ?? [];
$breakdownText = !empty($breakdown) ? "\n" . implode("\n", $breakdown) : '';
$msg = 'تم إضافة الزوج/الزوجة بنجاح';
$msg .= ' — الترتيب: #' . $spouseOrder;
$msg .= ' — الرسوم: ' . money($feeCalc['total_fee'] ?? '0');
if (!empty($feeCalc['rule_applied'])) {
$msg .= ' (' . $feeCalc['rule_applied'] . ')';
}
return $this->redirect("/members/{$memberId}") return $this->redirect("/members/{$memberId}")
->withSuccess('تم إضافة الزوج/الزوجة بنجاح — الرسوم: ' . money($feeCalc['spouse_fee'] ?? '0.00')); ->withSuccess($msg);
} }
public function show(Request $request, string $memberId, string $id): Response public function show(Request $request, string $memberId, string $id): Response
{ {
$spouse = Spouse::find((int) $id); $spouse = Spouse::find((int) $id);
if (!$spouse || (int) $spouse->member_id !== (int) $memberId) { if (!$spouse || (int) $spouse->member_id !== (int) $memberId) {
return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة'); return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة');
} }
$db = App::getInstance()->db(); $db = App::getInstance()->db();
$member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $memberId]); $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $memberId]);
return $this->view('Spouses.Views.show', [ return $this->view('Spouses.Views.show', ['member' => $member, 'spouse' => $spouse]);
'member' => $member,
'spouse' => $spouse,
]);
} }
public function edit(Request $request, string $memberId, string $id): Response public function edit(Request $request, string $memberId, string $id): Response
{ {
$spouse = Spouse::find((int) $id); $spouse = Spouse::find((int) $id);
if (!$spouse || (int) $spouse->member_id !== (int) $memberId) { if (!$spouse || (int) $spouse->member_id !== (int) $memberId) {
return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة'); return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة');
} }
$db = App::getInstance()->db(); $db = App::getInstance()->db();
...@@ -209,42 +226,35 @@ class SpouseController extends Controller ...@@ -209,42 +226,35 @@ class SpouseController extends Controller
{ {
$spouse = Spouse::find((int) $id); $spouse = Spouse::find((int) $id);
if (!$spouse || (int) $spouse->member_id !== (int) $memberId) { if (!$spouse || (int) $spouse->member_id !== (int) $memberId) {
return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة'); return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة');
} }
$data = $request->all(); $data = $request->all();
unset($data['_csrf_token']); unset($data['_csrf_token']);
$updateFields = [
'full_name_en', 'religion', 'occupation', 'work_address',
'work_phone', 'mobile', 'qualification_id',
];
$updateData = []; $updateData = [];
foreach ($updateFields as $field) { foreach (['full_name_en', 'occupation', 'work_address', 'work_phone', 'mobile', 'religion'] as $field) {
if (array_key_exists($field, $data)) { if (array_key_exists($field, $data)) {
$val = $data[$field]; $val = $data[$field];
$updateData[$field] = ($val === '' || $val === null) ? null : $val; $updateData[$field] = ($val === '' || $val === null) ? null : $val;
} }
} }
if (isset($data['qualification_id'])) {
$updateData['qualification_id'] = ($data['qualification_id'] !== '') ? (int) $data['qualification_id'] : null;
}
if (!empty($updateData)) { if (!empty($updateData)) {
$spouse->update($updateData); $spouse->update($updateData);
} }
EventBus::dispatch('spouse.updated', [ return $this->redirect("/members/{$memberId}")->withSuccess('تم تحديث بيانات الزوج/ة');
'member_id' => (int) $memberId,
'spouse_id' => (int) $id,
]);
return $this->redirect("/members/{$memberId}")->withSuccess('تم تحديث بيانات الزوج/الزوجة');
} }
public function archive(Request $request, string $memberId, string $id): Response public function archive(Request $request, string $memberId, string $id): Response
{ {
$spouse = Spouse::find((int) $id); $spouse = Spouse::find((int) $id);
if (!$spouse || (int) $spouse->member_id !== (int) $memberId) { if (!$spouse || (int) $spouse->member_id !== (int) $memberId) {
return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة'); return $this->redirect("/members/{$memberId}")->withError('بيانات الزوج غير موجودة');
} }
$reason = trim((string) $request->post('reason', '')); $reason = trim((string) $request->post('reason', ''));
...@@ -269,19 +279,6 @@ class SpouseController extends Controller ...@@ -269,19 +279,6 @@ class SpouseController extends Controller
'reason' => $reason, 'reason' => $reason,
]); ]);
return $this->redirect("/members/{$memberId}")->withSuccess('تم إزالة الزوج/الزوجة'); return $this->redirect("/members/{$memberId}")->withSuccess('تم إزالة الزوج/ة');
}
public function calculateFee(Request $request): Response
{
$memberId = (int) $request->post('member_id', 0);
$data = $request->all();
if ($memberId <= 0) {
return $this->json(['error' => 'بيانات غير صالحة'], 422);
}
$result = SpouseFeeCalculator::calculate($memberId, $data);
return $this->json($result);
} }
} }
\ No newline at end of file
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