Files
4WDCSA.co.za/docs/TEST_MEMBERSHIP_LINKING.md
2025-12-05 11:49:46 +02:00

9.5 KiB

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
  • 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:

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