Commit 75815e05 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fixed shit

parent 0af2ed0b
......@@ -7,12 +7,10 @@ use App\Core\App;
use App\Modules\Children\Models\Child;
use App\Modules\Pricing\Services\PricingEngine;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Members\Services\FormFeeService;
final class ChildFeeCalculator
{
/**
* Calculate the fee and classification for adding a child.
*/
public static function calculate(int $memberId, array $childData): array
{
$db = App::getInstance()->db();
......@@ -27,7 +25,6 @@ final class ChildFeeCalculator
return ['error' => 'قيمة العضوية غير محددة', 'fee' => '0.00', 'classification' => 'included'];
}
// Get child age
$childDob = $childData['date_of_birth'] ?? null;
$childAge = 0;
if ($childDob) {
......@@ -35,22 +32,11 @@ final class ChildFeeCalculator
$childAge = $age['years'];
}
// Count existing children under 18 to determine order
$childrenUnder18 = Child::countActiveUnder18ForMember($memberId);
$totalChildren = Child::countActiveForMember($memberId);
$childOrder = $totalChildren + 1;
// Use PricingEngine
$feeResult = PricingEngine::calculateChildFee($membershipValue, $childAge, $childOrder);
// Add form fee if post-creation
$formFee = '0.00';
if ($member['status'] !== 'potential') {
$formFeeData = RuleEngine::get('FORM_ADDITION_FEE');
$formFee = $formFeeData['amount'] ?? '570.00';
}
// Determine classification
$classification = $feeResult['classification'] ?? 'included';
if ($classification === 'not_accepted') {
return [
......@@ -69,18 +55,20 @@ final class ChildFeeCalculator
$childFee = $feeResult['fee'] ?? '0.00';
$formFee = FormFeeService::getFormFee($memberId, $member);
return [
'child_order' => $childOrder,
'child_age' => $childAge,
'children_under_18' => $childrenUnder18,
'membership_value' => $membershipValue,
'classification' => $classification,
'fee' => $childFee,
'percentage' => $feeResult['percentage'] ?? '0.00',
'form_fee' => $formFee,
'total_fee' => bcadd($childFee, $formFee, 2),
'rule_applied' => $feeResult['rule_applied'] ?? '',
'error' => null,
'child_order' => $childOrder,
'child_age' => $childAge,
'children_under_18' => Child::countActiveUnder18ForMember($memberId),
'membership_value' => $membershipValue,
'classification' => $classification,
'fee' => $childFee,
'percentage' => $feeResult['percentage'] ?? '0.00',
'form_fee' => $formFee,
'total_fee' => bcadd($childFee, $formFee, 2),
'rule_applied' => $feeResult['rule_applied'] ?? '',
'error' => null,
];
}
}
\ No newline at end of file
}
<?php
declare(strict_types=1);
namespace App\Modules\Members\Services;
use App\Core\App;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\ServiceCatalog\Models\ServicePrice;
/**
* Determines whether a dependant addition needs a form fee (570 EGP).
*
* Business rule:
* - During initial membership creation (member status = potential / under_review),
* all additions are on the same initial form — no additional form fee.
* - After activation, any modification needs a "form addition" (570 EGP).
* - Multiple additions within the SAME form session share one form fee.
* A form session is "open" if a form fee was paid (or is pending) within
* the configured validity window (default 30 days).
*/
final class FormFeeService
{
/**
* Check if the member is still on the initial membership form.
*/
public static function isOnInitialForm(array $member): bool
{
return in_array($member['status'] ?? '', ['potential', 'under_review'], true);
}
/**
* Check if there's an active (open) addition form session for this member.
*
* An addition form is "open" if any addition_fee payment request was created
* within the configured validity window. The form fee is embedded in the first
* addition's total — subsequent additions within the same window share it.
*/
public static function hasOpenAdditionForm(int $memberId): bool
{
$db = App::getInstance()->db();
$validityDays = (int) (RuleEngine::getValue('ADDITION_FORM_VALIDITY_DAYS', 'value') ?? 30);
$cutoff = date('Y-m-d H:i:s', strtotime("-{$validityDays} days"));
$existing = $db->selectOne(
"SELECT id FROM payment_requests
WHERE member_id = ? AND payment_type = 'addition_fee' AND is_voided = 0
AND status IN ('pending', 'processing', 'completed')
AND created_at >= ?
LIMIT 1",
[$memberId, $cutoff]
);
if ($existing) return true;
$paid = $db->selectOne(
"SELECT id FROM payments
WHERE member_id = ? AND payment_type = 'addition_fee' AND is_voided = 0
AND created_at >= ?
LIMIT 1",
[$memberId, $cutoff]
);
return $paid !== null;
}
/**
* Get the form fee that should be charged for an addition.
* Returns '0.00' if on initial form or if an addition form is already open.
*/
public static function getFormFee(int $memberId, array $member): string
{
if (self::isOnInitialForm($member)) {
return '0.00';
}
if (self::hasOpenAdditionForm($memberId)) {
return '0.00';
}
$feeData = RuleEngine::get('FORM_ADDITION_FEE');
return $feeData['amount'] ?? ServicePrice::getPrice('SVC_ADDITION_FORM', '570.00');
}
/**
* Check if this is a "free" spouse slot on the initial form.
* Rule: first N spouses are free (default N=1) during initial creation.
*/
public static function isSpouseFreeOnInitialForm(int $memberId, int $spouseOrder, array $member): bool
{
if (!self::isOnInitialForm($member)) {
return false;
}
$maxFree = (int) (RuleEngine::getValue('INITIAL_FREE_SPOUSES_COUNT', 'value') ?? 1);
return $spouseOrder <= $maxFree;
}
/**
* Check if this child is in a "free" slot on the initial form.
* Rule: first N children under max age are free (default N=2, age<18).
* Uses INITIAL_FREE_CHILDREN_COUNT for the initial form specifically,
* and CHILD_INCLUDED_MAX_COUNT / CHILD_INCLUDED_MAX_AGE for general classification.
*/
public static function isChildFreeOnInitialForm(int $memberId, int $childOrder, int $childAge, array $member): bool
{
if (!self::isOnInitialForm($member)) {
return false;
}
$maxFreeCount = (int) (RuleEngine::getValue('INITIAL_FREE_CHILDREN_COUNT', 'value') ?? 2);
$maxFreeAge = (int) (RuleEngine::getValue('CHILD_INCLUDED_MAX_AGE', 'value') ?? 18);
return $childOrder <= $maxFreeCount && $childAge < $maxFreeAge;
}
}
......@@ -174,7 +174,7 @@ final class MemberNumberGenerator
try {
$db = App::getInstance()->db();
$fee = $db->selectOne(
"SELECT base_amount FROM service_catalog WHERE service_code = 'FORM_NEW_MEMBERSHIP' AND is_active = 1 LIMIT 1"
"SELECT base_amount FROM service_catalog WHERE service_code IN ('SVC_NEW_FORM','FORM_NEW_MEMBERSHIP') AND is_active = 1 ORDER BY service_code ASC LIMIT 1"
);
if ($fee && $fee['base_amount']) {
return $fee['base_amount'];
......
......@@ -5,24 +5,21 @@ namespace App\Modules\Spouses\Services;
use App\Core\App;
use App\Modules\Spouses\Models\Spouse;
use App\Modules\ServiceCatalog\Models\ServicePrice;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Members\Services\FormFeeService;
/**
* Spouse Fee Calculator
* Spouse Fee Calculator — all percentages/amounts read from RuleEngine.
*
* RULES FROM CLUB REGULATIONS:
* ═══════════════════════════════════════════════════════════════
* 1st Spouse (same form / initial creation): FREE (included in membership value)
* 1st Spouse (added later, أساسي basis): 15% of membership value + 570 form
* 1st Spouse (added later, مكتسب acquired): 50% of membership value + 570 form
* Foreign Spouse (1st): 15% of membership value
* 2nd Spouse: 10% of membership value + 150 EGP × years
* 3rd Spouse: 20% of membership value + 200 EGP × years
* 4th Spouse: 30% of membership value + 300 EGP × years
* Years = from marriage date or membership acquisition, whichever LATER
* Partial year = full year (كسر السنة سنة كاملة)
* Late addition = +570 EGP form fee
* ═══════════════════════════════════════════════════════════════
* RULES (editable via /rules admin):
* 1st Spouse (initial form, not foreign): FREE (INITIAL_FREE_SPOUSES_COUNT)
* 1st Spouse (late, basic member): SPOUSE_BASE_MEMBER_FEE %
* 1st Spouse (late, acquired member): SPOUSE_ACQUIRED_MEMBER_FEE %
* Foreign Spouse: SPOUSE_FOREIGN_FEE %
* 2nd Spouse: SPOUSE_2ND_FEE (percentage + annual_flat × years)
* 3rd Spouse: SPOUSE_3RD_FEE (percentage + annual_flat × years)
* 4th+ Spouse: SPOUSE_4TH_FEE (percentage + annual_flat × years)
* Late addition form fee: FORM_ADDITION_FEE (shared via FormFeeService)
*/
final class SpouseFeeCalculator
{
......@@ -37,39 +34,26 @@ final class SpouseFeeCalculator
$membershipValue = $member['membership_value'] ?? '0.00';
// ── HARD BLOCK: No membership value = no spouse ──
if (bccomp($membershipValue, '0.01', 2) < 0) {
return self::error('يجب تحديد قيمة العضوية أولاً (ملء الاستمارة واختيار المؤهل)');
}
// ── Determine spouse order ──
$existingCount = Spouse::countActiveForMember($memberId);
$spouseOrder = $existingCount + 1;
// ── Is this during initial creation or later? ──
// "initial" = member status is still potential AND no membership_fee/down_payment paid yet
$isInitialCreation = in_array($member['status'] ?? '', ['potential', 'under_review']);
// Even during initial creation, only the FIRST spouse is free
// 2nd/3rd/4th ALWAYS have fees
$isFirstSpouseDuringCreation = ($spouseOrder === 1 && $isInitialCreation);
$isInitialCreation = FormFeeService::isOnInitialForm($member);
$isFirstFreeSlot = FormFeeService::isSpouseFreeOnInitialForm($memberId, $spouseOrder, $member);
// Late addition = member is already active/accepted = must pay form fee
$isLateAddition = !in_array($member['status'] ?? '', ['potential', 'under_review']);
$formFee = $isLateAddition ? ServicePrice::getPrice('SVC_ADDITION_FORM', '570.00') : '0.00';
$formFee = FormFeeService::getFormFee($memberId, $member);
// ── Is the member acquired (مكتسب)? ──
$isAcquiredMember = self::isAcquiredMember($memberId);
// ── Nationality check ──
$nationality = trim($spouseData['nationality'] ?? 'مصري');
$isForeign = ($nationality !== 'مصري' && $nationality !== '' && $nationality !== 'Egyptian');
// ── Marriage date for per-year calculation ──
$marriageDate = $spouseData['marriage_date'] ?? null;
$memberCreatedDate = substr($member['created_at'] ?? date('Y-m-d'), 0, 10);
// ── Calculate based on spouse order ──
$percentage = '0.00';
$percentageFee = '0.00';
$annualPerYear = '0.00';
......@@ -78,65 +62,63 @@ final class SpouseFeeCalculator
$ruleApplied = '';
switch (true) {
// ═══ 1ST SPOUSE ═══
case ($spouseOrder === 1):
if ($isFirstSpouseDuringCreation && !$isForeign) {
// Included in base price — truly free
if ($isFirstFreeSlot && !$isForeign) {
$percentage = '0.00';
$ruleApplied = 'الزوجة الأولى — مشمولة في قيمة العضوية الأساسية (بدون رسوم إضافية)';
} elseif ($isForeign) {
$percentage = '15.00';
$ruleApplied = 'زوج/ة أجنبي — 15% من قيمة العضوية';
$data = RuleEngine::get('SPOUSE_FOREIGN_FEE');
$percentage = $data['percentage'] ?? '15.00';
$ruleApplied = 'زوج/ة أجنبي — ' . $percentage . '% من قيمة العضوية';
} elseif ($isAcquiredMember) {
$percentage = '50.00';
$ruleApplied = 'إضافة زوج/ة لعضو مكتسب العضوية (فصل/طلاق/وفاة/تنازل) — 50% من قيمة العضوية';
$data = RuleEngine::get('SPOUSE_ACQUIRED_MEMBER_FEE');
$percentage = $data['percentage'] ?? '50.00';
$ruleApplied = 'إضافة زوج/ة لعضو مكتسب العضوية (فصل/طلاق/وفاة/تنازل) — ' . $percentage . '% من قيمة العضوية';
} else {
$percentage = '15.00';
$ruleApplied = 'إضافة زوج/ة لعضو أساس العضوية (إضافة لاحقة) — 15% من قيمة العضوية';
$data = RuleEngine::get('SPOUSE_BASE_MEMBER_FEE');
$percentage = $data['percentage'] ?? '15.00';
$ruleApplied = 'إضافة زوج/ة لعضو أساس العضوية (إضافة لاحقة) — ' . $percentage . '% من قيمة العضوية';
}
$percentageFee = bcdiv(bcmul($membershipValue, $percentage, 4), '100', 2);
break;
// ═══ 2ND SPOUSE ═══
case ($spouseOrder === 2):
$percentage = '10.00';
$annualPerYear = '150.00';
$ruleApplied = 'الزوجة الثانية — 10% من قيمة العضوية + 150 ج.م عن كل سنة';
$data = RuleEngine::get('SPOUSE_2ND_FEE');
$percentage = $data['percentage'] ?? '10.00';
$annualPerYear = $data['annual_flat'] ?? '150.00';
$ruleApplied = 'الزوجة الثانية — ' . $percentage . '% من قيمة العضوية + ' . $annualPerYear . ' ج.م عن كل سنة';
$percentageFee = bcdiv(bcmul($membershipValue, $percentage, 4), '100', 2);
$yearCount = self::calculateYears($marriageDate, $memberCreatedDate);
$yearlyTotal = bcmul($annualPerYear, (string) $yearCount, 2);
break;
// ═══ 3RD SPOUSE ═══
case ($spouseOrder === 3):
$percentage = '20.00';
$annualPerYear = '200.00';
$ruleApplied = 'الزوجة الثالثة — 20% من قيمة العضوية + 200 ج.م عن كل سنة';
$data = RuleEngine::get('SPOUSE_3RD_FEE');
$percentage = $data['percentage'] ?? '20.00';
$annualPerYear = $data['annual_flat'] ?? '200.00';
$ruleApplied = 'الزوجة الثالثة — ' . $percentage . '% من قيمة العضوية + ' . $annualPerYear . ' ج.م عن كل سنة';
$percentageFee = bcdiv(bcmul($membershipValue, $percentage, 4), '100', 2);
$yearCount = self::calculateYears($marriageDate, $memberCreatedDate);
$yearlyTotal = bcmul($annualPerYear, (string) $yearCount, 2);
break;
// ═══ 4TH SPOUSE ═══
case ($spouseOrder >= 4):
$percentage = '30.00';
$annualPerYear = '300.00';
$ruleApplied = 'الزوجة الرابعة — 30% من قيمة العضوية + 300 ج.م عن كل سنة';
$data = RuleEngine::get('SPOUSE_4TH_FEE');
$percentage = $data['percentage'] ?? '30.00';
$annualPerYear = $data['annual_flat'] ?? '300.00';
$ruleApplied = 'الزوجة الرابعة — ' . $percentage . '% من قيمة العضوية + ' . $annualPerYear . ' ج.م عن كل سنة';
$percentageFee = bcdiv(bcmul($membershipValue, $percentage, 4), '100', 2);
$yearCount = self::calculateYears($marriageDate, $memberCreatedDate);
$yearlyTotal = bcmul($annualPerYear, (string) $yearCount, 2);
break;
}
// ── Total ──
$additionFee = bcadd($percentageFee, $yearlyTotal, 2);
$totalFee = bcadd($additionFee, $formFee, 2);
// ── SANITY CHECK: 2nd+ spouse must NEVER be free ──
if ($spouseOrder >= 2 && bccomp($additionFee, '0.01', 2) < 0) {
// This should never happen if membership_value > 0
return self::error(
'خطأ في حساب الرسوم — الزوجة رقم ' . $spouseOrder .
'خطأ في حساب الرسوم — الزوجة رقم ' . $spouseOrder .
' يجب أن تكون برسوم. قيمة العضوية: ' . money($membershipValue)
);
}
......@@ -145,7 +127,7 @@ final class SpouseFeeCalculator
'spouse_order' => $spouseOrder,
'membership_value' => $membershipValue,
'is_initial' => $isInitialCreation,
'is_late_addition' => $isLateAddition,
'is_late_addition' => !$isInitialCreation,
'is_acquired' => $isAcquiredMember,
'is_foreign' => $isForeign,
'percentage' => $percentage,
......@@ -161,15 +143,11 @@ final class SpouseFeeCalculator
'breakdown' => self::buildBreakdown(
$spouseOrder, $membershipValue, $percentage, $percentageFee,
$annualPerYear, $yearCount, $yearlyTotal,
$formFee, $totalFee, $ruleApplied, $isFirstSpouseDuringCreation
$formFee, $totalFee, $ruleApplied, $isFirstFreeSlot && !$isForeign
),
];
}
/**
* Years from marriage date or membership acquisition (whichever later).
* Partial year = full year.
*/
private static function calculateYears(?string $marriageDate, string $memberCreatedDate): int
{
if (!$marriageDate) {
......@@ -178,12 +156,11 @@ final class SpouseFeeCalculator
$marriageTs = strtotime($marriageDate);
$memberTs = strtotime($memberCreatedDate);
if (!$marriageTs || !$memberTs) {
return 1;
}
// Use whichever is LATER
$startTs = max($marriageTs, $memberTs);
$start = new \DateTime(date('Y-m-d', $startTs));
$now = new \DateTime();
......@@ -195,7 +172,6 @@ final class SpouseFeeCalculator
$diff = $now->diff($start);
$years = $diff->y;
// كسر السنة سنة كاملة
if ($diff->m > 0 || $diff->d > 0) {
$years++;
}
......@@ -203,9 +179,6 @@ final class SpouseFeeCalculator
return max(1, $years);
}
/**
* Check if member got membership through transfer/separation/divorce/death/waiver.
*/
private static function isAcquiredMember(int $memberId): bool
{
$db = App::getInstance()->db();
......@@ -233,9 +206,6 @@ final class SpouseFeeCalculator
return false;
}
/**
* Build detailed Arabic breakdown.
*/
private static function buildBreakdown(
int $order, string $membershipValue, string $pct, string $pctFee,
string $annual, int $years, string $yearlyTotal,
......@@ -251,12 +221,10 @@ final class SpouseFeeCalculator
if (bccomp($pctFee, '0', 2) > 0) {
$lines[] = "📊 نسبة {$pct}% × " . money($membershipValue) . ' = ' . money($pctFee);
}
if (bccomp($annual, '0', 2) > 0 && $years > 0) {
$lines[] = "📅 رسوم سنوية: {$annual} ج.م × {$years} سنة = " . money($yearlyTotal);
$lines[] = ' (من تاريخ الزواج أو اكتساب العضوية — أيهما لاحق — كسر السنة سنة كاملة)';
}
if (bccomp($formFee, '0', 2) > 0) {
$lines[] = '📝 رسوم استمارة إضافة: ' . money($formFee);
}
......@@ -268,9 +236,6 @@ final class SpouseFeeCalculator
return $lines;
}
/**
* Return error result.
*/
private static function error(string $message): array
{
return [
......@@ -289,4 +254,4 @@ final class SpouseFeeCalculator
'breakdown' => ['❌ ' . $message],
];
}
}
\ No newline at end of file
}
......@@ -5,6 +5,7 @@ namespace App\Modules\Temporary\Services;
use App\Core\App;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Members\Services\FormFeeService;
final class TemporaryFeeCalculator
{
......@@ -22,19 +23,20 @@ final class TemporaryFeeCalculator
}
$hasChampionship = (bool) ($tempData['has_championship'] ?? false);
$category = $tempData['category'] ?? '';
// Championship exemption
$exemptData = RuleEngine::get('TEMP_CHAMPIONSHIP_EXEMPT');
$isExempt = $hasChampionship && ($exemptData['exempt'] ?? true);
if ($isExempt) {
return [
'fee' => '0.00',
'percentage' => '0.00',
'rule_applied' => 'TEMP_CHAMPIONSHIP_EXEMPT',
'exempt' => true,
'error' => null,
'fee' => '0.00',
'percentage' => '0.00',
'membership_value' => $membershipValue,
'form_fee' => '0.00',
'total_fee' => '0.00',
'rule_applied' => 'TEMP_CHAMPIONSHIP_EXEMPT',
'exempt' => true,
'error' => null,
];
}
......@@ -42,12 +44,7 @@ final class TemporaryFeeCalculator
$pct = $feeData['percentage'] ?? '10.00';
$fee = bcmul($membershipValue, bcdiv($pct, '100', 4), 2);
// Form fee if post-creation
$formFee = '0.00';
if ($member['status'] !== 'potential') {
$formFeeData = RuleEngine::get('FORM_ADDITION_FEE');
$formFee = $formFeeData['amount'] ?? '570.00';
}
$formFee = FormFeeService::getFormFee($memberId, $member);
return [
'membership_value' => $membershipValue,
......@@ -66,14 +63,20 @@ final class TemporaryFeeCalculator
$errors = [];
$age = (int) ($tempData['age_years'] ?? 0);
$maxAgeRules = [
'sister' => 'SISTER_MAX_AGE',
'stepchild' => 'STEPCHILD_MAX_AGE',
'orphan' => 'ORPHAN_MAX_AGE',
];
switch ($category) {
case 'parent':
// No specific age limit for parents
break;
case 'special_needs':
if ($age < 21) {
$errors[] = 'أبناء ذوي الاحتياجات الخاصة يجب أن يكونوا فوق 21 سنة';
$minAge = (int) (RuleEngine::getValue('SPOUSE_WORKING_AGE_THRESHOLD', 'value') ?? 21);
if ($age < $minAge) {
$errors[] = 'أبناء ذوي الاحتياجات الخاصة يجب أن يكونوا فوق ' . $minAge . ' سنة';
}
if (empty($tempData['disability_documentation'])) {
$errors[] = 'يجب تقديم وثائق الإعاقة';
......@@ -87,8 +90,9 @@ final class TemporaryFeeCalculator
break;
case 'sister':
if ($age >= 25) {
$errors[] = 'شقيقة العضو يجب أن تكون أقل من 25 سنة';
$maxAge = (int) (RuleEngine::getValue('SISTER_MAX_AGE', 'value') ?? 25);
if ($age >= $maxAge) {
$errors[] = 'شقيقة العضو يجب أن تكون أقل من ' . $maxAge . ' سنة';
}
if (($tempData['gender'] ?? '') !== 'female') {
$errors[] = 'هذه الفئة للإناث فقط';
......@@ -96,14 +100,16 @@ final class TemporaryFeeCalculator
break;
case 'stepchild':
if ($age >= 25) {
$errors[] = 'أبناء الزوج/الزوجة يجب أن تكون أعمارهم أقل من 25 سنة';
$maxAge = (int) (RuleEngine::getValue('STEPCHILD_MAX_AGE', 'value') ?? 25);
if ($age >= $maxAge) {
$errors[] = 'أبناء الزوج/الزوجة يجب أن تكون أعمارهم أقل من ' . $maxAge . ' سنة';
}
break;
case 'orphan':
if ($age >= 25) {
$errors[] = 'الطفل اليتيم يجب أن يكون أقل من 25 سنة';
$maxAge = (int) (RuleEngine::getValue('ORPHAN_MAX_AGE', 'value') ?? 25);
if ($age >= $maxAge) {
$errors[] = 'الطفل اليتيم يجب أن يكون أقل من ' . $maxAge . ' سنة';
}
break;
......@@ -114,7 +120,6 @@ final class TemporaryFeeCalculator
break;
case 'nanny':
// Nanny — companion, no specific age rules
break;
default:
......@@ -135,4 +140,5 @@ final class TemporaryFeeCalculator
$noIndependent = ['orphan', 'disabled_sibling', 'nanny'];
return !in_array($category, $noIndependent, true);
}
}
\ No newline at end of file
}
<?php
declare(strict_types=1);
/**
* Phase 39: Add form-session rules + fix CHILD_INCLUDED_MAX_COUNT.
*
* Business requirement:
* - Initial membership form (505 EGP) includes 1 spouse + 2 children under 18 free.
* - After activation, any modification needs a 570 EGP "addition form".
* - Multiple additions within the SAME form session share one form fee.
* - Form validity days controls how long an addition form stays open.
*/
return function (\App\Core\Database $db) {
$now = date('Y-m-d H:i:s');
$today = date('Y-m-d');
// ── New rules ────────────────────────────────────────────────────
$newRules = [
[
'rule_code' => 'INITIAL_FREE_SPOUSES_COUNT',
'category' => 'spouse_fee',
'name_ar' => 'عدد الزوجات المشمولات مجاناً في الاستمارة الأولى',
'name_en' => 'Free Spouses on Initial Form',
'data_type' => 'integer',
'current_value_json' => '{"value":1}',
'parameters_json' => '{"value":"integer"}',
],
[
'rule_code' => 'INITIAL_FREE_CHILDREN_COUNT',
'category' => 'children_fee',
'name_ar' => 'عدد الأبناء المشمولين مجاناً في الاستمارة الأولى (تحت السن)',
'name_en' => 'Free Children on Initial Form',
'data_type' => 'integer',
'current_value_json' => '{"value":2}',
'parameters_json' => '{"value":"integer"}',
],
[
'rule_code' => 'ADDITION_FORM_VALIDITY_DAYS',
'category' => 'financial',
'name_ar' => 'مدة صلاحية استمارة الإضافة/التعديل (أيام)',
'name_en' => 'Addition Form Validity Days',
'data_type' => 'integer',
'current_value_json' => '{"value":30}',
'parameters_json' => '{"value":"integer"}',
],
];
foreach ($newRules as $rule) {
$exists = $db->selectOne(
"SELECT id FROM business_rules WHERE rule_code = ? AND branch_id IS NULL",
[$rule['rule_code']]
);
if (!$exists) {
$db->insert('business_rules', array_merge($rule, [
'branch_id' => null,
'effective_from' => $today,
'effective_to' => null,
'version' => 1,
'is_active' => 1,
'created_at' => $now,
'updated_at' => $now,
]));
}
}
// ── Update CHILD_INCLUDED_MAX_COUNT from 3 → 2 ──────────────────
// The club rule is: first 2 children under 18 are free on the initial form.
// The existing seed had 3. We correct it here.
$childRule = $db->selectOne(
"SELECT id, current_value_json, version FROM business_rules WHERE rule_code = 'CHILD_INCLUDED_MAX_COUNT' AND branch_id IS NULL AND is_active = 1"
);
if ($childRule) {
$currentValue = json_decode($childRule['current_value_json'], true);
if (($currentValue['value'] ?? 3) === 3) {
$newVersion = (int) $childRule['version'] + 1;
$db->insert('rule_versions', [
'rule_id' => (int) $childRule['id'],
'version_number' => $newVersion,
'old_value_json' => $childRule['current_value_json'],
'new_value_json' => '{"value":2}',
'changed_by' => null,
'changed_at' => $now,
'change_reason' => 'تصحيح: القاعدة الصحيحة هي طفلين مشمولين مجاناً وليس 3',
]);
$db->update('business_rules', [
'current_value_json' => '{"value":2}',
'version' => $newVersion,
'updated_at' => $now,
], '`id` = ?', [(int) $childRule['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