chore: organize documentation files into docs directory
This commit is contained in:
249
docs/TEST_MEMBERSHIP_LINKING.md
Normal file
249
docs/TEST_MEMBERSHIP_LINKING.md
Normal file
@@ -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 <commit-hash>
|
||||
```
|
||||
|
||||
Key commits to know:
|
||||
- 646a3ecb - Latest fixes (pricing calculations)
|
||||
- e63bd806 - Improved getUserMemberStatus
|
||||
- c5112e1c - Fixed form nesting issue
|
||||
- bd20fc0f - Initial feature implementation
|
||||
Reference in New Issue
Block a user