- 04 Sep, 2026 1 commit
-
-
Mahmoud Aglan authored
The microsite is built for scrolling, so a naive print lost most of it: reveals start invisible, the phone shows one prototype screen at a time, the portal shows one admin screen, and <details> print collapsed. - @media print in styles.css: force reveals visible, drop the fixed nav and prototype tools, start each section on a fresh page, and mark cards, timeline items, tables and price blocks break-inside:avoid so none is split across a page boundary - generate-pdf.mjs (puppeteer): expands both prototypes before printing — the single phone frame becomes a labelled 3x3 grid of nine real app screens, and all seven portal screens are stacked. 1240x1754 pages (A4 proportion at 150dpi), backgrounds on. - Adds a "تحميل العرض PDF" button to the hero; the print stylesheet hides .btn-row so it does not appear inside the PDF itself Output is 14 pages with a real text layer: Arabic extracts correctly and figures stay searchable. Ghostscript compression reaches 2.3MB but its font re-embedding drops Arabic strings from the text layer, so the uncompressed 8.5MB file is kept instead. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
- 03 Sep, 2026 5 commits
-
-
Mahmoud Aglan authored
Commercial terms: - Price 900,000 -> 500,000 EGP, breakdown rebased to sum exactly (230k app + 160k portal/CMS + 60k gate/invites + 50k launch) - Payments simplified from three milestones to two: 360,000 on signing, 140,000 on delivery - Timeline 4-6 weeks -> 2-4 weeks, timeline recompressed from five milestones to four - Early-signing discount recalculated: 5% = 25,000 (was 45,000) - "غير شاملة ضريبة القيمة المضافة" now stated in the price hero, the totals row, under the payment schedule, in the hero stat and footer, and bolded in the FAQ New scope — club news / blog: - Fourth axis added; news moved out of the deferred list into phase one - Live prototype gains a news feed, article page and a fifth tab, with home showing the two latest items - Portal gains a news management screen: article list with reach stats, editor with category, image drop and publish-notification toggle - Article artwork is a branded crest placeholder, not stock photography — the club supplies real images at launch and inventing them would misrepresent what has been approved Reduced technical detail per request: - Dropped the per-template column-name lists (six of them) and the three import-engine cards, replaced with one plain note - Removed API/OTP/RTL/iOS-14/Android-8 jargon throughout; rewrote the security and extensibility cards in business terms - Simplified the in-scope list wording Also makes .tbl scroll rather than clip: a table too wide for its column silently lost its last cells instead of becoming reachable. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
Mahmoud Aglan authored
The prototype in the proposal was eight inline <div>s toggled with display:none — screenshots in a phone bezel. It now embeds a real single-page app from app/, so the screens shown in the proposal are the screens that ship, and the board can actually use it. app/ — hash routed, so any screen is linkable (#/dues): splash, login, otp, home, dues, pay, paying, success, receipts, qr, invites, activities, activity/:id, schedule, notifications, profile State is live, not scripted. Selecting dues recomputes the total before paying; paying clears those dues, creates a receipt and posts a notification; issuing an invite decrements the balance; subscribing to an activity adds the subscription, consumes a place and generates the first invoice into المستحقات. The QR regenerates every 60s against a countdown ring. Dark/light theme persists. Verified end to end by driving the app in headless Chrome, not just by rendering it. Chose an SPA over the multi-page pattern used by the older Proposal/ prototype: no white flash between screens, real forward/back transitions, and shared state across screens, which is the whole point of showing a collection flow. Proposal integration: - Phone hosts <iframe src="app/">; the side list drives it over postMessage and the prototype reports its route back, so the list and the annotation stay in sync when someone navigates inside the phone - Theme toggle, reset, and open-fullscreen controls - Annotation panel rewritten per screen Removed 409 lines of static screen markup and the 93 lines of CSS that served it (.sbar/.app-hd/.mcard/.tabbar/.sport-item/.otp-row/.qr-*), verified dead by checking real class= usage, not substring matches. Adds .dockerignore: the image is built with `COPY . /usr/share/nginx/html`, so any stray working file in this folder would be served publicly. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
Mahmoud Aglan authored
Emoji render as platform-specific colour cartoons (Apple/Windows/Android each differ) which reads informal in a document going to a club board, and they cannot inherit brand colour. Replaced every one with a 33-symbol inline SVG sprite: 24x24, stroke-based, currentColor, sized in em so each existing icon slot keeps its own scale. Removed: swimmer, bell, receipt, credit card, mobile, bank, football, martial-arts, tennis, cartwheel, page, lock, floppy, plug, envelope, gear, up/down arrows, and the EG regional-indicator flag pair. Also converted the geometric glyphs sitting in icon slots (fisheye, diamonds, house, quadrant-circle, square-fill, clock) plus the list check/x/arrow marks, so the icon layer is uniformly SVG rather than a mix of text glyphs and emoji. A source scan for emoji ranges now returns clean. Sprite is hidden with position/width/height rather than display:none, which can break <use> resolution in some engines. Fixes an unrelated pre-existing contrast bug found while verifying: .card h4 is declared after .dark h4 at equal specificity, so the three cards in the dark flow section rendered navy-on-navy. Added .dark .card h4. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
Mahmoud Aglan authored
Copy — the previous register read as marketing/AI boilerplate to a board audience. Removed the tells and rewrote in institutional MSA: - Drop staccato fragment headlines and their trailing periods ("ثلاثة محاور. لا أكثر." -> "نطاق المرحلة الأولى: ثلاثة محاور") - Drop rhetorical punchlines ("الاحتكاك يقتل الاشتراك."، "ليست صورًا تخيلية."، "من ينسى، لا يدفع.") for descriptive prose - Drop the «مصنع البيانات» metaphor and the pitch-deck eyebrow "لماذا الآن" - Rewrite all 8 prototype screen annotations from slogans to labels ("البوابة تعرف من يدخل" -> "الدخول بكود QR") - Reduce rhetorical em-dashes; keep structural ones only Schedule — project is 4-6 weeks, not 12. Timeline recompressed from six milestones over 12 weeks to five over 6, with the 4-week case stated as conditional on data and accounts landing in week 1. Updated hero stat, scope lede, price card, plan heading and footer badge to match. Design — elegant crest watermark: - Oversized club crest bleeding off the inline-start edge of the hero, gold-tinted, offset so it does not double with the hero logo - Alternating-side crest ghosts on problem/scope/flow/price sections - Crest in the price card and footer, plus a gold hairline on the footer - Uses background-image + filter, not mask-image: masks give a cleaner silhouette but do not paint in headless Chrome, so this variant is the one that can actually be verified before shipping - Logical properties throughout (inset-inline, margin-inline) so the watermark mirrors correctly in RTL - Added a prefers-reduced-motion guard for the scroll reveal Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
Mahmoud Aglan authored
Proposal microsite for Nady El-Seid mobile app (sayd-mobile). Arabic copy: - Fix agreement/tamyiz errors: اكتملت العدد -> اكتمل العدد, متأخر يومان -> يومين, "92 يوم" -> "92 يومًا", منها 214 متأخر -> متأخرًا, يومان تدريب -> يوما تدريب (dual mudaf drops nun) - Fix ambiguous/wrong forms: فيتحدث رصيده -> فيُحدَّث رصيده فورًا, الحمام الأولمبي -> حمام السباحة الأولمبي - Remove translationese: comma-lists rewritten with و, passives given back their agents, Egyptian تشتغلون -> تبدأون التشغيل - Unify register to plural address (اضغط -> اضغطوا, شاهد -> شاهدوا) - Apply reviewed headline/lede/ROI rewrites with corrected orthography Commercial terms: - Price 700,000 -> 900,000 EGP; breakdown rebased to sum exactly (400k app + 290k portal + 110k gate/invites + 100k integration) - Remove all post-launch support: annual maintenance contract, 6 free months, 1-year warranty, 99.5% SLA, first-year store fees. Delivery and release only, stated explicitly in a "غير مشمول" block and FAQ - Payments 40/30/20/10 -> 40/25/35: signing, data-entry plan approved + club opens required accounts and services, completed delivery - Timeline week 1-2 renamed to cover data-entry planning and names the account-opening as a parallel club obligation Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
- 01 Sep, 2026 3 commits
-
-
Mahmoud Aglan authored
-
Mahmoud Aglan authored
Pre-existing uncommitted working-tree change, not part of the member search work. Committed separately so the 478-line reduction stays visible in history. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
Mahmoud Aglan authored
Overhaul /members/search so one bar finds anyone in the club — the member, a spouse, a child or a temporary member — and add an advanced filter panel. MemberSearchService becomes the single source of truth for people search: - UNIONs members + spouses + children + temporary_members into one normalised row per matched PERSON (person_type, relation, parent membership, rank). - Token AND matching on names, so word order no longer matters: "محمود احمد" finds "أحمد سيد محمود". - Arabic orthographic folding (أ إ آ ٱ→ا, ى→ي, ة→ه, ؤ→و, ئ→ي) applied to both the query and the column, so "احمد" matches "أحمد". - Arabic-Indic and Persian digits folded to ASCII before identifier matching. - Relevance ranking: exact membership number / national id, then name prefix, then substring. LIKE wildcards in user input are escaped. Scopes (member/spouse/child/temporary) and fields (name, membership number, national id, phone, form number, passport) are selectable; branch, membership status and membership type filter on the parent membership. A scope whose table lacks the requested field is skipped rather than matching nothing. The legacy search() keeps its exact signature and output shape, so the three existing API consumers are untouched. Also: - Split Member::getStatusOptions() (statuses an employee may ASSIGN) from getAllStatusLabels() (every status, for display/filtering). deceased, transferred and waived exist in live data but were missing from the list, so they could not be filtered on; they are deliberately kept out of the assignable set because the Death, Transfer and Waiver workflows own those transitions. - Dependent deep links honour spouse.view / child.view / temp.view and fall back to the membership file when denied. - Map children.relationship (son/daughter) and temporary_members.category (nanny/parent/unmarried_daughter) to Arabic for display. - The search form submitted to /members, dropping most of what was typed; it now posts back to /members/search. - Sidebar declared member.search while the route requires member.view; aligned. Architecture Map and Dependency Graph updated per project protocol, including the placeholder-ordering constraint in buildScopeQuery() and the three inline member-search SQL blocks that remain unconsolidated. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
- 31 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Phase-1 scope only: membership renewals/installments, sports activity invoices, QR gate entry + invitations. Interactive HTML prototypes for 8 mobile screens and 6 portal screens, 6 downloadable CSV import templates, 12-week plan, 700,000 EGP commercial offer. Deployed to CapRover as app 'sayd-mobile'. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Client clarified their earlier request: the member "special discount" dropdown should show board-approved special_discounts AND active عروض مجلس الإدارة (board_offers) cash discounts side by side, not one instead of the other — they'd stopped seeing anything they'd added under Board Offers. - Add members.special_discount_source ('special_discount'|'board_offer') and drop the hard FK on special_discount_id (a single column can no longer FK exactly one table). Integrity is now validated in MemberController::parseDiscountSelection(). - BoardOffer::allActiveWithCashDiscount() surfaces board offers that define a cash discount as selectable options. - SpecialDiscountService::resolveAssignedDiscount()/amountForType() give one place that normalizes "the member's assigned discount" across both source tables — used by BillingService's invoice line item, the show page's applied-discount banner, and the dropdown's own validation. - fill-form/edit/show views render two <optgroup>s ("عروض مجلس الإدارة" / "الخصومات الخاصة") with prefixed option values (bo:<id> / sd:<id>) so a single form field can select from either table; edit.php's live discount-amount preview now handles fixed-amount discounts too, not just percentage. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
-
- 30 Aug, 2026 4 commits
-
-
Mahmoud Aglan authored
fix(members,subscriptions): drop due-date column from family tables, collect annual subscription via الخزنة - Remove the "تاريخ الاستحقاق" column from the spouses/children/temporary members tables on the member show page (display-only, no schema change). - Annual subscription payments no longer post directly from the اشتراك سنوي page. SubscriptionController::payYear() now queues a payment_request instead of calling PaymentService::processPayment() directly; the subscription rows are only marked paid once خزنة العضويات (Membership Treasury / Cashier) actually collects it, via a new payment_request.completed listener (SubscriptionSyncService::completeFamilyYearPayment()). - Closed the same bypass on the legacy generic /payments/process/{id} page, which had its own divergent partial-payment, oldest-year-first logic for annual_subscription that skipped the treasury entirely and violated the all-or-nothing-per-family rule; that path now redirects to the member's subscriptions page instead. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
fix(pricing): require board decision for member special discounts, allow fixed-amount down payment on board offers - special_discounts gains board_decision_number/board_decision_date; the member-facing "special discount" dropdown (fill-form, edit, show, apply) now only lists/accepts discounts backed by a board decision instead of the full unaudited special_discounts catalog, per client request that the dropdown should only read board-approved discounts. - board_offers gains inst_down_payment_type (percentage/fixed_amount) so a board-approved offer's installment down payment (المقدم) can be a fixed cash amount, not only a percentage. Wired through BoardOfferService, InstallmentCalculator (new min_down_amount override) and PaymentLifecycleService so the fixed amount is actually enforced at billing time, not just in the admin form. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Users saw sidebar links that returned 403. Root cause was drift between four independently-authored declaration sets that nothing reconciles: the permission catalogue (bootstrap.php), the route gate (Routes.php), the menu gate (MenuRegistry) and the role grants (seeds). Route shadowing (Router::dispatch is first-match-wins over a sorted module glob): - GET /reports was declared by both Members and Reports; Members won and enforced member.reports while the sidebar gated on report.view_membership. Members' report routes moved to /members/reports/*. - GET /sports-dashboard[/export] was declared by three modules, so the dashboard index and its drill-downs were served by different modules. Disciplines -> /disciplines/dashboard, PlaygroundAdmin -> /playgrounds/dashboard[/export]; /sports-dashboard is now wholly owned by SportsDashboard. - Members/Routes.php used unconstrained {id} in 15 routes, so /members/<anything> was swallowed by MemberController@show. Constrained to {id:\d+}, matching every other module. All 25 affected links updated. Gate alignment: - Six menu entries gated on a different permission than the route they link to (/members/search, /sports, /carnets, /rentals/entities, /notifications/templates, /reports). Authorization bypasses: - RetroactiveWizardController hardcoded a role_code = 'super_admin' query, throwing "هذه الأداة متاحة فقط لمدير النظام". Replaced with a registered member.retroactive permission enforced by the route and grantable via the Roles UI. - report_definitions.required_permission was stored and displayed but never checked, so report.view_membership was enough to open ANY report by code, including financial ones. Now enforced on view/export/print; the listing filters to what the viewer can actually run. Role grants (Phase_105_001, idempotent): - Closes the reported gaps for report_viewer, general_manager, receptionist, sports_officer, academy_manager and membership_director; grants the sports report keys to board_member/auditor so enforcing the per-report permission does not silently remove reports; revokes member.view/member.search from facilities_manager, who keeps bookings and reservations. Data correctness: - SaFinanceReportService read base_price from sa_pricing_rules, a facility booking table with neither that column nor activity_type, and derived revenue as headcount x a rate-card price. Now sums actual sa_registrations .registration_fee, matching how subscription and booking revenue are computed. Regression guard: - php cli.php permissions:audit reconciles all four declaration sets, reproduces the router's load order, and exits non-zero on drift. Run it after touching any Routes.php, menu block or role seed. Docs: new docs/architecture-maps/Authorization.md; cross-module authorization section added to DEPENDENCY-GRAPH.md. Note: the live DB was unreachable from the dev environment, so role grants were verified by replaying the seeds and schema came from migrations, not the live DB. PHPUnit is not installed locally; all changed files lint clean. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- ActivitySubscriptions: fix generate/calculateRate querying nonexistent `enrollments` table; use `academy_enrollments` with correct columns - SportsDashboard: fix queries against nonexistent `disciplines` table; use `sport_disciplines` - Sports: unify conversion-fee percentage to a single source (MembershipRulesService::getAthleticMemberConversionRules), preventing the eligibility preview from drifting from what's actually charged - SportsActivity: align absence-threshold fallback defaults between AttendanceRuleService and TrainingAttendanceService via a shared constant - SportsActivity: auto-bill first month on Registration Wizard completion, matching the direct-enrollment path so wizard-registered players aren't left uncharged until the monthly batch runs - ActivitySubscriptions: guard paySubscription() to only transition pending/overdue -> paid, making it idempotent against the (currently unreachable) payment.completed listener path - ActivitySubscriptions: dispatch academy.enrollment_created from the enroll wizard so PlayerAffairs' auto-billing listener actually fires Also adds/updates Architecture Maps for Sports, SportsActivity, SportsDashboard, ActivitySubscriptions and the cross-module Dependency Graph, per this repo's mandatory architecture-map workflow. Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com> Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com>
-
- 29 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Every user previously saw the same dashboard: DashboardDataService::getData() returned one fixed payload with no reference to the current employee. A cashier got membership stats they could not act on; an HR manager got revenue instead of headcount. Each role now gets a curated dashboard. Role presets pick the layout, permissions gate every widget (mirroring MenuRegistry::getVisible), and multi-role users get the deduped union of their presets. Super admin gets a 5-KPI, 16-widget command center across six sections. Wires up WidgetRegistry, which existed fully written but was used by nothing. 144 widgets, all SQL executed and verified against the live schema — 46 were corrected during verification, including a month-to-date figure compared against a full prior month (a fake collapse every month), spouse counts missing their status filter, and receivables that included debt owed by archived deceased members. Only the headline plus first six widgets query on load; the rest hydrate through GET /dashboard/widget/{key}, which re-checks permission server-side and renders via the same partial as the eager path. Employees with no mapped role fall back to the previous shared dashboard, preserved verbatim. Also loads Chart.js, which PlayerAffairs has always called behind a `typeof Chart !== 'undefined'` guard while the library was loaded nowhere — those evaluation charts were silently dead and now render. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
-
- 28 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Assigns human-friendly usernames, unique passwords, and business-appropriate roles to all 62 imported employees based on their HR job titles. Includes credentials reference sheet for permission testing. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add board offer "عروض عضويات شيراتون 2026" with 4 tiers (cash 10%, 24mo 0%, 40mo 15%, 60mo 15%) - Add "فوق المتوسط" qualification at 187,500 EGP - Fix crash in show.php: board_offers uses title_ar not name_ar - Rewrite discounts tutorial with full regulatory discount coverage Co-Authored-By:Claude Opus 4.6 (1M context) <noreply@anthropic.com>
-
- 27 Aug, 2026 1 commit
-
-
Mahmoud Aglan authored
Sports Activity Reports: player reports with filters (discipline/program/group/ player type/medical/payment status/branch) and finance reports (revenue/costs/ profit with daily/weekly/monthly/yearly/3yr/5yr/custom periods). CSV and PDF export for both. Role-based access with 3 new permissions. Membership Discounts: fix BillingService to include regulatory discount as bill line item, add regulatory discount section to edit page, add FYI discount guide to show page covering all 3 discount types (special, regulatory, board offers), handle regulatory discount in update controller with document upload. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 26 Aug, 2026 4 commits
-
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Phase 3: Weekly work schedules - Migration: hr_weekly_schedules table (per-employee per-day shift times + rest days) - Seed: import 59 employees' weekly schedules from club's work schedule sheet - Seed: 13 shift definitions (9-5, 3-11, 10-6, 12-8, etc.) Phase 7B: Job description cards - Migration: hr_job_descriptions table (purpose, authority, duties per job title) - View: printable بطاقة الوصف الوظيفي matching club's official template - Route: GET /hr/job-titles/{id}/description-card Phase 8: Org structure hierarchy - Migration sets parent_id=1 (EXEC) for all other departments Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Phase_05_001: changed department_type from 'edara' to 'idara' (CHECK constraint only allows 'idara'/'qism') - Phase_05_002: create employees table records before hr_employee_profiles to satisfy FK constraint - Generates unique usernames (emp0001, emp0002, ...) - Sets default password 'Club@2026' with force_password_change=1 - Links hr_employee_profiles.employee_id to newly created employees.id Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Phase 1 - Leave System (2025 Law): - Annual leave: 15d (1st year) → 21d (after 1y) → 30d (10y+/age 50+) → 45d (disability) - Maternity: 90 → 120 days (4 months), hajj: now PAID with 5y service min - New leave types: childcare (unpaid, 3 career, 24mo gap), paternity (1d, 3 career), exam - Casual leave: enforce max 2 consecutive days - Childcare gap enforcement, service months validation Phase 2 - Employee Import: - Extract 75 employees from HR registry Excel → JSON seed data - 34 Bank of Alexandria accounts extracted for salary transfers - 14 departments + all job titles auto-created from registry - Migration adds variable_salary + total_allowances columns Phase 4 - Payroll Alignment (July 2026 format): - Solidarity fund: 0.25% of gross (صندوق التكافل) - Stamp duty: 3% of net (دمغة عادية وإضافية) - now percentage-based - Emergency fund + VAT config keys added - calculation_json includes full breakdown Phase 5 - Bank Transfer Export: - BankTransferService generates transfer data from payroll runs - CSV export with BOM for Arabic compatibility - View + route: /hr/payroll/periods/{id}/bank-transfer Phase 6 - Performance Evaluation: - Seed 10-criteria template matching club's official form (100 points) - Dual evaluator support (direct manager + general supervisor) - 5-tier rating labels (ضعيف → ممتاز) Phase 7 - Reports & Forms: - Work receipt printable form (إقرار استلام العمل) - Workforce statement report (بيان القوة الفعلية) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 23 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
Always-visible reference table on the membership form showing: - All 7 articles with their discount percentages and conditions - Which branches each applies to - What proof is needed (auto-verify vs document upload) - Non-stacking rule note Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- 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:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Full-cycle implementation of club bylaw discount rules: - Art 97: Cross-branch member discounts (50% Sheraton
↔ 6th Oct, 25% →Admin Capital) - Art 98: Government employees 50%, Ministry of Youth 62.5% at Admin Capital - Art 99: Ministry of Youth 25% at Sheraton/6th Oct - Art 100: Board of Trustees 50% + 2yr interest-free installment - Art 101: Ministry employees installment-only (no discount) - Art 102: Club employees (5+ yrs) up to 15% - Art 110: Group membership tiered (5-10→3%, 11-20→7%, 21+→10%) Includes: migration, seed data, model, service with eligibility engine, controller (CRUD + eligibility check API + application workflow), views (index, form, applications), routes, permissions, menu entry, and PricingEngine integration. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 20 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Board Offers: - Add board_offer_tiers table for multiple payment plans per offer - Each offer now supports 4 tiers: cash (10% discount), 24mo/0%, 40mo/15%, 60mo/15% - View shows all tiers as selectable cards with pre-calculated breakdowns - Controller accepts offer_tier_id and uses tier-specific terms - Seed populates tiers for all active board offers - Legacy fallback preserved when no tiers are configured Subscription Fix: - First-year members no longer get subscription rows (membership fee covers current FY) - First-year dependents no longer get subscription rows (addition fee covers current FY) - MembershipValidationService bypasses subscription check for first-year members - AutoFreezeService.checkSubscriptionBlock bypasses for first-year members - MembershipRulesService.canPrintCarnet bypasses for first-year members - SubscriptionGenerator skips first-year members/dependents entirely - Individual subscription pay() now redirects to payYear() (all-or-nothing family payment) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 19 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
The hidden input had min=1 with value=0, causing browser validation error "not focusable" when form submits. Changed to min=0 with empty default. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Complete guide covering board offers lifecycle, special discounts, subscription adjustments, accumulation rules, edge cases, scenarios, and anti-patterns. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Fixed crash: pagination used `total_pages` key but Pagination class returns `last_page` - Board offers index: card-based layout with status indicators, usage counts, branch names (joined), days-until-expiry warnings, and stat summary at top - Board offers form: two-column layout with live preview sidebar that shows real-time calculation examples, date validation warnings, and contextual help - Model search now joins branches table and counts payment_request usage per offer Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 18 Aug, 2026 8 commits
-
-
Mahmoud Aglan authored
SubscriptionSyncService was recreating subscription rows for waiver-acquired members on every page view and event. Added early return when transferred_from_waiver_id is set — waiver fee covers annual subscription, no separate subscription rows should exist. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Waiver-acquired members should not have subscription rows created — the waiver fee covers the annual subscription implicitly. Also sets join_date on all dependents (spouses, children, temps) when they are activated during waiver completion, using COALESCE to preserve any pre-existing value. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Both completion paths (last installment paid + early cash settlement) now set remaining_balance = 0.00. Fixed 14 existing completed plans in live DB. Archive view colors remaining green when 0, red when outstanding. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
remaining_balance is set at plan creation and never updated. For completed plans, display "0.00 (مكتمل)" in green instead of the misleading original balance. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Removed the green/blue financial summary stat cards (membership value + total paid) from member profile — only the "سجل المدفوعات" button remains 2. Deceased children and spouses now show a red "حالة الوفاة" button linking to their death case record 3. Deceased spouses now appear in the spouse table (were previously hidden by is_archived filter) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Adds comprehensive translation maps for DB column names (field labels), enum values (status, relationship, classification, gender), section headers, and boolean fields. All archive snapshot data now displays in Arabic. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Three issues fixed: 1. Deceased/archived dependents now transfer with membership (Death, Transfer, Waiver) 2. Archive snapshots (full membership history) follow the membership number on all transfer types 3. Missing Arabic labels added for transfer subtypes in Archive views Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-