Commit ccd9b70a authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix(transfers): show separation origin on child profile and translate audit labels to Arabic

- Add transferred_from_transfer_id column to track child separation origin
- TransferProcessor sets the field when completing child separations
- Member profile detects separation transfers and shows: parent name,
  separation date, actual paid fees (not full membership_value)
- Financial summary shows "رسوم الفصل المدفوعة" for separated children
- Transfer status labels: "requested" now shows "في انتظار الدفع"
- AuditService: comprehensive Arabic labels for statuses, fields, and
  formatted values (payment_method, membership_type, classification, etc.)
- Backfill migration links existing completed transfers to their target members
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent cb2f1384
...@@ -381,95 +381,158 @@ final class AuditService ...@@ -381,95 +381,158 @@ final class AuditService
public static function getFieldLabel(string $field): string public static function getFieldLabel(string $field): string
{ {
return match ($field) { return match ($field) {
'full_name_ar' => 'الاسم بالعربية', 'full_name_ar' => 'الاسم بالعربية',
'full_name_en' => 'الاسم بالإنجليزية', 'full_name_en' => 'الاسم بالإنجليزية',
'national_id' => 'الرقم القومي', 'national_id' => 'الرقم القومي',
'status' => 'الحالة', 'status' => 'الحالة',
'membership_number' => 'رقم العضوية', 'membership_number' => 'رقم العضوية',
'form_number' => 'رقم الاستمارة', 'form_number' => 'رقم الاستمارة',
'branch_id' => 'الفرع', 'branch_id' => 'الفرع',
'qualification_id' => 'المؤهل', 'qualification_id' => 'المؤهل',
'membership_value' => 'قيمة العضوية', 'membership_value' => 'قيمة العضوية',
'membership_type' => 'نوع العضوية', 'membership_type' => 'نوع العضوية',
'member_category' => 'فئة العضو', 'member_category' => 'فئة العضو',
'date_of_birth' => 'تاريخ الميلاد', 'membership_origin_date' => 'تاريخ أصل العضوية',
'gender' => 'النوع', 'date_of_birth' => 'تاريخ الميلاد',
'phone' => 'الهاتف', 'gender' => 'النوع',
'email' => 'البريد الإلكتروني', 'phone' => 'الهاتف',
'marital_status' => 'الحالة الاجتماعية', 'phone_mobile' => 'الهاتف المحمول',
'nationality' => 'الجنسية', 'phone_home' => 'هاتف المنزل',
'religion' => 'الديانة', 'email' => 'البريد الإلكتروني',
'occupation' => 'المهنة', 'marital_status' => 'الحالة الاجتماعية',
'residence_address' => 'عنوان السكن', 'nationality' => 'الجنسية',
'is_archived' => 'مؤرشف', 'religion' => 'الديانة',
'archived_at' => 'تاريخ الأرشفة', 'occupation' => 'المهنة',
'archived_by' => 'أرشف بواسطة', 'job_title' => 'المسمى الوظيفي',
'created_at' => 'تاريخ الإنشاء', 'residence_address' => 'عنوان السكن',
'updated_at' => 'تاريخ التعديل', 'area' => 'المنطقة',
'created_by' => 'أنشئ بواسطة', 'governorate' => 'المحافظة',
'updated_by' => 'عُدّل بواسطة', 'emergency_name' => 'اسم الطوارئ',
'amount' => 'المبلغ', 'emergency_phone' => 'هاتف الطوارئ',
'payment_type' => 'نوع الدفعة', 'is_archived' => 'مؤرشف',
'payment_method' => 'طريقة الدفع', 'archived_at' => 'تاريخ الأرشفة',
'payment_date' => 'تاريخ الدفع', 'archived_by' => 'أرشف بواسطة',
'receipt_number' => 'رقم الإيصال', 'created_at' => 'تاريخ الإنشاء',
'request_number' => 'رقم الطلب', 'updated_at' => 'تاريخ التعديل',
'addition_fee' => 'رسوم الإضافة', 'created_by' => 'أنشئ بواسطة',
'spouse_order' => 'ترتيب الزوجة', 'updated_by' => 'عُدّل بواسطة',
'child_order' => 'ترتيب الابن', 'activated_at' => 'تاريخ التفعيل',
'classification' => 'التصنيف', 'activated_by_payment_id' => 'دفعة التفعيل',
'join_date' => 'تاريخ الالتحاق', 'amount' => 'المبلغ',
'marriage_date' => 'تاريخ الزواج', 'total_amount' => 'المبلغ الإجمالي',
'age_years' => 'السن (سنوات)', 'paid_amount' => 'المبلغ المدفوع',
'age_months' => 'السن (شهور)', 'remaining_balance' => 'المبلغ المتبقي',
'category' => 'الفئة', 'down_payment' => 'المقدم',
'notes' => 'ملاحظات', 'monthly_payment' => 'القسط الشهري',
'is_voided' => 'ملغى', 'payment_type' => 'نوع الدفعة',
'voided_at' => 'تاريخ الإلغاء', 'payment_method' => 'طريقة الدفع',
'void_reason' => 'سبب الإلغاء', 'payment_date' => 'تاريخ الدفع',
'description_ar' => 'الوصف', 'receipt_number' => 'رقم الإيصال',
'current_value_json' => 'القيمة الحالية', 'receipt_id' => 'رقم الإيصال',
'rule_code' => 'كود القاعدة', 'request_number' => 'رقم الطلب',
'fee_amount' => 'مبلغ الرسوم', 'addition_fee' => 'رسوم الإضافة',
'start_date' => 'تاريخ البداية', 'spouse_order' => 'ترتيب الزوجة',
'end_date' => 'تاريخ النهاية', 'child_order' => 'ترتيب الابن',
'discount_amount' => 'مبلغ الخصم', 'classification' => 'التصنيف',
'special_discount_id' => 'خصم خاص', 'join_date' => 'تاريخ الالتحاق',
'has_championship' => 'بطولات رياضية', 'marriage_date' => 'تاريخ الزواج',
'disability_documentation' => 'وثائق إعاقة', 'age_years' => 'السن (سنوات)',
'relationship_to_member' => 'صلة القرابة', 'age_months' => 'السن (شهور)',
'passport_number' => 'رقم جواز السفر', 'category' => 'الفئة',
'can_separate' => 'يمكن الفصل', 'notes' => 'ملاحظات',
'can_get_independent' => 'يمكن الاستقلال', 'description' => 'الوصف',
'processed_by' => 'معالج بواسطة', 'is_voided' => 'ملغى',
'processed_at' => 'تاريخ المعالجة', 'voided_at' => 'تاريخ الإلغاء',
'requested_by' => 'مقدم الطلب', 'void_reason' => 'سبب الإلغاء',
'related_entity_type' => 'نوع الكيان المرتبط', 'voided_by' => 'ألغي بواسطة',
'related_entity_id' => 'رقم الكيان المرتبط', 'description_ar' => 'الوصف',
default => $field, 'current_value_json' => 'القيمة الحالية',
'rule_code' => 'كود القاعدة',
'fee_amount' => 'مبلغ الرسوم',
'fine_amount' => 'مبلغ الغرامة',
'start_date' => 'تاريخ البداية',
'end_date' => 'تاريخ النهاية',
'due_date' => 'تاريخ الاستحقاق',
'discount_amount' => 'مبلغ الخصم',
'special_discount_id' => 'خصم خاص',
'special_discount_document' => 'مستند الخصم',
'has_championship' => 'بطولات رياضية',
'disability_documentation' => 'وثائق إعاقة',
'relationship_to_member' => 'صلة القرابة',
'passport_number' => 'رقم جواز السفر',
'id_type' => 'نوع الهوية',
'can_separate' => 'يمكن الفصل',
'can_get_independent' => 'يمكن الاستقلال',
'processed_by' => 'معالج بواسطة',
'processed_at' => 'تاريخ المعالجة',
'requested_by' => 'مقدم الطلب',
'related_entity_type' => 'نوع الكيان المرتبط',
'related_entity_id' => 'رقم الكيان المرتبط',
'member_id' => 'رقم العضو',
'transferred_from_death_id' => 'محوّل من حالة وفاة',
'transferred_from_waiver_id' => 'محوّل من تنازل',
'transferred_from_divorce_id' => 'محوّل من طلاق',
'transferred_from_transfer_id' => 'محوّل من فصل',
'ownership_transfer_date' => 'تاريخ نقل الملكية',
'financial_year' => 'السنة المالية',
'number_of_months' => 'عدد الأشهر',
'installment_amount' => 'مبلغ القسط',
'interest_rate' => 'نسبة الفائدة',
'check_number' => 'رقم الشيك',
'check_bank' => 'بنك الشيك',
'check_date' => 'تاريخ الشيك',
'fee_receipt_number' => 'رقم إيصال الرسوم',
'form_date' => 'تاريخ الاستمارة',
'source_member_id' => 'العضو المصدر',
'target_member_id' => 'العضو المستهدف',
'transfer_type' => 'نوع التحويل',
'separation_fee' => 'رسوم الفصل',
'total_fee' => 'إجمالي الرسوم',
'companion_surcharge' => 'رسوم ملحقين إضافيين',
'fee_percentage' => 'نسبة الرسوم',
'years_since_acquisition' => 'سنوات منذ الاكتساب',
'effective_transfer_date' => 'تاريخ الفصل الفعلي',
'completed_at' => 'تاريخ الإتمام',
'approved_at' => 'تاريخ الاعتماد',
'approved_by' => 'اعتمد بواسطة',
'board_decision_notes' => 'ملاحظات مجلس الإدارة',
default => $field,
}; };
} }
public static function getStatusLabel(string $status): string public static function getStatusLabel(string $status): string
{ {
return match ($status) { return match ($status) {
'active' => 'نشط', 'active' => 'نشط',
'inactive' => 'غير نشط', 'inactive' => 'غير نشط',
'potential' => 'محتمل', 'potential' => 'محتمل',
'under_review' => 'قيد المراجعة', 'under_review' => 'قيد المراجعة',
'accepted' => 'مقبول', 'interview_scheduled' => 'مقابلة محددة',
'rejected' => 'مرفوض', 'accepted' => 'مقبول',
'payment_pending' => 'في انتظار الدفع', 'rejected' => 'مرفوض',
'pending_payment' => 'في انتظار الدفع', 'payment_pending' => 'في انتظار الدفع',
'pending' => 'معلق', 'pending_payment' => 'في انتظار الدفع',
'processing' => 'قيد المعالجة', 'pending' => 'معلق',
'completed' => 'مكتمل', 'pending_cheques' => 'في انتظار الشيكات',
'cancelled' => 'ملغى', 'pending_form_fill' => 'في انتظار ملء الاستمارة',
'frozen' => 'مجمد', 'processing' => 'قيد المعالجة',
'suspended' => 'موقوف', 'completed' => 'مكتمل',
'dropped' => 'منسحب', 'cancelled' => 'ملغى',
'expired' => 'منتهي', 'frozen' => 'مجمد',
default => $status, 'suspended' => 'موقوف',
'dropped' => 'منسحب',
'expired' => 'منتهي',
'transferred' => 'محوّل',
'separated' => 'مفصول',
'deceased' => 'متوفي',
'requested' => 'في انتظار الدفع',
'approved' => 'معتمد',
'fee_paid' => 'تم الدفع',
'paid' => 'مدفوع',
'overdue' => 'متأخر',
'partial' => 'مدفوع جزئياً',
'voided' => 'ملغى',
default => $status,
}; };
} }
...@@ -477,7 +540,7 @@ final class AuditService ...@@ -477,7 +540,7 @@ final class AuditService
{ {
if ($value === null || $value === '') return '—'; if ($value === null || $value === '') return '—';
if (in_array($field, ['amount', 'membership_value', 'addition_fee', 'fee_amount', 'discount_amount', 'total_amount', 'down_payment', 'remaining_balance', 'monthly_payment'], true)) { if (in_array($field, ['amount', 'membership_value', 'addition_fee', 'fee_amount', 'fine_amount', 'discount_amount', 'total_amount', 'down_payment', 'remaining_balance', 'monthly_payment', 'paid_amount', 'separation_fee', 'total_fee', 'companion_surcharge', 'installment_amount'], true)) {
return number_format((float) $value, 2) . ' ج.م'; return number_format((float) $value, 2) . ' ج.م';
} }
if ($field === 'status') return self::getStatusLabel((string) $value); if ($field === 'status') return self::getStatusLabel((string) $value);
...@@ -488,6 +551,30 @@ final class AuditService ...@@ -488,6 +551,30 @@ final class AuditService
if ($field === 'payment_type') { if ($field === 'payment_type') {
return \App\Modules\Cashier\Services\PaymentRequestService::getPaymentTypeLabel((string) $value); return \App\Modules\Cashier\Services\PaymentRequestService::getPaymentTypeLabel((string) $value);
} }
if ($field === 'payment_method') {
return match ((string) $value) { 'cash' => 'نقدي', 'visa' => 'فيزا', 'bank_transfer' => 'تحويل بنكي', 'check' => 'شيك', 'instalment' => 'تقسيط', default => (string) $value };
}
if ($field === 'membership_type') {
return match ((string) $value) { 'working' => 'عامل', 'seasonal' => 'موسمي', 'honorary' => 'شرفي', 'sports' => 'رياضي', 'foreign' => 'أجنبي', default => (string) $value };
}
if ($field === 'member_category') {
return match ((string) $value) { 'working_member' => 'عضو عامل', 'seasonal_member' => 'عضو موسمي', 'honorary_member' => 'عضو شرفي', 'sports_member' => 'عضو رياضي', default => (string) $value };
}
if ($field === 'transfer_type') {
return match ((string) $value) { 'child_separation' => 'فصل أبناء', 'child_mandatory_25' => 'تحويل وجوبي (25 سنة)', 'sports_conversion' => 'تحويل رياضي', 'cross_branch' => 'تحويل بين فروع', 'full_transfer' => 'تحويل عضوية كامل', default => (string) $value };
}
if ($field === 'classification') {
return match ((string) $value) { 'active' => 'نشط', 'separated' => 'مفصول', 'graduated' => 'متخرج', 'employed' => 'موظف', 'married' => 'متزوجة', default => (string) $value };
}
if ($field === 'id_type') {
return match ((string) $value) { 'national_id' => 'بطاقة رقم قومي', 'passport' => 'جواز سفر', 'birth_certificate' => 'شهادة ميلاد', default => (string) $value };
}
if ($field === 'marital_status') {
return match ((string) $value) { 'single' => 'أعزب', 'married' => 'متزوج', 'divorced' => 'مطلق', 'widowed' => 'أرمل', default => (string) $value };
}
if ($field === 'category') {
return match ((string) $value) { 'relative' => 'قريب', 'friend' => 'صديق', 'nanny' => 'مربية', 'driver' => 'سائق', default => (string) $value };
}
return mb_substr((string) $value, 0, 200); return mb_substr((string) $value, 0, 200);
} }
......
...@@ -319,9 +319,28 @@ class MemberController extends Controller ...@@ -319,9 +319,28 @@ class MemberController extends Controller
[(int) $id] [(int) $id]
); );
// Check if this member was created via child separation transfer
$separationTransfer = null;
if (!empty($member->transferred_from_transfer_id)) {
$separationTransfer = $db->selectOne(
"SELECT tr.id, tr.source_member_id, tr.total_fee, tr.separation_fee, tr.transfer_type,
tr.completed_at as transfer_date, tr.effective_transfer_date,
m.full_name_ar as source_member_name, m.membership_number as source_number
FROM transfer_requests tr
LEFT JOIN members m ON m.id = tr.source_member_id
WHERE tr.id = ?",
[(int) $member->transferred_from_transfer_id]
);
}
// Transfer fee payment (for separated children / waiver-acquired members) // Transfer fee payment (for separated children / waiver-acquired members)
$transferFeePayment = null; $transferFeePayment = null;
if (!empty($member->transferred_from_waiver_id)) { if (!empty($member->transferred_from_transfer_id) && $separationTransfer) {
$transferFeePayment = $db->selectOne(
"SELECT amount, payment_date FROM payments WHERE member_id = ? AND payment_type = 'separation_fee' AND related_entity_type = 'transfer_requests' AND related_entity_id = ? AND is_voided = 0 ORDER BY id DESC LIMIT 1",
[(int) $separationTransfer['source_member_id'], (int) $member->transferred_from_transfer_id]
);
} elseif (!empty($member->transferred_from_waiver_id)) {
$transferFeePayment = $db->selectOne( $transferFeePayment = $db->selectOne(
"SELECT amount, payment_date FROM payments WHERE member_id = ? AND payment_type = 'waiver_fee' AND is_voided = 0 ORDER BY id DESC LIMIT 1", "SELECT amount, payment_date FROM payments WHERE member_id = ? AND payment_type = 'waiver_fee' AND is_voided = 0 ORDER BY id DESC LIMIT 1",
[(int) $id] [(int) $id]
...@@ -365,6 +384,7 @@ class MemberController extends Controller ...@@ -365,6 +384,7 @@ class MemberController extends Controller
'subscriptionStatus' => $subscriptionStatus, 'subscriptionStatus' => $subscriptionStatus,
'overdueSubscriptions' => $overdueSubscriptions, 'overdueSubscriptions' => $overdueSubscriptions,
'transferFeePayment' => $transferFeePayment, 'transferFeePayment' => $transferFeePayment,
'separationTransfer' => $separationTransfer,
]); ]);
} }
......
...@@ -162,7 +162,7 @@ $canEdit = can('member.edit') && (!$isLocked || ($isSuperAdmin ?? false)); ...@@ -162,7 +162,7 @@ $canEdit = can('member.edit') && (!$isLocked || ($isSuperAdmin ?? false));
<!-- ═══════════════════════════════════════════════ --> <!-- ═══════════════════════════════════════════════ -->
<!-- TRANSFER ORIGIN DETAILS --> <!-- TRANSFER ORIGIN DETAILS -->
<!-- ═══════════════════════════════════════════════ --> <!-- ═══════════════════════════════════════════════ -->
<?php if (!empty($deathTransfer) || !empty($waiverTransfer) || !empty($divorceTransfer)): ?> <?php if (!empty($deathTransfer) || !empty($waiverTransfer) || !empty($divorceTransfer) || !empty($separationTransfer)): ?>
<div class="card" style="margin-bottom:20px;padding:20px;background:#F0F9FF;border:1px solid #BAE6FD;"> <div class="card" style="margin-bottom:20px;padding:20px;background:#F0F9FF;border:1px solid #BAE6FD;">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;"> <div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;">
<span style="font-size:18px;">🔄</span> <span style="font-size:18px;">🔄</span>
...@@ -190,6 +190,14 @@ $canEdit = can('member.edit') && (!$isLocked || ($isSuperAdmin ?? false)); ...@@ -190,6 +190,14 @@ $canEdit = can('member.edit') && (!$isLocked || ($isSuperAdmin ?? false));
<tr><td style="padding:6px 0;color:#6B7280;">المبلغ المدفوع فعلياً</td><td style="padding:6px 0;font-weight:700;color:#059669;font-size:15px;"><?= number_format((float) $transferFeePayment['amount'], 2) ?> ج.م</td></tr> <tr><td style="padding:6px 0;color:#6B7280;">المبلغ المدفوع فعلياً</td><td style="padding:6px 0;font-weight:700;color:#059669;font-size:15px;"><?= number_format((float) $transferFeePayment['amount'], 2) ?> ج.م</td></tr>
<tr><td style="padding:6px 0;color:#6B7280;">تاريخ الدفع</td><td style="padding:6px 0;"><?= e($transferFeePayment['payment_date'] ?? '—') ?></td></tr> <tr><td style="padding:6px 0;color:#6B7280;">تاريخ الدفع</td><td style="padding:6px 0;"><?= e($transferFeePayment['payment_date'] ?? '—') ?></td></tr>
<?php endif; ?> <?php endif; ?>
<?php elseif (!empty($separationTransfer)): ?>
<tr><td style="padding:6px 0;color:#6B7280;width:160px;">فُصل من عضوية</td><td style="padding:6px 0;font-weight:600;"><a href="/members/<?= (int) $separationTransfer['source_member_id'] ?>" style="color:#14B8A6;"><?= e($separationTransfer['source_member_name'] ?? '—') ?></a> (<?= e($separationTransfer['source_number'] ?? '') ?>)</td></tr>
<tr><td style="padding:6px 0;color:#6B7280;">تاريخ الفصل</td><td style="padding:6px 0;font-weight:600;"><?= e(substr($separationTransfer['transfer_date'] ?? '', 0, 10)) ?></td></tr>
<tr><td style="padding:6px 0;color:#6B7280;">رسوم الفصل المدفوعة</td><td style="padding:6px 0;font-weight:700;color:#059669;font-size:15px;"><?= number_format((float) ($transferFeePayment['amount'] ?? $separationTransfer['total_fee'] ?? 0), 2) ?> ج.م</td></tr>
<?php if (!empty($transferFeePayment['payment_date'])): ?>
<tr><td style="padding:6px 0;color:#6B7280;">تاريخ الدفع</td><td style="padding:6px 0;"><?= e($transferFeePayment['payment_date']) ?></td></tr>
<?php endif; ?>
<tr><td style="padding:6px 0;color:#6B7280;">تفاصيل الطلب</td><td style="padding:6px 0;"><a href="/transfers/<?= (int) $separationTransfer['id'] ?>" style="color:#0D7377;font-weight:600;">عرض طلب الفصل #<?= (int) $separationTransfer['id'] ?></a></td></tr>
<?php endif; ?> <?php endif; ?>
</table> </table>
</div> </div>
...@@ -754,10 +762,13 @@ $hasIncomplete = !empty(array_filter($missingSteps, fn($s) => !$s['done'])); ...@@ -754,10 +762,13 @@ $hasIncomplete = !empty(array_filter($missingSteps, fn($s) => !$s['done']));
<div style="padding:15px 20px;"> <div style="padding:15px 20px;">
<div style="display:grid;grid-template-columns:<?= !empty($specialDiscount) ? '1fr 1fr 1fr' : '1fr 1fr' ?>;gap:15px;"> <div style="display:grid;grid-template-columns:<?= !empty($specialDiscount) ? '1fr 1fr 1fr' : '1fr 1fr' ?>;gap:15px;">
<?php <?php
$isTransferred = !empty($member->transferred_from_death_id) || !empty($member->transferred_from_waiver_id) || !empty($member->transferred_from_divorce_id); $isTransferred = !empty($member->transferred_from_death_id) || !empty($member->transferred_from_waiver_id) || !empty($member->transferred_from_divorce_id) || !empty($member->transferred_from_transfer_id);
$displayValue = $member->membership_value ?? '0'; $displayValue = $member->membership_value ?? '0';
$valueLabel = 'قيمة العضوية'; $valueLabel = 'قيمة العضوية';
if ($isTransferred && !empty($transferFeePayment)) { if (!empty($member->transferred_from_transfer_id) && !empty($separationTransfer)) {
$displayValue = $transferFeePayment['amount'] ?? $separationTransfer['total_fee'] ?? $displayValue;
$valueLabel = 'رسوم الفصل المدفوعة';
} elseif ($isTransferred && !empty($transferFeePayment)) {
$displayValue = $transferFeePayment['amount']; $displayValue = $transferFeePayment['amount'];
$valueLabel = 'المبلغ المدفوع عند الانتقال'; $valueLabel = 'المبلغ المدفوع عند الانتقال';
} elseif ($isTransferred && !empty($deathTransfer['paid_amount'])) { } elseif ($isTransferred && !empty($deathTransfer['paid_amount'])) {
......
...@@ -185,6 +185,8 @@ final class TransferProcessor ...@@ -185,6 +185,8 @@ final class TransferProcessor
} }
} }
$newMemberData['transferred_from_transfer_id'] = $transferRequestId;
$newMemberId = $db->insert('members', $newMemberData); $newMemberId = $db->insert('members', $newMemberData);
// 5. Record number chain // 5. Record number chain
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<td style="font-size:13px;"><?= match($r['transfer_type'] ?? '') { 'child_separation' => 'فصل ابن', 'child_mandatory_25' => 'تحويل وجوبي (25)', 'sports_conversion' => 'تحويل رياضي', 'cross_branch' => 'تحويل بين فروع', default => $r['transfer_type'] ?? '' } ?></td> <td style="font-size:13px;"><?= match($r['transfer_type'] ?? '') { 'child_separation' => 'فصل ابن', 'child_mandatory_25' => 'تحويل وجوبي (25)', 'sports_conversion' => 'تحويل رياضي', 'cross_branch' => 'تحويل بين فروع', default => $r['transfer_type'] ?? '' } ?></td>
<td style="font-weight:600;"><?= money($r['separation_fee'] ?? '0') ?></td> <td style="font-weight:600;"><?= money($r['separation_fee'] ?? '0') ?></td>
<td style="font-weight:600;color:#0D7377;"><?= e($r['new_membership_number'] ?? '—') ?></td> <td style="font-weight:600;color:#0D7377;"><?= e($r['new_membership_number'] ?? '—') ?></td>
<td><span style="color:<?= match($r['status'] ?? '') { 'completed' => '#059669', 'approved' => '#0284C7', default => '#D97706' } ?>;font-weight:600;"><?= match($r['status'] ?? '') { 'requested' => 'مقدم', 'approved' => 'معتمد', 'completed' => 'مكتمل', 'rejected' => 'مرفوض', default => $r['status'] ?? '' } ?></span></td> <td><span style="color:<?= match($r['status'] ?? '') { 'completed' => '#059669', 'fee_paid' => '#2563EB', 'approved' => '#0284C7', 'rejected' => '#DC2626', default => '#D97706' } ?>;font-weight:600;"><?= match($r['status'] ?? '') { 'requested' => 'في انتظار الدفع', 'approved' => 'معتمد', 'fee_paid' => 'تم الدفع', 'completed' => 'مكتمل', 'rejected' => 'مرفوض', default => $r['status'] ?? '' } ?></span></td>
<td style="font-size:12px;"><?= e(substr($r['created_at'] ?? '', 0, 10)) ?></td> <td style="font-size:12px;"><?= e(substr($r['created_at'] ?? '', 0, 10)) ?></td>
<td><a href="/transfers/<?= (int) $r['id'] ?>" class="btn btn-sm btn-outline">عرض</a></td> <td><a href="/transfers/<?= (int) $r['id'] ?>" class="btn btn-sm btn-outline">عرض</a></td>
</tr> </tr>
......
...@@ -24,7 +24,7 @@ if ($transfer['transfer_type'] === 'full_transfer' && !empty($transfer['notes']) ...@@ -24,7 +24,7 @@ if ($transfer['transfer_type'] === 'full_transfer' && !empty($transfer['notes'])
<tr><td style="padding:8px 0;color:#6B7280;">الزوج/ة</td><td style="padding:8px 0;font-weight:600;"><?= e($transfer['spouse_name']) ?></td></tr> <tr><td style="padding:8px 0;color:#6B7280;">الزوج/ة</td><td style="padding:8px 0;font-weight:600;"><?= e($transfer['spouse_name']) ?></td></tr>
<?php endif; ?> <?php endif; ?>
<tr><td style="padding:8px 0;color:#6B7280;">النوع</td><td style="padding:8px 0;font-weight:600;"><?= e($typeLabels[$transfer['transfer_type']] ?? $transfer['transfer_type']) ?></td></tr> <tr><td style="padding:8px 0;color:#6B7280;">النوع</td><td style="padding:8px 0;font-weight:600;"><?= e($typeLabels[$transfer['transfer_type']] ?? $transfer['transfer_type']) ?></td></tr>
<tr><td style="padding:8px 0;color:#6B7280;">الحالة</td><td style="padding:8px 0;font-weight:700;color:<?= match($transfer['status']) { 'completed' => '#059669', 'fee_paid' => '#2563EB', 'approved' => '#0284C7', 'rejected' => '#DC2626', default => '#D97706' } ?>;"><?= match($transfer['status']) { 'completed' => 'مكتمل', 'fee_paid' => 'تم الدفع', 'approved' => 'معتمد', 'rejected' => 'مرفوض', default => 'مقدّم' } ?></td></tr> <tr><td style="padding:8px 0;color:#6B7280;">الحالة</td><td style="padding:8px 0;font-weight:700;color:<?= match($transfer['status']) { 'completed' => '#059669', 'fee_paid' => '#2563EB', 'approved' => '#0284C7', 'rejected' => '#DC2626', default => '#D97706' } ?>;"><?= match($transfer['status']) { 'completed' => 'مكتمل', 'fee_paid' => 'تم الدفع', 'approved' => 'معتمد — في انتظار الدفع', 'rejected' => 'مرفوض', 'requested' => 'في انتظار الدفع', default => $transfer['status'] } ?></td></tr>
<?php if ($transfer['new_membership_number']): ?><tr><td style="padding:8px 0;color:#6B7280;">رقم العضوية (نفس الرقم)</td><td style="padding:8px 0;font-weight:700;color:#0D7377;font-size:20px;"><?= e($transfer['new_membership_number']) ?></td></tr><?php endif; ?> <?php if ($transfer['new_membership_number']): ?><tr><td style="padding:8px 0;color:#6B7280;">رقم العضوية (نفس الرقم)</td><td style="padding:8px 0;font-weight:700;color:#0D7377;font-size:20px;"><?= e($transfer['new_membership_number']) ?></td></tr><?php endif; ?>
<?php if (!empty($transfer['form_number'])): ?><tr><td style="padding:8px 0;color:#6B7280;">رقم الاستمارة</td><td style="padding:8px 0;font-weight:700;color:#1A1A2E;"><?= e($transfer['form_number']) ?></td></tr><?php endif; ?> <?php if (!empty($transfer['form_number'])): ?><tr><td style="padding:8px 0;color:#6B7280;">رقم الاستمارة</td><td style="padding:8px 0;font-weight:700;color:#1A1A2E;"><?= e($transfer['form_number']) ?></td></tr><?php endif; ?>
<?php if ($transfer['source_companions_count'] !== null): ?> <?php if ($transfer['source_companions_count'] !== null): ?>
......
<?php
declare(strict_types=1);
return [
'up' => "ALTER TABLE members ADD COLUMN transferred_from_transfer_id BIGINT UNSIGNED NULL AFTER transferred_from_waiver_id;
UPDATE members m
JOIN transfer_requests tr ON tr.target_member_id = m.id AND tr.status = 'completed'
SET m.transferred_from_transfer_id = tr.id
WHERE m.transferred_from_transfer_id IS NULL",
'down' => "ALTER TABLE members DROP COLUMN transferred_from_transfer_id",
];
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