Commit b86c24f6 authored by Mahmoud Aglan's avatar Mahmoud Aglan

feat(members): integrate regulatory discounts into membership form

- Add regulatory_discount_id/amount/document columns to members table
- Add eligibility type selector with conditional sections per type
- Auto-verification for cross-branch (checks members DB) and club employee (HR)
- Document upload for types requiring manual proof (gov, ministry, board, group)
- AJAX eligibility check button calls /pricing/regulatory-discounts/check-eligibility
- Creates audit trail application record on form submit (status: pending)
- Dynamic UI: shows/hides relevant fields based on selected type
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 3f42fa01
...@@ -758,6 +758,61 @@ class MemberController extends Controller ...@@ -758,6 +758,61 @@ class MemberController extends Controller
} }
} }
// Regulatory discount
$regDiscountId = trim((string) ($data['regulatory_discount_id'] ?? ''));
if ($regDiscountId !== '' && $regDiscountId !== '0') {
$regRule = $db->selectOne("SELECT * FROM regulatory_discounts WHERE id = ? AND is_active = 1", [(int) $regDiscountId]);
if ($regRule) {
$update['regulatory_discount_id'] = (int) $regDiscountId;
$mValue = $update['membership_value'] ?? ($member->membership_value ?? '0.00');
$pct = $regRule['discount_percentage'];
if ($regRule['max_discount_percentage'] !== null) {
$pct = min((float) $pct, (float) $regRule['max_discount_percentage']);
$pct = number_format($pct, 2, '.', '');
}
$update['regulatory_discount_amount'] = bcmul($mValue, bcdiv($pct, '100', 4), 2);
// Upload proof document
if (!empty($_FILES['regulatory_discount_document']['tmp_name'])) {
$file = $_FILES['regulatory_discount_document'];
$allowedTypes = ['application/pdf', 'image/jpeg', 'image/png'];
$finfo = new \finfo(FILEINFO_MIME_TYPE);
$mimeType = $finfo->file($file['tmp_name']);
if (in_array($mimeType, $allowedTypes, true) && $file['size'] <= 10485760) {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$storedName = 'reg_discount_' . (int) $id . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
$uploadDir = App::getInstance()->basePath() . '/storage/uploads/discounts/';
if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);
if (move_uploaded_file($file['tmp_name'], $uploadDir . $storedName)) {
$update['regulatory_discount_document'] = 'storage/uploads/discounts/' . $storedName;
}
}
}
// Create application record for audit trail
\App\Modules\Pricing\Services\RegulatoryDiscountService::createApplication([
'regulatory_discount_id' => (int) $regDiscountId,
'member_id' => (int) $id,
'applicant_name' => $member->full_name_ar,
'discount_percentage' => $pct,
'original_amount' => $mValue,
'discount_amount' => $update['regulatory_discount_amount'],
'final_amount' => bcsub($mValue, $update['regulatory_discount_amount'], 2),
'status' => 'pending',
'verification_data' => [
'eligibility_type' => $data['regulatory_eligibility_type'] ?? $regRule['eligibility_type'],
'source_branch_id' => $data['reg_source_branch_id'] ?? null,
'employee_id' => $data['reg_employee_id'] ?? null,
'group_quantity' => $data['reg_group_quantity'] ?? null,
],
'created_by' => session()->get('user_id'),
]);
}
} elseif ($regDiscountId === '') {
$update['regulatory_discount_id'] = null;
$update['regulatory_discount_amount'] = null;
}
if ($member->status === 'potential') $update['status'] = 'under_review'; if ($member->status === 'potential') $update['status'] = 'under_review';
if (!empty($update)) $member->update($update); if (!empty($update)) $member->update($update);
......
This diff is collapsed.
<?php
declare(strict_types=1);
return function (\App\Core\Database $db): void {
$db->raw("
ALTER TABLE `members`
ADD COLUMN `regulatory_discount_id` BIGINT UNSIGNED NULL AFTER `discount_amount`,
ADD COLUMN `regulatory_discount_amount` DECIMAL(15,2) NULL AFTER `regulatory_discount_id`,
ADD COLUMN `regulatory_discount_document` VARCHAR(500) NULL AFTER `regulatory_discount_amount`,
ADD INDEX `idx_members_regulatory_discount` (`regulatory_discount_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