Commit 6c3db858 authored by Mahmoud Aglan's avatar Mahmoud Aglan

Fix waiver duplicate key error + wrong fee calculation + member search name mismatch

TKT-71: Fixed duplicate entry for membership_number by reversing operation
order in WaiverProcessor — source member's number is now NULLed BEFORE
assigning it to target member, preventing unique constraint violation.

TKT-71: Waiver fee now calculated from current pricing_configs value instead
of the member's stored membership_value (old/historical price).

TKT-69: Member search duplicate check now shows the entity type (spouse/child)
and the parent member's number, clarifying which person is being shown.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 42f0ccc6
......@@ -243,7 +243,11 @@ document.addEventListener('DOMContentLoaded', function() {
resultsBox.style.display = 'block';
feedback.innerHTML = '<span style="color:#059669;">الرقم القومي صالح — تم استخراج البيانات</span>';
if (data.duplicate) {
feedback.innerHTML += '<br><span style="color:#DC2626;">مسجل بالفعل: ' + data.duplicate.full_name_ar + '</span>';
var dupType = data.duplicate.type;
var dupLabel = dupType === 'spouse' ? 'زوج/ة العضو رقم ' + data.duplicate.membership_number
: dupType === 'child' ? 'ابن/ة العضو رقم ' + data.duplicate.membership_number
: 'عضو';
feedback.innerHTML += '<br><span style="color:#DC2626;">⚠️ مسجل بالفعل كـ' + dupLabel + ': ' + data.duplicate.full_name_ar + '</span>';
}
} else {
resultsBox.style.display = 'none';
......
......@@ -30,7 +30,7 @@ class WaiverController extends Controller
$member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [(int) $memberId]);
if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');
$membershipValue = $member['membership_value'] ?? '0.00';
$membershipValue = self::getCurrentMembershipValue($db, $member);
$waiverPctData = RuleEngine::get('WAIVER_FEE');
$waiverPct = $waiverPctData['percentage'] ?? '30.00';
$waiverFee = bcdiv(bcmul($membershipValue, $waiverPct, 4), '100', 2);
......@@ -56,7 +56,7 @@ class WaiverController extends Controller
if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');
if (!$member['membership_number']) return $this->redirect("/members/{$memberId}")->withError('العضو ليس لديه رقم عضوية');
$membershipValue = $member['membership_value'] ?? '0.00';
$membershipValue = self::getCurrentMembershipValue($db, $member);
$waiverPctData = RuleEngine::get('WAIVER_FEE');
$waiverPct = $waiverPctData['percentage'] ?? '30.00';
$waiverFee = bcdiv(bcmul($membershipValue, $waiverPct, 4), '100', 2);
......@@ -228,4 +228,29 @@ class WaiverController extends Controller
return $this->redirect("/waivers/{$id}")->withSuccess('تم إتمام التنازل — العضوية نُقلت بنجاح');
}
private static function getCurrentMembershipValue(\App\Core\Database $db, array $member): string
{
$branchId = (int) ($member['branch_id'] ?? 1);
$qualId = !empty($member['qualification_id']) ? (int) $member['qualification_id'] : null;
$mType = $member['membership_type'] ?? 'working';
if ($qualId) {
$currentPrice = $db->selectOne(
"SELECT price FROM pricing_configs WHERE branch_id = ? AND qualification_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY effective_from DESC LIMIT 1",
[$branchId, $qualId, $mType]
);
} else {
$currentPrice = $db->selectOne(
"SELECT price FROM pricing_configs WHERE branch_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY price ASC LIMIT 1",
[$branchId, $mType]
);
}
if ($currentPrice && bccomp($currentPrice['price'], '0', 2) > 0) {
return $currentPrice['price'];
}
return $member['membership_value'] ?? '0.00';
}
}
\ No newline at end of file
......@@ -32,14 +32,7 @@ final class WaiverProcessor
// Archive snapshot
$snapshotId = ArchiveService::takeSnapshot('members', (int) $sourceMember['id'], 'waiver', 'تنازل — طلب #' . $waiverId);
// Transfer membership number to target member
$db->update('members', [
'membership_number' => $waiver['membership_number'],
'status' => 'active',
'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [(int) $waiver['target_member_id']]);
// Archive source member (remove number, set archived)
// Archive source member FIRST (release number to avoid unique constraint violation)
$db->update('members', [
'membership_number' => null,
'status' => 'waived',
......@@ -49,6 +42,13 @@ final class WaiverProcessor
'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [(int) $waiver['source_member_id']]);
// Transfer membership number to target member
$db->update('members', [
'membership_number' => $waiver['membership_number'],
'status' => 'active',
'updated_at' => date('Y-m-d H:i:s'),
], '`id` = ?', [(int) $waiver['target_member_id']]);
// Record number chain
ArchiveService::recordNumberTransfer($waiver['membership_number'], 'waiver', 'members', (int) $waiver['target_member_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