'Número de orden y código de orden son requeridos.'], $jsonOptions); } // Load env from executor/.env (helps when Apache/PHP doesn't export .env vars) function load_dotenv_if_needed(array $keys): void { $missing = array_filter($keys, fn($k) => getenv($k) === false || getenv($k) === ''); if (empty($missing)) { return; } static $loaded = false; if ($loaded) return; $envPath = realpath(__DIR__ . '/../.env'); // executor/.env if ($envPath && is_readable($envPath)) { $lines = @file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: []; foreach ($lines as $line) { $trimmed = trim($line); if ($trimmed === '' || $trimmed[0] === '#') { continue; } if (!str_contains($trimmed, '=')) continue; [$k, $v] = array_map('trim', explode('=', $trimmed, 2)); if ($k === '') continue; // Strip potential surrounding quotes $v = trim($v, "\"' "); // Do not override existing process env if (getenv($k) === false || getenv($k) === '') { putenv("{$k}={$v}"); } } $loaded = true; } } load_dotenv_if_needed(['SHALOM_API_KEY']); // API $apiKey = getenv('SHALOM_API_KEY'); // Fallback: allow setting the key from the DB (so the app works even if you can't edit .env) if (!$apiKey) { try { require_once __DIR__ . '/db/config.php'; $pdo = db(); $stmt = $pdo->prepare('SELECT valor FROM configuracion WHERE clave = ? LIMIT 1'); $stmt->execute(['SHALOM_API_KEY']); $apiKey = $stmt->fetchColumn(); if (is_string($apiKey)) { $apiKey = trim($apiKey); } else { $apiKey = null; } } catch (Throwable $e) { $apiKey = null; } } if (!$apiKey) { respond_json(500, [ 'error' => 'Falta SHALOM_API_KEY. Configura la clave en Configuración General (Administrador) o en tu .env para poder consultar el tracking.', ], $jsonOptions); } $url = 'https://shalom-api.lat/api/track'; $postData = [ 'orderNumber' => $orderNumber, 'orderCode' => $orderCode, ]; $jsonData = json_encode($postData, JSON_UNESCAPED_UNICODE); if ($jsonData === false) { respond_json(500, ['error' => 'Error serializando la solicitud a Shalom.'], $jsonOptions); } $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $jsonData, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'Accept: application/json', "Authorization: Bearer {$apiKey}", ], // Timeouts: evitamos que la UI quede esperando indefinidamente CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_TIMEOUT => 25, CURLOPT_FOLLOWLOCATION => true, ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); if ($curlError) { respond_json(502, [ 'error' => 'Error en la comunicación con la API de Shalom', 'details' => $curlError, ], $jsonOptions); } if ($response === false || $response === null || $response === '') { respond_json(502, [ 'error' => 'Shalom no devolvió respuesta', 'http_code' => $httpCode ?: null, ], $jsonOptions); } // Error HTTP del proveedor if ($httpCode >= 400) { $errorBody = json_decode($response, true); $shMessage = null; if (json_last_error() === JSON_ERROR_NONE && is_array($errorBody)) { $shMessage = $errorBody['message'] ?? $errorBody['error'] ?? null; } if ($shMessage) { respond_json($httpCode, [ 'error' => "Error de la API de Shalom: {$shMessage}", 'http_code' => $httpCode, 'details' => $errorBody ?: $response, ], $jsonOptions); } respond_json($httpCode, [ 'error' => "Error de la API de Shalom (código {$httpCode}).", 'http_code' => $httpCode, 'details' => $response, ], $jsonOptions); } // OK: devolvemos tal cual lo que responde Shalom (la UI espera JSON) echo $response;