Commit 4733feb0 authored by Fares's avatar Fares

docs: update Members architecture map for non-working type flows

Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 5f2720c3
# Members Module — Architecture Map
> **Last updated:** 2026-06-11
> **Last updated:** 2026-07-22
> **Status:** Living document — incrementally updated as new information is discovered
---
......@@ -245,12 +245,12 @@ As of 2026-06-11, `membership_type` is a **primary selection at creation time**,
| seasonal | عضوية موسمية | 0 | NO | NO | Duration-based via SeasonalPricingService |
| sports | عضوية رياضية | 0 | NO | NO | 50% conversion fee of working membership value |
| honorary | عضوية شرفية | 0 | NO | NO | Form fee only, membership value = 0, no payment needed |
| foreign | عضوية أجنبية | 21 | NO | NO | $10,000 USD from RuleEngine |
| foreign | عضوية أجنبية | 21 | YES | NO | $10,000 USD (Sheraton) / $15,000 USD (New Capital) from RuleEngine |
**Key behaviors:**
- `MembershipRulesService::getCreatableMembershipTypes()` returns all 5 types
- `MembershipRulesService::allowsDependents(type)`only `working` returns true
- Spouse/Children/Temporary controllers guard against non-working types
- `MembershipRulesService::allowsDependents(type)``working` and `foreign` return true
- Spouse/Children/Temporary controllers guard against types where `allowsDependents()` is false
- `BillingService::getMemberBill()` dispatches via `match($membershipType)` to type-specific billing methods
- `MembershipPaymentGuard::reconcile()` bypasses honorary (no payment required)
- Special module detail pages (Foreign/Honorary/Sports/Seasonal) validate member type before allowing access
......@@ -267,37 +267,26 @@ As of 2026-06-11, `membership_type` is a **primary selection at creation time**,
### 5.1 New Member Registration Flow
**Working member flow (full lifecycle):**
```
1. POST /members (store)
- Validate: name, phone, branch, NID/passport, age≥21, photo required
- Create member with status='potential'
- Assign form_number (sequential)
- Upload photo
- Start workflow instance (if 'new_membership' definition exists)
- Dispatch: member.created
2. POST /members/{id}/pay-form-fee
- Create payment_request (type='form_fee', amount=505 EGP)
- Sent to Cashier/Treasury for processing
3. GET /members/{id}/fill-form (requires form_fee paid)
- Detailed application form (employment, address, qualifications, etc.)
- Sets membership_value based on qualification + branch pricing
- Status changes: potential → under_review
4. POST /members/{id}/pay-membership
- Create payment_request (type='membership_fee' or 'down_payment')
- Includes all dependent fees in the bill
- Cancels individual pending addition_fee requests (subsumed)
5. [Cashier processes payment → Payments module confirms]
- MembershipPaymentGuard::activateMember() is called
- Assigns membership_number
- Sets status='active', activated_at, activated_by_payment_id
- Activates included dependents
- Dispatches: member.activated
1. POST /members (store) → status='potential', form_number assigned
2. POST /members/{id}/pay-form-fee → payment_request(form_fee, 505 EGP) → Cashier
3. GET /members/{id}/fill-form → sets qualification/membership_value → status='under_review'
4. Interview/Acceptance process → status='accepted' or 'payment_pending'
5. POST /members/{id}/pay-membership → payment_request(membership_fee/down_payment)
6. Cashier completes → MembershipPaymentGuard::activateMember() → status='active'
```
**Non-working type flows (skip acceptance, stay 'potential' until payment):**
```
Foreign: potential → form_fee → (optional: /foreign/create for passport+exchange rate) → pay-membership(foreign_membership_fee) → active
Sports: potential → form_fee → (optional: /sports/create for discipline info) → pay-membership(sports_membership_fee) → active
Seasonal: potential → form_fee → /seasonal/create (auto-sends payment_request) → Cashier → active
Honorary: potential → form_fee → /honorary/create → immediately active (no payment)
```
**Key:** Non-working types have `$formFilled = true` unconditionally (MemberController::show, line 221). The show page payment section allows `potential` status for non-working types with form_fee_paid.
### 5.2 Billing Calculation (BillingService::getMemberBill)
Dispatches by `membership_type` via PHP `match()`:
......
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