• Mahmoud Aglan's avatar
    fix(waiver): prevent reconcile() from revoking membership after successful transfer · ba9d9f81
    Mahmoud Aglan authored
    Root cause: after WaiverProcessor::execute() completed, visiting /members/{id}
    triggered MembershipPaymentGuard::reconcile(), which did not recognise waiver_fee
    as a valid activation payment. It stripped the membership_number and then called
    deactivateAllDependents(), which crashed on spouses.join_date NOT NULL constraint.
    
    Fixes:
    - MembershipPaymentGuard::reconcile(): add waiver_fee path — looks up completed
      waiver_requests where target_member_id matches, preventing false deactivation
    - MembershipPaymentGuard::deactivateAllDependents(): spouses.join_date is NOT NULL;
      use sentinel date '1970-01-01' instead of NULL to avoid constraint violation
    - MembershipPaymentGuard::deactivateDependent(): same sentinel fix for spouses
    - WaiverProcessor::execute(): set activated_by_payment_id + activated_at on the
      target member so the existing fallback check in reconcile() catches future cases
    
    Also restored member #136 directly in DB (membership_number='1600', status='active',
    activated_by_payment_id=773) which was the live victim of this bug.
    Co-Authored-By: 's avatarClaude Sonnet 4.6 <noreply@anthropic.com>
    ba9d9f81