getConnectBase() . " …\n"); $resp = $client->api('GET', '/v2/locations', $token); if ($resp['status'] === 401) { fwrite(STDERR, "\n❌ HTTP 401 Unauthorized — Square rejected this access token.\n" . " Fix: Developer Dashboard → open your app → toggle to SANDBOX → Credentials →\n" . " copy the \"Sandbox Access Token\" (starts with EAAA…). Make sure:\n" . " • you copied the SANDBOX token (not Production), and the whole string,\n" . " • it's from the SAME app as your client_id (" . $config['client_id'] . "),\n" . " • the token hasn't been rotated since you copied it.\n"); exit(1); } if ($resp['status'] < 200 || $resp['status'] >= 300) { fwrite(STDERR, "\n❌ GET /v2/locations failed (HTTP " . $resp['status'] . "): " . json_encode($resp['body']['errors'] ?? $resp['body']) . "\n"); exit(1); } $locations = $resp['body']['locations'] ?? []; if (empty($locations)) { fwrite(STDERR, "\n❌ Token is valid but the seller has no locations. Create one in the sandbox seller dashboard.\n"); exit(1); } // ── Pick a location. ───────────────────────────────────────────────────────── $wanted = isset($opts['location']) ? (string)$opts['location'] : ''; $chosen = null; foreach ($locations as $l) { if ($wanted !== '') { if (($l['id'] ?? '') === $wanted) { $chosen = $l; break; } continue; } $active = ($l['status'] ?? '') === 'ACTIVE'; $card = in_array('CREDIT_CARD_PROCESSING', $l['capabilities'] ?? [], true); if ($active && $card) { $chosen = $l; break; } // best: active + can take cards if ($active && $chosen === null) { $chosen = $l; } // fallback: any active } if ($chosen === null) $chosen = $locations[0]; if ($wanted !== '' && ($chosen['id'] ?? '') !== $wanted) { fwrite(STDERR, "\n❌ Location '$wanted' not found for this token. Available: " . implode(', ', array_map(fn($l) => $l['id'] ?? '?', $locations)) . "\n"); exit(1); } $locationId = $chosen['id']; $currency = strtoupper((string)($opts['currency'] ?? ($chosen['currency'] ?? 'CAD'))); $canCards = in_array('CREDIT_CARD_PROCESSING', $chosen['capabilities'] ?? [], true); // merchant id: --merchant, else GET /v2/merchants, else a placeholder. $merchantId = (string)($opts['merchant'] ?? ''); if ($merchantId === '') { $m = $client->api('GET', '/v2/merchants', $token); $merchantId = $m['body']['merchant'][0]['id'] ?? 'SANDBOX_TEST_MERCHANT'; } // ── Store it. ──────────────────────────────────────────────────────────────── $store = new MerchantStore($config); $store->saveConnection($school, $merchantId, $token, '', gmdate('Y-m-d\TH:i:s\Z', time() + 365 * 86400)); $store->mergeMeta($school, [ 'active_location_id' => $locationId, 'square_ready' => true, 'currency' => $currency, 'seeded_for_testing' => true, 'status_checked_at' => time(), ]); fwrite(STDOUT, "\n✅ Seeded connection for \"$school\"\n"); fwrite(STDOUT, " merchant_id : $merchantId\n"); fwrite(STDOUT, " location_id : $locationId (" . ($chosen['status'] ?? '?') . ($canCards ? ", card-capable" : ", NO card capability") . ")\n"); fwrite(STDOUT, " currency : $currency\n"); fwrite(STDOUT, " token : stored " . (empty($config['token_encryption_key']) ? "(PLAINTEXT)" : "encrypted") . "\n"); if (!$canCards) { fwrite(STDOUT, "\n⚠️ This location has no CREDIT_CARD_PROCESSING capability — card charges may fail.\n"); } fwrite(STDOUT, "\nNext: php -S 127.0.0.1:8000 then open\n"); fwrite(STDOUT, " http://127.0.0.1:8000/demo-checkout.php?school=" . rawurlencode($school) . "\n"); exit(0);