conexion con api winsaai
This commit is contained in:
5
.env
5
.env
@@ -10,3 +10,8 @@ ENCRYPTION_IV=7c9f4a2d1e3b5f7a
|
||||
RECAPTCHA_SECRET=6LfkMB8rAAAAAFWMAZmIqtN0ocDzg9t1g0_xbkkN
|
||||
|
||||
SMTP_PASS=N036p7y!
|
||||
|
||||
|
||||
API_URL=http://50.21.176.205:3000
|
||||
API_USER=adminAS
|
||||
API_PASS=zC?K.Z5o2tiLN4gE
|
||||
|
||||
163
app/controllers/proveedores.php
Normal file
163
app/controllers/proveedores.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
// app/controllers/proveedores.php
|
||||
|
||||
session_start();
|
||||
|
||||
// 1) Composer autoload (phpdotenv y demás libs)
|
||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||
|
||||
// 2) Carga nuestro helper de entorno y dispara la carga de .env
|
||||
require_once __DIR__ . '/../helpers/env.php';
|
||||
loadEnv();
|
||||
|
||||
/**
|
||||
* Obtiene (y cachea en sesión) el JWT de la API usando las credenciales de $_ENV
|
||||
*/
|
||||
function getApiToken(): ?string
|
||||
{
|
||||
if (!empty($_SESSION['api_token'])) {
|
||||
return $_SESSION['api_token'];
|
||||
}
|
||||
|
||||
$url = rtrim($_ENV['API_URL'] ?? '', '/') . '/auth/login';
|
||||
$user = $_ENV['API_USER'] ?? '';
|
||||
$pass = $_ENV['API_PASS'] ?? '';
|
||||
$body = json_encode(['username'=>$user,'password'=>$pass]);
|
||||
|
||||
error_log("[getApiToken] POST $url → body: $body");
|
||||
|
||||
$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 → resp: $resp");
|
||||
|
||||
if ($http === 200 && ($data = json_decode($resp, true)) && !empty($data['token'])) {
|
||||
$_SESSION['api_token'] = $data['token'];
|
||||
return $data['token'];
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
/**
|
||||
* 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');
|
||||
// Devolvemos estructura vacía
|
||||
echo json_encode(['data' => []]);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) Construimos la URL de la API
|
||||
$apiBase = rtrim($_ENV['API_URL'] ?? '', '/');
|
||||
$url = $apiBase . '/proveedores';
|
||||
error_log("[ajax_lista] GET $url");
|
||||
|
||||
// 4) Ejecutamos cURL
|
||||
$ch = curl_init($url);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_HTTPHEADER => ["Authorization: $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("[ajax_lista] HTTP $status → $resp");
|
||||
|
||||
// 5) Parseamos y formateamos
|
||||
$dataList = [];
|
||||
if ($status === 200 && ($json = json_decode($resp, true)) && is_array($json)) {
|
||||
foreach ($json as $p) {
|
||||
$clave = htmlspecialchars($p['Clave'] ?? '', ENT_QUOTES);
|
||||
$dataList[] = [
|
||||
$clave,
|
||||
htmlspecialchars($p['Nombre'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['RFC'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Ciudad'] ?? '', ENT_QUOTES),
|
||||
htmlspecialchars($p['Telefono']?? '', ENT_QUOTES),
|
||||
// Acciones
|
||||
"<a href=\"/IMPORTADORES/proveedores/editar?clave=" . rawurlencode($clave) . "\" class=\"btn btn-sm btn-primary\">✏️</a>
|
||||
<button class=\"btn btn-sm btn-danger\" onclick=\"confirmDelete('{$clave}')\">🗑️</button>"
|
||||
];
|
||||
}
|
||||
} else {
|
||||
error_log('[ajax_lista] Respuesta inválida o status != 200');
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
$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',
|
||||
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token",'Accept: application/json'],
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 5,
|
||||
]);
|
||||
curl_exec($ch);
|
||||
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
header('Location: /IMPORTADORES/proveedores?deleted=' . ($status===200||$status===204 ? 'ok':'error'));
|
||||
exit;
|
||||
}
|
||||
@@ -93,30 +93,31 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
|
||||
</div>
|
||||
<!-- Proveedores -->
|
||||
<a
|
||||
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center <?= str_contains($_SERVER['REQUEST_URI'], '/proveedores') ? 'active' : '' ?>"
|
||||
class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'active' : '' ?>"
|
||||
data-bs-toggle="collapse"
|
||||
href="#submenuProveedores"
|
||||
role="button"
|
||||
aria-expanded="<?= str_contains($_SERVER['REQUEST_URI'], '/proveedores') ? 'true' : 'false' ?>"
|
||||
aria-expanded="<?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'true' : 'false' ?>"
|
||||
aria-controls="submenuProveedores"
|
||||
>
|
||||
🏭 Proveedores
|
||||
🏭 Proveedores
|
||||
<span class="badge bg-secondary">2</span>
|
||||
</a>
|
||||
<div
|
||||
class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/proveedores') ? 'show' : '' ?>"
|
||||
class="collapse <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores') ? 'show' : '' ?>"
|
||||
id="submenuProveedores"
|
||||
>
|
||||
<nav class="nav flex-column ms-3">
|
||||
<a
|
||||
href="/importadores/proveedores"
|
||||
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/importadores/proveedores' ? 'active' : '' ?>"
|
||||
href="/IMPORTADORES/proveedores"
|
||||
class="nav-link px-3 py-1 <?= $_SERVER['REQUEST_URI'] === '/IMPORTADORES/proveedores' ? 'active' : '' ?>"
|
||||
>
|
||||
• Lista de Proveedores
|
||||
</a>
|
||||
<a
|
||||
href="/importadores/proveedores/crear"
|
||||
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/proveedores/crear') ? 'active' : '' ?>"
|
||||
href="/IMPORTADORES/proveedores/crear"
|
||||
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/IMPORTADORES/proveedores/crear') ? 'active' : '' ?>"
|
||||
>
|
||||
• Registro de Proveedor
|
||||
</a>
|
||||
@@ -124,6 +125,7 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- SOLICITUDES DE IMPORTACIÓN -->
|
||||
<a class="nav-link px-3 py-2 d-flex justify-content-between align-items-center
|
||||
<?= str_contains($_SERVER['REQUEST_URI'], '/solicitud_importacion') ? 'active' : '' ?>"
|
||||
|
||||
110
views/proveedores/lista.php
Normal file
110
views/proveedores/lista.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>📄 Listado de Proveedores</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- Bootstrap y DataTables CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
|
||||
<style>
|
||||
body { background: #f4f6f9; font-family: 'Segoe UI', sans-serif; }
|
||||
.sidebar { width: 220px; position: fixed; height: 100vh; background: #343a40; padding-top: 60px; }
|
||||
.sidebar .nav-link { color: #ccc; padding: 12px 20px; }
|
||||
.sidebar .nav-link.active,
|
||||
.sidebar .nav-link:hover { background: #495057; color: #fff; }
|
||||
.content { margin-left: 220px; padding: 40px 20px; }
|
||||
.card { border-radius: 12px; }
|
||||
table.dataTable thead th { background: #343a40; color: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<div class="content">
|
||||
<br> <br>
|
||||
<h4 class="mb-4">📄 Listado de Proveedores</h4>
|
||||
<div class="card p-3 shadow-sm">
|
||||
<table id="proveedores-table" class="display nowrap" style="width:100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Clave</th>
|
||||
<th>Nombre</th>
|
||||
<th>RFC</th>
|
||||
<th>Ciudad</th>
|
||||
<th>Teléfono</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JS: jQuery, DataTables, Bootstrap, SweetAlert2 -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<script>
|
||||
|
||||
$(function(){
|
||||
$('#proveedores-table').DataTable({
|
||||
serverSide: true,
|
||||
processing: true,
|
||||
ajax: {
|
||||
url: '/IMPORTADORES/proveedores/ajax_lista',
|
||||
type: 'GET',
|
||||
dataSrc: function(json) {
|
||||
if (!json || !Array.isArray(json.data)) {
|
||||
console.error('Respuesta inválida de ajax_lista:', json);
|
||||
return [];
|
||||
}
|
||||
return json.data;
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('Error Ajax:', status, error, '\nResponse:', xhr.responseText);
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error al cargar proveedores',
|
||||
text: 'Revisa la consola para más detalles.',
|
||||
});
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{ data: 0 }, { data: 1 }, { data: 2 },
|
||||
{ data: 3 }, { data: 4 }, { data: 5 }
|
||||
],
|
||||
language: {
|
||||
url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function confirmDelete(clave) {
|
||||
Swal.fire({
|
||||
title: '¿Desactivar proveedor?',
|
||||
text: 'No podrá volver a usarse hasta reactivarlo.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, desactivar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
confirmButtonColor: '#d33'
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
window.location = `/IMPORTADORES/proveedores/eliminar?clave=${clave}`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
<?php if (isset($_GET['deleted']) && $_GET['deleted']==='ok'): ?>
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Proveedor desactivado',
|
||||
confirmButtonColor: '#198754'
|
||||
});
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user