From a038a7449e678e9c5fd7777145ebc6bf1f5f94d9 Mon Sep 17 00:00:00 2001 From: twotalesanimation <80506065+twotalesanimation@users.noreply.github.com> Date: Fri, 5 Dec 2025 11:47:29 +0200 Subject: [PATCH] docs: add comprehensive testing and implementation guide for membership linking feature --- TEST_MEMBERSHIP_LINKING.md | 249 +++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 TEST_MEMBERSHIP_LINKING.md diff --git a/TEST_MEMBERSHIP_LINKING.md b/TEST_MEMBERSHIP_LINKING.md new file mode 100644 index 00000000..4c81cfd8 --- /dev/null +++ b/TEST_MEMBERSHIP_LINKING.md @@ -0,0 +1,249 @@ +# Membership Linking Feature - Test & Verification Checklist + +## Feature Overview +This document outlines the membership linking feature that allows multiple users (e.g., married couples, family members) to share a single membership account. + +## Database Schema + +### Tables Created +1. **membership_links** - Tracks relationships between primary and secondary users + - link_id (auto-increment) + - primary_user_id - User who owns/manages the membership + - secondary_user_id - User gaining access to membership + - status (ACTIVE/INACTIVE) + - created_date + - expires_date (optional) + +2. **membership_permissions** - Granular permission control + - permission_id (auto-increment) + - link_id - Foreign key to membership_links + - permission_name (e.g., access_member_areas, member_pricing, etc.) + - granted_date + +## Core Functions (in src/config/functions.php) + +### New Functions Added +1. **linkSecondaryUserToMembership($primary_user_id, $secondary_user_id, $permissions = [])** + - Creates link and assigns default permissions + - Validates primary user has active membership + - Validates secondary user exists and doesn't already link + - Returns success/error response + +2. **getUserMembershipLink($user_id)** + - Checks if user is linked as secondary to another membership + - Returns link details if active + - Returns false if no active link + +3. **getLinkedSecondaryUsers($primary_user_id)** + - Returns array of all secondary users linked to primary + - Includes link creation date and status + - Used for UI display on membership_details page + +4. **unlinkSecondaryUser($primary_user_id, $secondary_user_id)** + - Removes link and associated permissions + - Returns success/error response + +### Modified Functions +1. **getUserMemberStatus($user_id)** + - NOW checks linked memberships at ALL failure points: + * If user has no application → check if linked to active membership + * If user hasn't accepted indemnity → check if linked + * If user has no payment record → check if linked + * If user's direct membership expired → check if linked + - Returns true for linked members even if direct membership check fails + +## API Endpoints + +### POST /src/processors/link_membership_user.php +- **Purpose**: AJAX endpoint for creating membership links +- **Parameters**: + - csrf_token (validated) + - secondary_user_email (validated) +- **Returns**: JSON response with success/error +- **Security**: CSRF token validation, database injection prevention + +### POST /src/processors/unlink_membership_user.php +- **Purpose**: AJAX endpoint for removing membership links +- **Parameters**: + - csrf_token (validated) + - secondary_user_id (validated) +- **Returns**: JSON response with success/error +- **Security**: CSRF token validation, only primary user can unlink + +## UI Implementation + +### Membership Details Page (src/pages/membership_details.php) +- Added "Linked Accounts" section OUTSIDE main info form +- Displays list of currently linked secondary users +- Form to add new linked user by email +- Unlink buttons for each linked user +- IMPORTANT FIX: Form moved outside infoForm to prevent form submission conflicts + +### Header Navigation (src/pages/header.php) +- "Members Area" dropdown shown for users with direct OR linked membership +- Uses getUserMemberStatus() to determine visibility +- Shows: Campsites & Gallery links + +## Booking Pages & Pricing + +### Protected Member Pages +- `src/pages/bookings/campsites.php` - Redirects non-members +- `src/pages/gallery/gallery.php` - Redirects non-members +- `src/pages/gallery/view_album.php` - Redirects non-members +- `src/pages/gallery/create_album.php` - Redirects non-members + +### Open Booking Pages (All Users Welcome) +1. **Trip Details** (`src/pages/bookings/trip-details.php`) + - Shows member & non-member rates + - Linked members get member pricing + - Correct calculateTotal() logic with adults/children/pensioners + +2. **Driver Training** (`src/pages/bookings/driver_training.php`) + - Pricing: Members vs Non-members + - Form fields adjusted for non-members + - FIXED: calculateTotal() now correctly: + * Members: (self + additional_members at member rate) + additional_nonmembers + * Non-members: (self + additional participants at non-member rate) + +3. **Bush Mechanics** (`src/pages/other/bush_mechanics.php`) + - FIXED: calculateTotal() pricing logic corrected + - Members: (self at member rate) + additional members + additional non-members + - Non-members: (self + additional participants at non-member rate) + +4. **Rescue & Recovery** (`src/pages/other/rescue_recovery.php`) + - FIXED: calculateTotal() pricing logic corrected + - Members: (self at member rate) + additional members + additional non-members + - Non-members: (self + additional participants at non-member rate) + +5. **Course Details** (`src/pages/bookings/course_details.php`) + - Shows member & non-member rates + - Open to all users (members and non-members) + +6. **Campsite Booking** (`src/pages/bookings/campsite_booking.php`) + - Pricing: Members stay FREE, Non-members R200/night + - Calculates based on getUserMemberStatus() + +### Booking Processors +1. **process_trip_booking.php** - ✅ Allows non-members, applies pricing correctly +2. **process_course_booking.php** - ✅ Allows non-members, applies pricing correctly +3. **process_camp_booking.php** - ✅ Allows non-members, applies pricing correctly + +## Testing Checklist + +### Unit Tests +- [ ] Link secondary user to primary user membership +- [ ] Verify linked user appears in getLinkedSecondaryUsers() +- [ ] Verify linked user gets member pricing on bookings +- [ ] Verify linked user can access member-only areas +- [ ] Unlink secondary user from primary membership +- [ ] Verify unlinked user loses member benefits +- [ ] Test with invalid secondary user email +- [ ] Test with secondary user who already has direct membership + +### Integration Tests +- [ ] Member books trip - should use member pricing +- [ ] Member books course - should use member pricing +- [ ] Member books campsite - should stay FREE +- [ ] Linked member books trip - should use member pricing +- [ ] Linked member books course - should use member pricing +- [ ] Linked member books campsite - should stay FREE +- [ ] Non-member books trip - should use non-member pricing +- [ ] Non-member books course - should use non-member pricing +- [ ] Non-member books campsite - should pay R200/night +- [ ] Linked member can view members gallery +- [ ] Non-member cannot access members gallery +- [ ] Linked member dropdown link shows in header +- [ ] Payment processing for non-member bookings + +### UI/UX Tests +- [ ] Linking form displays properly on membership details +- [ ] Unlink buttons work correctly +- [ ] "You will be added at non-member rate" message shows for non-members +- [ ] Pricing calculations update correctly as form fields change +- [ ] Member/Non-member rate display is clear + +## Known Issues & Fixes Applied + +### Issue 1: Form Submission Conflicts +- **Problem**: linkUserForm nested inside infoForm - submit triggered parent +- **Fix**: Moved linkUserForm outside infoForm closes +- **Commit**: c5112e1c + +### Issue 2: Linked Members Not Recognized +- **Problem**: getUserMemberStatus() only checked linked if no application existed +- **Fix**: Added linked checks at all failure points in function +- **Commit**: e63bd806 + +### Issue 3: JavaScript Pricing Calculations Wrong +- **Problem**: calculateTotal() in driver_training, bush_mechanics, rescue_recovery incorrectly calculated non-member totals +- **Fix**: Corrected variable names and logic to properly handle: + - Members: count themselves + additional members/non-members + - Non-members: count themselves only + additional participants +- **Commits**: + - driver_training: inline with member label UI improvement + - bush_mechanics & rescue_recovery: 646a3ecb + +## Performance Considerations + +### Database Queries +- getUserMembershipLink() - Single query with index on secondary_user_id +- getLinkedSecondaryUsers() - Single join query with index on primary_user_id +- getUserMemberStatus() - Multiple queries but cached in session after first call + +### Recommended Indexes +- membership_links(secondary_user_id) +- membership_links(primary_user_id) +- membership_links(status) + +## Security Considerations + +### Access Control +- Only primary user can link/unlink accounts +- Secondary user cannot manage their own link (primary must unlink) +- CSRF tokens validated on all membership operations + +### Input Validation +- User emails validated before linking +- User IDs validated as integers +- Links can only be created between valid users + +### Audit Trail +- All linking operations logged via auditLog() +- Timestamps recorded for all changes + +## Future Enhancements + +1. **Secondary user control** + - Allow secondary users to decline/accept links + - Option for secondary user to self-unlink + +2. **Permissions system** + - Granular control over which permissions secondary users receive + - Ability to revoke specific permissions without unlinking + +3. **Multiple primary accounts** + - Allow one user to be secondary to multiple primaries + - Flexible family/group structure support + +4. **Member linking UI** + - Search for existing members to link + - Batch link multiple users + - Link management dashboard + +5. **Expiration dates** + - Time-limited links (e.g., seasonal guests) + - Auto-renewal options + - Expiration notifications + +## Rollback Plan + +If issues arise, revert to previous commit: +```bash +git revert +``` + +Key commits to know: +- 646a3ecb - Latest fixes (pricing calculations) +- e63bd806 - Improved getUserMemberStatus +- c5112e1c - Fixed form nesting issue +- bd20fc0f - Initial feature implementation