First Commit

This commit is contained in:
mark committed 2026-10-19 15:22:52 -07:00
1 parent 5eb9dd037d
commit 2e62c0e60b
11877 files changed
+2035312

No files matched your search

+151
View File
@@ -0,0 +1,151 @@
<?php
$config = require __DIR__ . '/config.php';
require __DIR__ . '/lib/PayPalClient.php';
require __DIR__ . '/lib/Storage.php';
$school = $_GET['school'] ?? '';
$track = $_GET['track'] ?? '';
$pref = $_GET['partner_referral_id'] ?? null;
if (!$school || !$track) {
header('Location: ' . rtrim($config['base_url'], '/') . '/index.php');
exit;
}
$client = new PayPalClient($config);
$storage = new Storage($config['storage_path']);
// First, PayPal may append merchantId to the return URL on successful onboarding
$merchantId = $_GET['merchantId']
?? $_GET['merchant_id']
?? $_GET['merchantIdInPayPal']
?? null;
// If not provided, use Partner Lookup API to retrieve merchant info by tracking_id.
// Docs: GET /v1/customer/partners/<partner_merchant_id>/merchant-integrations?tracking_id=
if (!$merchantId) {
$merchantId = null;
$lastResp = null;
// poll up to ~15s total
for ($i = 0; $i < 15; $i++) {
$path = '/v1/customer/partners/' . urlencode($config['partner_merchant_id']) . '/merchant-integrations?tracking_id=' . urlencode($track);
$resp = $client->api('GET', $path);
$lastResp = $resp;
if ($resp['status'] >= 200 && $resp['status'] < 300) {
if (!empty($resp['body']['merchant_id'])) {
$foundId = $resp['body']['merchant_id'];
// CRITICAL: Don't accept the partner's own ID as merchant ID
// This means the merchant hasn't completed onboarding yet
if (strcasecmp($foundId, $config['partner_merchant_id']) !== 0) {
$merchantId = $foundId;
break;
}
}
}
usleep(1000000);
}
if (!$merchantId) {
$debug = $storage->get('return_debug', []);
$debug[] = [
'ts' => time(),
'query' => $_GET,
'last_status' => $lastResp['status'] ?? null,
'last_body' => $lastResp['body'] ?? null,
'track' => $track,
'school' => $school,
'reason' => 'Merchant onboarding not completed or partner ID returned'
];
$storage->set('return_debug', $debug);
}
}
// Fallback by partner_referral_id if available and still missing
if (!$merchantId) {
// Load pending entry for additional clues
$pending = $storage->get('pending_onboarding', []);
$entry = $pending[$track] ?? [];
$prefFromStore = $entry['partner_referral_id'] ?? $entry['referral_token'] ?? null;
$pref = $pref ?: $prefFromStore;
}
if (!$merchantId && $pref) {
// Try list integrations and filter by partner_referral_id
$path = '/v1/customer/partners/' . urlencode($config['partner_merchant_id']) . '/merchant-integrations?onboarded=true';
$resp = $client->api('GET', $path);
if ($resp['status'] >= 200 && $resp['status'] < 300 && !empty($resp['body']['merchant_integrations'])) {
foreach ($resp['body']['merchant_integrations'] as $mi) {
$rid = $mi['partner_referral_id'] ?? ($mi['referral_id'] ?? null);
$foundId = $mi['merchant_id'] ?? null;
// Only accept if it's a different merchant ID (not the partner's own)
if ($rid && strcasecmp($rid, $pref) === 0 && $foundId && strcasecmp($foundId, $config['partner_merchant_id']) !== 0) {
$merchantId = $foundId;
break;
}
}
// If still not found, but the list contains exactly one new integration with our tracking id, take it
if (!$merchantId) {
foreach ($resp['body']['merchant_integrations'] as $mi) {
$foundId = $mi['merchant_id'] ?? null;
if (!empty($mi['tracking_id']) && strcasecmp($mi['tracking_id'], $track) === 0 && $foundId && strcasecmp($foundId, $config['partner_merchant_id']) !== 0) {
$merchantId = $foundId;
break;
}
}
}
}
}
// As a last resort, if merchants.json already contains the school mapping, use it
if (!$merchantId) {
$merchants = $storage->get('merchants', []);
if (!empty($merchants[$school]['merchant_id'])) {
$existingId = $merchants[$school]['merchant_id'];
// Only use if it's not the partner's own ID
if (strcasecmp($existingId, $config['partner_merchant_id']) !== 0) {
$merchantId = $existingId;
}
}
}
if (!$merchantId) {
// Mark as incomplete onboarding
$pending = $storage->get('pending_onboarding', []);
if (isset($pending[$track])) {
$pending[$track]['status'] = 'incomplete_onboarding';
$pending[$track]['last_return_at'] = time();
$pending[$track]['note'] = 'Merchant did not complete PayPal onboarding. Partner ID was returned instead.';
$storage->set('pending_onboarding', $pending);
}
// Not available yet; merchant needs to complete onboarding
header('Location: ' . rtrim($config['base_url'], '/') . '/index.php?onboard=incomplete');
exit;
}
// Persist school -> merchant mapping
$merchants = $storage->get('merchants', []);
$merchants[$school] = [
'merchant_id' => $merchantId,
'tracking_id' => $track,
'connected_at' => time(),
];
$storage->set('merchants', $merchants);
// Also annotate the matching pending record so it's visible where you looked
$pending = $storage->get('pending_onboarding', []);
if (!isset($pending[$track])) {
// if for some reason it's missing, recreate a minimal record
$pending[$track] = [
'school' => $school,
'created_at' => time(),
];
}
$pending[$track]['merchant_id'] = $merchantId;
$pending[$track]['status'] = 'connected';
$pending[$track]['connected_at'] = time();
// Store the raw return query for troubleshooting
$pending[$track]['last_return_query'] = $_GET;
$storage->set('pending_onboarding', $pending);
header('Location: ' . rtrim($config['base_url'], '/') . '/index.php?onboard=ok');
exit;