Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
Clubphp
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Clubphp
Commits
5b4e277d
Commit
5b4e277d
authored
Apr 27, 2026
by
Mahmoud Aglan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
dryjkftykft
parent
5ff91171
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
57 additions
and
30 deletions
+57
-30
ChildFeeCalculator.php
app/Modules/Children/Services/ChildFeeCalculator.php
+4
-1
FormFeeService.php
app/Modules/Members/Services/FormFeeService.php
+40
-23
SpouseFeeCalculator.php
app/Modules/Spouses/Services/SpouseFeeCalculator.php
+13
-6
No files found.
app/Modules/Children/Services/ChildFeeCalculator.php
View file @
5b4e277d
...
@@ -72,8 +72,11 @@ final class ChildFeeCalculator
...
@@ -72,8 +72,11 @@ final class ChildFeeCalculator
$breakdown
[]
=
'👶 الترتيب: #'
.
$childOrder
.
' — السن: '
.
$childAge
.
' سنة'
;
$breakdown
[]
=
'👶 الترتيب: #'
.
$childOrder
.
' — السن: '
.
$childAge
.
' سنة'
;
$breakdown
[]
=
'📌 التصنيف: '
.
(
$classLabels
[
$classification
]
??
$classification
);
$breakdown
[]
=
'📌 التصنيف: '
.
(
$classLabels
[
$classification
]
??
$classification
);
if
(
$classification
===
'included'
)
{
if
(
$classification
===
'included'
&&
bccomp
(
$formFee
,
'0'
,
2
)
<=
0
)
{
$breakdown
[]
=
'✅ مشمول في قيمة العضوية — بدون رسوم إضافية'
;
$breakdown
[]
=
'✅ مشمول في قيمة العضوية — بدون رسوم إضافية'
;
}
elseif
(
$classification
===
'included'
&&
bccomp
(
$formFee
,
'0'
,
2
)
>
0
)
{
$breakdown
[]
=
'✅ مشمول (بدون رسوم عضوية)'
;
$breakdown
[]
=
'📝 رسوم استمارة إضافة: '
.
money
(
$formFee
);
}
else
{
}
else
{
if
(
bccomp
(
$childFee
,
'0'
,
2
)
>
0
)
{
if
(
bccomp
(
$childFee
,
'0'
,
2
)
>
0
)
{
$breakdown
[]
=
'📊 نسبة '
.
$percentage
.
'% × '
.
money
(
$membershipValue
)
.
' = '
.
money
(
$childFee
);
$breakdown
[]
=
'📊 نسبة '
.
$percentage
.
'% × '
.
money
(
$membershipValue
)
.
' = '
.
money
(
$childFee
);
...
...
app/Modules/Members/Services/FormFeeService.php
View file @
5b4e277d
...
@@ -10,26 +10,31 @@ use App\Modules\ServiceCatalog\Models\ServicePrice;
...
@@ -10,26 +10,31 @@ use App\Modules\ServiceCatalog\Models\ServicePrice;
/**
/**
* Determines whether a dependant addition needs a form fee (570 EGP).
* Determines whether a dependant addition needs a form fee (570 EGP).
*
*
* Business rule:
* Business rule — the boundary is the MEMBERSHIP NUMBER:
* - During initial membership creation (member status = potential / under_review),
* - Before the member gets a membership number (hasn't paid membership yet),
* all additions are on the same initial form — no additional form fee.
* all additions are on the initial 505 EGP form — no extra form fee.
* - After activation (member has membership number), any addition/modification/removal
* This covers all pre-activation statuses: potential, under_review,
* requires a 570 EGP form fee PER PERSON. No session sharing.
* interview_scheduled, accepted, payment_pending.
* - After activation (member has a membership number), every addition costs
* an additional 570 EGP form fee PER PERSON on top of the dependant's own fees.
* Free dependants (1st spouse, first 2 children under 18) remain free — only
* the 570 form fee applies, and free slots are still free (no 570 either).
*/
*/
final
class
FormFeeService
final
class
FormFeeService
{
{
/**
/**
* Check if the member is still on the initial membership form.
* Check if the member is still on the initial membership form.
* True = no membership number yet = pre-activation = all on same 505 form.
*/
*/
public
static
function
isOnInitialForm
(
array
$member
)
:
bool
public
static
function
isOnInitialForm
(
array
$member
)
:
bool
{
{
return
in_array
(
$member
[
'status'
]
??
''
,
[
'potential'
,
'under_review'
],
true
);
return
empty
(
$member
[
'membership_number'
]
);
}
}
/**
/**
* Get the form fee
that should be charged for an addition
.
* Get the form fee
for adding a dependant
.
* Returns '0.00' if
on initial form
.
* Returns '0.00' if
still on initial form (no membership number)
.
* Returns 570 EGP
(or configured amount)
per person after activation.
* Returns 570 EGP per person after activation.
*/
*/
public
static
function
getFormFee
(
int
$memberId
,
array
$member
)
:
string
public
static
function
getFormFee
(
int
$memberId
,
array
$member
)
:
string
{
{
...
@@ -42,31 +47,43 @@ final class FormFeeService
...
@@ -42,31 +47,43 @@ final class FormFeeService
}
}
/**
/**
* Check if this is a "free" spouse slot on the initial form.
* Check if this spouse is in a "free" slot (zero dependant fee).
* Rule: first N spouses are free (default N=1) during initial creation.
* Free slots apply ALWAYS — on initial form AND after activation.
* The only difference: after activation the 570 form fee is added.
* On initial form: free slot = no fee at all.
* After activation: free slot = 0 dependant fee + 570 form fee.
*/
*/
public
static
function
isSpouseFree
OnInitialForm
(
int
$memberId
,
int
$spouseOrder
,
array
$memb
er
)
:
bool
public
static
function
isSpouseFree
Slot
(
int
$memberId
,
int
$spouseOrd
er
)
:
bool
{
{
if
(
!
self
::
isOnInitialForm
(
$member
))
{
return
false
;
}
$maxFree
=
(
int
)
(
RuleEngine
::
getValue
(
'INITIAL_FREE_SPOUSES_COUNT'
,
'value'
)
??
1
);
$maxFree
=
(
int
)
(
RuleEngine
::
getValue
(
'INITIAL_FREE_SPOUSES_COUNT'
,
'value'
)
??
1
);
return
$spouseOrder
<=
$maxFree
;
return
$spouseOrder
<=
$maxFree
;
}
}
/**
/**
* Check if this child is in a "free" slot on the initial form.
* @deprecated Use isSpouseFreeSlot() instead
* 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
public
static
function
isSpouseFreeOnInitialForm
(
int
$memberId
,
int
$spouseOrder
,
array
$member
)
:
bool
{
return
self
::
isSpouseFreeSlot
(
$memberId
,
$spouseOrder
);
}
/**
* Check if this child is in a "free" slot (zero dependant fee).
* Free slots apply ALWAYS. After activation: 0 dependant fee + 570 form fee.
* On initial form: no fee at all.
*/
public
static
function
isChildFreeSlot
(
int
$memberId
,
int
$childOrder
,
int
$childAge
)
:
bool
{
{
if
(
!
self
::
isOnInitialForm
(
$member
))
{
return
false
;
}
$maxFreeCount
=
(
int
)
(
RuleEngine
::
getValue
(
'INITIAL_FREE_CHILDREN_COUNT'
,
'value'
)
??
2
);
$maxFreeCount
=
(
int
)
(
RuleEngine
::
getValue
(
'INITIAL_FREE_CHILDREN_COUNT'
,
'value'
)
??
2
);
$maxFreeAge
=
(
int
)
(
RuleEngine
::
getValue
(
'CHILD_INCLUDED_MAX_AGE'
,
'value'
)
??
18
);
$maxFreeAge
=
(
int
)
(
RuleEngine
::
getValue
(
'CHILD_INCLUDED_MAX_AGE'
,
'value'
)
??
18
);
return
$childOrder
<=
$maxFreeCount
&&
$childAge
<
$maxFreeAge
;
return
$childOrder
<=
$maxFreeCount
&&
$childAge
<
$maxFreeAge
;
}
}
/**
* @deprecated Use isChildFreeSlot() instead
*/
public
static
function
isChildFreeOnInitialForm
(
int
$memberId
,
int
$childOrder
,
int
$childAge
,
array
$member
)
:
bool
{
return
self
::
isChildFreeSlot
(
$memberId
,
$childOrder
,
$childAge
);
}
}
}
app/Modules/Spouses/Services/SpouseFeeCalculator.php
View file @
5b4e277d
...
@@ -42,7 +42,7 @@ final class SpouseFeeCalculator
...
@@ -42,7 +42,7 @@ final class SpouseFeeCalculator
$spouseOrder
=
$existingCount
+
1
;
$spouseOrder
=
$existingCount
+
1
;
$isInitialCreation
=
FormFeeService
::
isOnInitialForm
(
$member
);
$isInitialCreation
=
FormFeeService
::
isOnInitialForm
(
$member
);
$isF
irstFreeSlot
=
FormFeeService
::
isSpouseFreeOnInitialForm
(
$memberId
,
$spouseOrder
,
$memb
er
);
$isF
reeSlot
=
FormFeeService
::
isSpouseFreeSlot
(
$memberId
,
$spouseOrd
er
);
$formFee
=
FormFeeService
::
getFormFee
(
$memberId
,
$member
);
$formFee
=
FormFeeService
::
getFormFee
(
$memberId
,
$member
);
...
@@ -63,9 +63,13 @@ final class SpouseFeeCalculator
...
@@ -63,9 +63,13 @@ final class SpouseFeeCalculator
switch
(
true
)
{
switch
(
true
)
{
case
(
$spouseOrder
===
1
)
:
case
(
$spouseOrder
===
1
)
:
if
(
$isF
irstF
reeSlot
&&
!
$isForeign
)
{
if
(
$isFreeSlot
&&
!
$isForeign
)
{
$percentage
=
'0.00'
;
$percentage
=
'0.00'
;
$ruleApplied
=
'الزوجة الأولى — مشمولة في قيمة العضوية الأساسية (بدون رسوم إضافية)'
;
if
(
$isInitialCreation
)
{
$ruleApplied
=
'الزوجة الأولى — مشمولة في الاستمارة الأولى (بدون رسوم)'
;
}
else
{
$ruleApplied
=
'الزوجة الأولى — مشمولة (رسوم الاستمارة فقط '
.
money
(
$formFee
)
.
')'
;
}
}
elseif
(
$isForeign
)
{
}
elseif
(
$isForeign
)
{
$data
=
RuleEngine
::
get
(
'SPOUSE_FOREIGN_FEE'
);
$data
=
RuleEngine
::
get
(
'SPOUSE_FOREIGN_FEE'
);
$percentage
=
$data
[
'percentage'
]
??
'15.00'
;
$percentage
=
$data
[
'percentage'
]
??
'15.00'
;
...
@@ -143,7 +147,7 @@ final class SpouseFeeCalculator
...
@@ -143,7 +147,7 @@ final class SpouseFeeCalculator
'breakdown'
=>
self
::
buildBreakdown
(
'breakdown'
=>
self
::
buildBreakdown
(
$spouseOrder
,
$membershipValue
,
$percentage
,
$percentageFee
,
$spouseOrder
,
$membershipValue
,
$percentage
,
$percentageFee
,
$annualPerYear
,
$yearCount
,
$yearlyTotal
,
$annualPerYear
,
$yearCount
,
$yearlyTotal
,
$formFee
,
$totalFee
,
$ruleApplied
,
$isF
irstF
reeSlot
&&
!
$isForeign
$formFee
,
$totalFee
,
$ruleApplied
,
$isFreeSlot
&&
!
$isForeign
),
),
];
];
}
}
...
@@ -215,8 +219,11 @@ final class SpouseFeeCalculator
...
@@ -215,8 +219,11 @@ final class SpouseFeeCalculator
$lines
[]
=
'📋 القاعدة المطبقة: '
.
$rule
;
$lines
[]
=
'📋 القاعدة المطبقة: '
.
$rule
;
$lines
[]
=
'💰 قيمة العضوية: '
.
money
(
$membershipValue
);
$lines
[]
=
'💰 قيمة العضوية: '
.
money
(
$membershipValue
);
if
(
$isFirstFree
)
{
if
(
$isFirstFree
&&
bccomp
(
$formFee
,
'0'
,
2
)
<=
0
)
{
$lines
[]
=
'✅ الزوجة الأولى مشمولة في قيمة العضوية — بدون رسوم إضافية'
;
$lines
[]
=
'✅ الزوجة الأولى مشمولة في الاستمارة — بدون رسوم إضافية'
;
}
elseif
(
$isFirstFree
&&
bccomp
(
$formFee
,
'0'
,
2
)
>
0
)
{
$lines
[]
=
'✅ الزوجة الأولى مشمولة (بدون رسوم عضوية)'
;
$lines
[]
=
'📝 رسوم استمارة إضافة: '
.
money
(
$formFee
);
}
else
{
}
else
{
if
(
bccomp
(
$pctFee
,
'0'
,
2
)
>
0
)
{
if
(
bccomp
(
$pctFee
,
'0'
,
2
)
>
0
)
{
$lines
[]
=
"📊 نسبة
{
$pct
}
% × "
.
money
(
$membershipValue
)
.
' = '
.
money
(
$pctFee
);
$lines
[]
=
"📊 نسبة
{
$pct
}
% × "
.
money
(
$membershipValue
)
.
' = '
.
money
(
$pctFee
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment