Previously, linked membership checks only occurred if there was no membership
application record. Now linked memberships are checked as fallback at every
stage of the direct membership validation:
- No membership application check linked
- Indemnity not accepted check linked
- No membership fees record check linked
- Direct membership not active/expired check linked
This ensures linked members see themselves as active across all member areas,
detail pages, and booking forms (trips, courses, campsites, driver training,
bush mechanics, rescue & recovery).
- Created membership_links table to associate secondary users with primary memberships
- Created membership_permissions table for granular permission control
- Added linkSecondaryUserToMembership() function to create links with validation
- Added getUserMembershipLink() to check access via secondary links
- Added getLinkedSecondaryUsers() to list all secondary users for a primary member
- Added unlinkSecondaryUser() to remove links
- Updated getUserMemberStatus() to check both direct and linked memberships
- Created link_membership_user processor to handle linking via API
- Created unlink_membership_user processor to handle unlinking via API
- Added .htaccess routes for linking endpoints
- Grants default permissions: access_member_areas, member_pricing, book_campsites, book_courses, book_trips
- Includes transaction safety with rollback on errors
- Includes comprehensive documentation with usage examples
- Validates primary user has active membership before allowing links
- Prevents duplicate links and self-linking
- Add UNIQUE constraint on membership_application.user_id (one app per user)
- Add UNIQUE constraint on membership_fees.user_id (one fee record per user)
- Add validation checks in process_application.php before inserting
- Improve error messages for duplicate submission attempts
- Add migration script to clean up existing duplicates before constraints
- Update checkMembershipApplication to set session message on redirect
- Add comprehensive documentation of duplicate prevention architecture
Individual payments/EFTs are tracked separately in payments table
- Updated sendPOP() function to read recipient emails from POP_NOTIFICATION_EMAILS env variable
- Supports comma-separated email list for flexibility
- Allows dev and live servers to have different notification recipients
- Falls back to info@4wdcsa.co.za if no env variable configured