# PayPal Merchant Onboarding Flow ## BEFORE FIX (The Problem) ❌ ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. User clicks "Connect with PayPal" │ │ → onboard.php creates referral │ │ → Saves to pending_onboarding.json │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 2. Redirected to PayPal Onboarding │ │ → User sees business account signup │ │ → User CLOSES browser WITHOUT completing ❌ │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 3. Returns to return.php │ │ → Queries PayPal API for merchant_id │ │ → PayPal returns: "NEG5HMUKCTQNL" (PARTNER ID!) ❌ │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 4. OLD CODE: Accepts partner ID as merchant ID ❌ │ │ → Saves "NEG5HMUKCTQNL" to merchants.json │ │ → WRONG! This is YOUR ID, not the merchant's! │ └─────────────────────────────────────────────────────────────────┘ ↓ STUCK FOREVER 😞 ``` --- ## AFTER FIX (The Solution) ✅ ``` ┌─────────────────────────────────────────────────────────────────┐ │ 1. User clicks "Connect with PayPal" │ │ → onboard.php creates referral │ │ → Saves to pending_onboarding.json │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 2. Redirected to PayPal Onboarding │ │ → User sees business account signup │ └─────────────────────────────────────────────────────────────────┘ ↙ ↘ SCENARIO A SCENARIO B (Incomplete) (Complete) ┌──────────────────────────┐ ┌──────────────────────────┐ │ User CLOSES browser │ │ User COMPLETES all │ │ WITHOUT finishing ❌ │ │ steps at PayPal ✅ │ └──────────────────────────┘ └──────────────────────────┘ ↓ ↓ ┌──────────────────────────┐ ┌──────────────────────────┐ │ Returns to return.php │ │ Returns to return.php │ │ PayPal returns: │ │ PayPal returns: │ │ "NEG5HMUKCTQNL" │ │ "ABC123XYZ456" ✅ │ │ (partner ID) │ │ (real merchant ID) │ └──────────────────────────┘ └──────────────────────────┘ ↓ ↓ ┌──────────────────────────┐ ┌──────────────────────────┐ │ NEW CODE: │ │ NEW CODE: │ │ ✅ REJECTS partner ID │ │ ✅ ACCEPTS merchant ID │ │ ✅ Marks as incomplete │ │ ✅ Saves to merchants │ │ ✅ Shows warning │ │ ✅ Shows success │ └──────────────────────────┘ └──────────────────────────┘ ↓ ↓ ┌──────────────────────────┐ ┌──────────────────────────┐ │ Dashboard shows: │ │ Dashboard shows: │ │ ⚠️ Incomplete │ │ ✅ Connected │ │ "Complete PayPal │ │ "Ready to accept │ │ signup to continue" │ │ payments" │ └──────────────────────────┘ └──────────────────────────┘ ``` --- ## Data Structure Comparison ### BEFORE FIX ❌ ```json // pending_onboarding.json { "school_ab32258ab0": { "school": "m", "created_at": 1760884706, "partner_referral_id": "YzU2NGVl...", "referral_token": "YzU2NGVl...", "merchant_id": "NEG5HMUKCTQNL", ← WRONG! This is partner ID "status": "connected" ← FALSE! Not really connected } } ``` ### AFTER FIX - Incomplete ⚠️ ```json // pending_onboarding.json { "school_ab32258ab0": { "school": "m", "created_at": 1760884706, "partner_referral_id": "YzU2NGVl...", "referral_token": "YzU2NGVl...", "status": "incomplete_onboarding", ← Honest status "note": "Merchant did not complete PayPal onboarding", "last_return_at": 1760885000 } } ``` ### AFTER FIX - Complete ✅ ```json // pending_onboarding.json { "school_3387003d82": { "school": "b", "created_at": 1760797314, "partner_referral_id": "MTQ2Njlm...", "referral_token": "MTQ2Njlm...", "merchant_id": "796GQ4VM8SWSQ", ← CORRECT! Different ID "status": "connected", ← TRUE! Really connected "connected_at": 1760797400 } } // merchants.json { "b": { "merchant_id": "796GQ4VM8SWSQ", "tracking_id": "school_3387003d82", "connected_at": 1760797400 } } ``` --- ## Key Changes in Code ### return.php ```php // OLD CODE ❌ if (!empty($resp['body']['merchant_id'])) { $merchantId = $resp['body']['merchant_id']; // Accepts ANY ID } // NEW CODE ✅ if (!empty($resp['body']['merchant_id'])) { $foundId = $resp['body']['merchant_id']; // CRITICAL: Don't accept partner's own ID if (strcasecmp($foundId, $config['partner_merchant_id']) !== 0) { $merchantId = $foundId; // Only accept if different } } ``` ### sync_merchants.php ```php // OLD CODE ❌ if (!empty($resp['body']['merchant_id'])) { $merchantId = $resp['body']['merchant_id']; // Blindly accepts } // NEW CODE ✅ if (!empty($resp['body']['merchant_id'])) { $foundId = $resp['body']['merchant_id']; // Don't accept partner ID - means onboarding not completed if (strcasecmp($foundId, $config['partner_merchant_id']) !== 0) { $merchantId = $foundId; } } ``` --- ## Testing Scenarios ### Test 1: Incomplete Onboarding ⚠️ 1. Click "Connect with PayPal" 2. See PayPal signup page 3. **Immediately click "Return to School Lunch App"** 4. **Expected Result**: - ⚠️ "Onboarding Incomplete" warning - Status: `incomplete_onboarding` - NO merchant_id saved ### Test 2: Complete Onboarding ✅ 1. Click "Connect with PayPal" 2. See PayPal signup page 3. **Complete ALL steps** (business info, email verification, etc.) 4. Click "Return to Application" 5. **Expected Result**: - ✅ "Onboarding completed" success message - Status: `connected` - Merchant ID saved (NOT `NEG5HMUKCTQNL`) ### Test 3: Sync Pending ⏳ 1. Complete onboarding but merchant_id not immediately available 2. Click "🔄 Sync Now" 3. **Expected Result**: - System queries PayPal API - Retrieves merchant_id - Updates status to `connected` --- ## Success Indicators ✅ You'll know it's working when: 1. **Different Merchant IDs**: Each merchant gets unique ID (not `NEG5HMUKCTQNL`) 2. **Clear Status**: See `connected` or `incomplete_onboarding` (not stuck) 3. **Warning Messages**: Incomplete onboardings show warnings 4. **Real Payments**: Can create orders with actual merchant IDs --- ## Your Real Example 🎯 From your `sync_debug.json`, school "b" worked correctly: ```json { "ts": 1760884845, "track": "school_3387003d82", "school": "b", "attempt": "by-tracking", "status": 200, "body": { "merchant_id": "796GQ4VM8SWSQ", ← SUCCESS! ✅ "tracking_id": "school_3387003d82" } } ``` This is what ALL your merchants should look like! 🎉