$user, 'password' => $pass]); error_log("[getApiToken] POST $url"); $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], CURLOPT_POSTFIELDS => $body, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, ]); $resp = curl_exec($ch); $http = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); error_log("[getApiToken] HTTP $http"); if ($http === 200 && ($data = json_decode($resp, true)) && !empty($data['token'])) { // 3) Guardamos token y tiempo actual $_SESSION['api_token'] = $data['token']; $_SESSION['api_token_time'] = time(); return $data['token']; } // 4) Si no se pudo obtener, devolvemos null error_log('[getApiToken] No se pudo obtener token de la API'); return null; } /** GET /IMPORTADORES/proveedores * Muestra la vista de listado **/ function index() { lista(); } function lista() { if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } include __DIR__ . '/../../views/proveedores/lista.php'; } /** GET /IMPORTADORES/proveedores/ajax_lista * Devuelve JSON para DataTables (siempre HTTP 200) **/ function ajax_lista() { // 1) Fijamos el header JSON header('Content-Type: application/json; charset=utf-8'); // 2) Obtener o renovar token $token = getApiToken(); if (!$token) { error_log('[ajax_lista] Sin token válido'); echo json_encode(['data' => [], 'error' => 'No se pudo obtener token de autenticación']); return; } // CORRECCIÓN: Usar la misma estructura de URL que en otras funciones $apiBase = rtrim($_ENV['API_URL'] ?? '', '/'); $url = $apiBase . '/proveedores'; // Cambié para que sea consistente error_log("[ajax_lista] GET $url"); // 4) Ejecutamos cURL $ch = curl_init($url); curl_setopt_array($ch, [ // CORRECCIÓN: Agregar "Bearer" al token CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, // Aumenté el timeout ]); $resp = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); curl_close($ch); error_log("[ajax_lista] HTTP $status"); // MEJORA: Verificar errores de cURL if ($curlError) { error_log("[ajax_lista] cURL Error: $curlError"); echo json_encode(['data' => [], 'error' => 'Error de conexión con la API']); return; } // MEJORA: Mejor manejo de errores if ($status !== 200) { error_log("[ajax_lista] Error HTTP $status: $resp"); echo json_encode(['data' => [], 'error' => "Error HTTP $status"]); return; } $json = json_decode($resp, true); if (!is_array($json)) { error_log("[ajax_lista] Respuesta no es un array válido: $resp"); echo json_encode(['data' => [], 'error' => 'Respuesta inválida de la API']); return; } error_log("[ajax_lista] Procesando " . count($json) . " proveedores"); $dataList = []; foreach ($json as $p) { $clave = htmlspecialchars($p['Clave'] ?? '', ENT_QUOTES); // Construir dirección de forma más robusta $direccionParts = array_filter([ $p['Calles'] ?? '', ($p['NumExt'] ?? '') ? 'Num. Ext: ' . $p['NumExt'] : '', ($p['NumInt'] ?? '') ? 'Num. Int: ' . $p['NumInt'] : '', $p['Colonia'] ?? '', $p['Municipio'] ?? '', $p['Ciudad'] ?? '', ($p['CodigoPostal'] ?? '') ? 'C.P. ' . $p['CodigoPostal'] : '', $p['EntidadFederativa'] ?? '', $p['Pais'] ?? '' ]); $direccion = implode(', ', $direccionParts); $dataList[] = [ $clave, htmlspecialchars($p['Nombre'] ?? '', ENT_QUOTES), htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES), htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES), htmlspecialchars($p['Telefono'] ?? '', ENT_QUOTES), htmlspecialchars($direccion, ENT_QUOTES), "✏️ " ]; } // 6) Devolvemos siempre HTTP 200 con data (posiblemente vacío) echo json_encode(['data' => $dataList]); } /** GET /IMPORTADORES/proveedores/eliminar * Llama a DELETE /api/proveedores/:clave y redirige **/ function eliminar() { $token = getApiToken(); $clave = $_GET['clave'] ?? ''; if (!$token || !$clave) { header('Location: /IMPORTADORES/proveedores'); exit; } // CORRECCIÓN: Usar la misma URL base y corregir el Authorization header $url = rtrim($_ENV['API_URL'] ?? '', '/') . '/api/proveedores/' . urlencode($clave); error_log("[eliminar] DELETE $url"); $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_CUSTOMREQUEST => 'DELETE', // CORRECCIÓN: Quitar el espacio extra y agregar Bearer CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, ]); $resp = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); error_log("[eliminar] HTTP $status: $resp"); header('Location: /IMPORTADORES/proveedores?deleted=' . ($status===200||$status===204 ? 'ok':'error')); exit; } function crear() { // 1) Aseguramos que el usuario esté logueado if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } // 2) Cargamos la vista include __DIR__ . '/../../views/proveedores/crear.php'; } /** POST /IMPORTADORES/proveedores/guardar * Procesa el alta de un nuevo proveedor contra la API WinSAAI. **/ function guardar() { // 1) Validar sesión if (empty($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; } // 2) Recoger datos del formulario $payload = [ 'Clave' => trim($_POST['Clave'] ?? ''), 'Nombre' => trim($_POST['Nombre'] ?? ''), 'RFC' => trim($_POST['RFC'] ?? ''), 'Ciudad' => trim($_POST['Ciudad'] ?? ''), 'Telefono' => trim($_POST['Telefono'] ?? ''), 'Pais' => trim($_POST['Pais'] ?? ''), 'Colonia' => trim($_POST['Colonia'] ?? ''), 'Municipio' => trim($_POST['Municipio'] ?? ''), 'CodigoPostal' => trim($_POST['CodigoPostal'] ?? ''), 'EntidadFederativa' => trim($_POST['EntidadFederativa'] ?? ''), ]; // 3) Validar campos obligatorios if ($payload['Clave']==='' || $payload['Nombre']==='' || $payload['RFC']==='' || $payload['Ciudad']==='') { $_SESSION['flash_error'] = 'Clave, Nombre, RFC y Ciudad son obligatorios.'; header('Location: /IMPORTADORES/proveedores/crear'); exit; } // 4) Obtener JWT $token = getApiToken(); if (!$token) { $_SESSION['flash_error'] = 'No fue posible autenticar contra la API.'; header('Location: /IMPORTADORES/proveedores/crear'); exit; } // 5) Llamada a la API para crear el proveedor $url = rtrim($_ENV['API_URL'] ?? '', '/') . '/api/proveedores'; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer $token", 'Content-Type: application/json' ], CURLOPT_POSTFIELDS => json_encode($payload), CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10, ]); $resp = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); // 6) Manejar respuesta if ($status === 201) { // Éxito header('Location: /IMPORTADORES/proveedores?created=ok'); exit; } else { // Error, opcionalmente parsear mensaje $msg = ''; if ($json = json_decode($resp, true)) { $msg = $json['mensaje'] ?? $json['error'] ?? ''; } $_SESSION['flash_error'] = "Error al crear proveedor (HTTP $status) $msg"; header('Location: /IMPORTADORES/proveedores/crear'); exit; } }