Sprint 2
This commit is contained in:
@@ -13,7 +13,8 @@ use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
loadEnv();
|
||||
|
||||
function dashboard() {
|
||||
function dashboard()
|
||||
{
|
||||
if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
|
||||
header("Location: /IMPORTADORES/login");
|
||||
exit;
|
||||
@@ -28,7 +29,8 @@ function dashboard() {
|
||||
include __DIR__ . '/../../views/agentes/dashboard.php';
|
||||
}
|
||||
|
||||
function importadores_activos() {
|
||||
function importadores_activos()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
@@ -175,8 +177,8 @@ function aprobar_solicitud()
|
||||
exit;
|
||||
}
|
||||
|
||||
function activos() {
|
||||
|
||||
function activos()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
@@ -203,9 +205,8 @@ function activos() {
|
||||
include __DIR__ . '/../../views/agentes/importadores_activos.php';
|
||||
}
|
||||
|
||||
function toggle_estado() {
|
||||
|
||||
|
||||
function toggle_estado()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false) || $_SESSION['tipo_usuario'] !== 'agente_aduanal') {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
@@ -241,3 +242,32 @@ function toggle_estado() {
|
||||
header("Location: /IMPORTADORES/agentes/activos");
|
||||
exit;
|
||||
}
|
||||
|
||||
function bitacora()
|
||||
{
|
||||
$conn = getConnection();
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT u.id_usuario, u.nombre, b.email, b.ip, b.fecha, b.exito, b.detalle
|
||||
FROM dbo.bitacora_login b
|
||||
JOIN dbo.usuarios_sistema u ON u.id_usuario = b.id_usuario
|
||||
ORDER BY b.fecha DESC
|
||||
";
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql);
|
||||
if ($stmt === false) {
|
||||
die("Error en bitacora(): " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$bitacoras = [];
|
||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$row['nombre'] = decrypt($row['nombre']); // Desencripta aquí
|
||||
$bitacoras[] = $row;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../../views/agentes/bitacora.php';
|
||||
}
|
||||
@@ -62,7 +62,7 @@ function guardar()
|
||||
// Captura los datos del formulario
|
||||
$campos = [
|
||||
'clave', 'tipo_identificador', 'curp', 'calle', 'num_exterior', 'num_interior',
|
||||
'ciudad', 'colonia', 'pais', 'codigo_postal', 'municipio', 'estado', 'fax', 'observaciones'
|
||||
'ciudad', 'colonia', 'pais', 'codigo_postal', 'municipio', 'estado', 'telefono', 'fax', 'observaciones'
|
||||
];
|
||||
|
||||
$sql_parts = [];
|
||||
@@ -75,23 +75,95 @@ function guardar()
|
||||
}
|
||||
}
|
||||
|
||||
// Si no hay datos que actualizar
|
||||
if (empty($sql_parts)) {
|
||||
header("Location: /IMPORTADORES/configuracion");
|
||||
exit;
|
||||
}
|
||||
|
||||
$sql = "UPDATE informacion_general SET " . implode(", ", $sql_parts) . " WHERE id_usuario = ?";
|
||||
$params[] = $id_usuario;
|
||||
// Iniciar transacción para asegurar consistencia
|
||||
sqlsrv_begin_transaction($conn);
|
||||
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
try {
|
||||
// 1. Actualiza la tabla informacion_general
|
||||
$sql = "UPDATE informacion_general SET " . implode(", ", $sql_parts) . " WHERE id_usuario = ?";
|
||||
$params[] = $id_usuario;
|
||||
|
||||
if ($stmt === false) {
|
||||
die(print_r(sqlsrv_errors(), true));
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
if ($stmt === false) {
|
||||
throw new Exception(print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// 2. Actualiza el teléfono en solicitudes_importadores usando company_name encriptado
|
||||
if (isset($_POST['telefono']) && $_POST['telefono'] !== '') {
|
||||
$telefono = $_POST['telefono'];
|
||||
|
||||
// Primero obtenemos el nombre de la empresa de informacion_general
|
||||
$sql_get_name = "SELECT nombre FROM informacion_general WHERE id_usuario = ?";
|
||||
$params_get_name = [$id_usuario];
|
||||
$stmt_get_name = sqlsrv_query($conn, $sql_get_name, $params_get_name);
|
||||
|
||||
if ($stmt_get_name === false) {
|
||||
throw new Exception("Error al obtener nombre de empresa: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
$empresa_data = sqlsrv_fetch_array($stmt_get_name, SQLSRV_FETCH_ASSOC);
|
||||
|
||||
if ($empresa_data && !empty($empresa_data['nombre'])) {
|
||||
$nombre_empresa = $empresa_data['nombre'];
|
||||
|
||||
// Encriptar el nombre de la empresa para comparar
|
||||
$nombre_encriptado = encrypt($nombre_empresa);
|
||||
|
||||
// Actualizar solicitudes_importadores usando el company_name encriptado
|
||||
$sql_solicitud = "UPDATE solicitudes_importadores SET phone = ? WHERE company_name = ?";
|
||||
$params_solicitud = [$telefono, $nombre_encriptado];
|
||||
|
||||
$stmt_solicitud = sqlsrv_query($conn, $sql_solicitud, $params_solicitud);
|
||||
|
||||
if ($stmt_solicitud === false) {
|
||||
throw new Exception("Error al actualizar teléfono en solicitudes: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
|
||||
// Verificar si se actualizó algún registro
|
||||
$rows_affected = sqlsrv_rows_affected($stmt_solicitud);
|
||||
if ($rows_affected === false || $rows_affected == 0) {
|
||||
// Log para debugging
|
||||
error_log("No se encontró registro en solicitudes_importadores para actualizar teléfono. Empresa: " . $nombre_empresa);
|
||||
|
||||
// Opcional: Buscar por RFC como fallback
|
||||
$sql_rfc = "SELECT rfc FROM informacion_general WHERE id_usuario = ?";
|
||||
$stmt_rfc = sqlsrv_query($conn, $sql_rfc, [$id_usuario]);
|
||||
|
||||
if ($stmt_rfc) {
|
||||
$rfc_data = sqlsrv_fetch_array($stmt_rfc, SQLSRV_FETCH_ASSOC);
|
||||
if ($rfc_data && !empty($rfc_data['rfc'])) {
|
||||
$sql_solicitud_rfc = "UPDATE solicitudes_importadores SET phone = ? WHERE rfc = ?";
|
||||
$params_solicitud_rfc = [$telefono, $rfc_data['rfc']];
|
||||
|
||||
$stmt_solicitud_rfc = sqlsrv_query($conn, $sql_solicitud_rfc, $params_solicitud_rfc);
|
||||
|
||||
if ($stmt_solicitud_rfc === false) {
|
||||
error_log("Error al actualizar por RFC: " . print_r(sqlsrv_errors(), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error_log("No se pudo obtener el nombre de la empresa para el usuario: " . $id_usuario);
|
||||
}
|
||||
}
|
||||
|
||||
// Confirmar transacción
|
||||
sqlsrv_commit($conn);
|
||||
|
||||
header("Location: /IMPORTADORES/configuracion/index");
|
||||
exit;
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Revertir transacción en caso de error
|
||||
sqlsrv_rollback($conn);
|
||||
die("Error al actualizar datos: " . $e->getMessage());
|
||||
}
|
||||
|
||||
header("Location: /IMPORTADORES/configuracion/index");
|
||||
exit;
|
||||
}
|
||||
|
||||
function automatizaciones()
|
||||
|
||||
@@ -24,6 +24,17 @@ function index()
|
||||
|
||||
function opciones()
|
||||
{
|
||||
$conn = getConnection();
|
||||
$id_usuario = $_SESSION['usuario_id'] ?? null;
|
||||
|
||||
// Asegúrate de que el usuario está autenticado
|
||||
if (!$id_usuario) {
|
||||
die("Usuario no autenticado.");
|
||||
}
|
||||
|
||||
// Obtener correos
|
||||
$correos = obtenerCorreos($conn, $id_usuario);
|
||||
|
||||
include __DIR__ . '/../../views/seguridad/agregar.php';
|
||||
}
|
||||
|
||||
@@ -145,6 +156,35 @@ function correoExtra()
|
||||
}
|
||||
}
|
||||
|
||||
function modificarCorreoExtra()
|
||||
{
|
||||
if (!isset($_SESSION['usuario_id']) || ($_SESSION['pendiente_confirmacion'] ?? false)) {
|
||||
echo "Error: no se ha iniciado sesión o sesión incompleta.";
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$conn = getConnection();
|
||||
|
||||
$correo = $_POST['email-extra'] ?? '';
|
||||
|
||||
if (!filter_var($correo, FILTER_VALIDATE_EMAIL)) {
|
||||
echo "Correo inválido.";
|
||||
return;
|
||||
}
|
||||
|
||||
$query = "UPDATE correo_extra SET correo = ? WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$correo, $id_usuario]);
|
||||
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
$_SESSION['config_success'] = 'Correo adicional actualizado correctamente.';
|
||||
header('Location: /IMPORTADORES/seguridad/index');
|
||||
exit;
|
||||
} else {
|
||||
echo "Error al actualizar el correo extra.";
|
||||
}
|
||||
}
|
||||
|
||||
function correoRespaldo()
|
||||
{
|
||||
// CORRIGIDO: Cambiar id_usuario por usuario_id y verificar confirmación
|
||||
@@ -184,6 +224,35 @@ function correoRespaldo()
|
||||
}
|
||||
}
|
||||
|
||||
function modificarCorreoRspaldo()
|
||||
{
|
||||
if (!isset($_SESSION['usuario_id']) || ($_SESSION['pendiente_confirmacion'] ?? false)) {
|
||||
echo "Error: no se ha iniciado sesión o sesión incompleta.";
|
||||
exit;
|
||||
}
|
||||
|
||||
$id_usuario = $_SESSION['usuario_id'];
|
||||
$conn = getConnection();
|
||||
|
||||
$correo = $_POST['email-respaldo'] ?? '';
|
||||
|
||||
if (!filter_var($correo, FILTER_VALIDATE_EMAIL)) {
|
||||
echo "Correo inválido.";
|
||||
return;
|
||||
}
|
||||
|
||||
$query = "UPDATE correo_respaldo SET correo = ? WHERE id_usuario = ?";
|
||||
$stmt = sqlsrv_prepare($conn, $query, [$correo, $id_usuario]);
|
||||
|
||||
if ($stmt && sqlsrv_execute($stmt)) {
|
||||
$_SESSION['config_success'] = 'Correo de respaldo actualizado correctamente.';
|
||||
header('Location: /IMPORTADORES/seguridad/index');
|
||||
exit;
|
||||
} else {
|
||||
echo "Error al actualizar el correo de respaldo.";
|
||||
}
|
||||
}
|
||||
|
||||
function obtenerCorreos($conn, $id_usuario)
|
||||
{
|
||||
$correos = [
|
||||
|
||||
@@ -77,14 +77,17 @@ function lista() {
|
||||
f.*,
|
||||
tr.nombre AS transportista,
|
||||
(c.nombre + ' ' + c.apellido) AS chofer,
|
||||
p.nombre AS nombre_pais_proveedor,
|
||||
f.foto_solicitud_url
|
||||
FROM dbo.solicitud_importacion_factura f
|
||||
JOIN dbo.transportistas tr
|
||||
ON f.transportista_id = tr.id_transportista
|
||||
ON f.transportista_id = tr.id_transportista
|
||||
LEFT JOIN dbo.choferes c
|
||||
ON f.chofer_id = c.id_chofer
|
||||
ON f.chofer_id = c.id_chofer
|
||||
LEFT JOIN dbo.paises p
|
||||
ON f.pais_proveedor = p.id_pais
|
||||
WHERE f.id_importador = ?
|
||||
AND f.status >= 1
|
||||
AND f.status >= 1
|
||||
ORDER BY f.created_at DESC
|
||||
";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$id_importador]);
|
||||
@@ -104,7 +107,8 @@ function lista() {
|
||||
}
|
||||
|
||||
/** Formulario de nueva factura **/
|
||||
function crear() {
|
||||
function crear()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
exit;
|
||||
@@ -114,7 +118,7 @@ function crear() {
|
||||
|
||||
// Carga de datos para selects
|
||||
$transportistas = [];
|
||||
$stmtT = sqlsrv_query($conn, "SELECT id_transportista,nombre FROM dbo.transportistas WHERE id_usuario=? AND activo=1 ORDER BY nombre",[$id_importador]);
|
||||
$stmtT = sqlsrv_query($conn, "SELECT id_transportista, clave_identificador, nombre FROM dbo.transportistas WHERE id_usuario=? AND activo=1 ORDER BY nombre",[$id_importador]);
|
||||
while ($r = sqlsrv_fetch_array($stmtT, SQLSRV_FETCH_ASSOC)) { $transportistas[] = $r; }
|
||||
|
||||
$choferes = [];
|
||||
@@ -122,15 +126,15 @@ function crear() {
|
||||
while ($r = sqlsrv_fetch_array($stmtC, SQLSRV_FETCH_ASSOC)) { $choferes[] = $r; }
|
||||
|
||||
$paises = [];
|
||||
$stmtP = sqlsrv_query($conn, "SELECT id_pais,nombre FROM dbo.paises ORDER BY nombre");
|
||||
$stmtP = sqlsrv_query($conn, "SELECT id_pais, nombre FROM dbo.paises ORDER BY nombre");
|
||||
while ($r = sqlsrv_fetch_array($stmtP, SQLSRV_FETCH_ASSOC)) { $paises[] = $r; }
|
||||
|
||||
$aduanas = [];
|
||||
$stmtA = sqlsrv_query($conn, "SELECT aduana_seccion,nombre FROM dbo.aduanas ORDER BY aduana_seccion");
|
||||
$stmtA = sqlsrv_query($conn, "SELECT DISTINCT RIGHT(REPLICATE('0', 3) + CAST(aduana_seccion AS VARCHAR), 3) AS aduana_seccion, nombre FROM dbo.aduanas ORDER BY aduana_seccion");
|
||||
while ($r = sqlsrv_fetch_array($stmtA, SQLSRV_FETCH_ASSOC)) { $aduanas[] = $r; }
|
||||
|
||||
$incoterms = [];
|
||||
$stmtI = sqlsrv_query($conn, "SELECT INCOTERM,DESCESPANOL FROM dbo.gIncoterms ORDER BY INCOTERM");
|
||||
$stmtI = sqlsrv_query($conn, "SELECT INCOTERM, DESCESPANOL FROM dbo.gIncoterms ORDER BY INCOTERM");
|
||||
while ($r = sqlsrv_fetch_array($stmtI, SQLSRV_FETCH_ASSOC)) { $incoterms[] = $r; }
|
||||
|
||||
$unidades_medida = [];
|
||||
@@ -143,7 +147,8 @@ function crear() {
|
||||
}
|
||||
|
||||
/** Procesa la creación de una nueva factura y sus partidas **/
|
||||
function guardar() {
|
||||
function guardar()
|
||||
{
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
session_start();
|
||||
require_once __DIR__ . '/../../config/database.php';
|
||||
|
||||
/**
|
||||
* Listado de transportes (sólo activos) para el importador logueado
|
||||
*/
|
||||
/** Listado de transportes (sólo activos) para el importador logueado **/
|
||||
function lista() {
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
@@ -31,9 +29,7 @@ function lista() {
|
||||
include __DIR__ . '/../../views/transportes/lista.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formulario de alta de transporte
|
||||
*/
|
||||
/** Formulario de alta de transporte **/
|
||||
function crear() {
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
@@ -44,7 +40,7 @@ function crear() {
|
||||
|
||||
// Traer transportistas propios para el select
|
||||
$sql = "
|
||||
SELECT id_transportista, nombre
|
||||
SELECT id_transportista, clave_identificador, nombre
|
||||
FROM dbo.transportistas
|
||||
WHERE id_usuario = ? AND activo = 1
|
||||
ORDER BY nombre
|
||||
@@ -58,9 +54,7 @@ function crear() {
|
||||
include __DIR__ . '/../../views/transportes/crear.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Procesa la creación de un nuevo transporte
|
||||
*/
|
||||
/** Procesa la creación de un nuevo transporte **/
|
||||
function guardar() {
|
||||
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -101,9 +95,7 @@ function guardar() {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formulario de edición
|
||||
*/
|
||||
/** Formulario de edición **/
|
||||
function editar() {
|
||||
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -143,9 +135,7 @@ function editar() {
|
||||
include __DIR__ . '/../../views/transportes/editar.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Procesa la actualización
|
||||
*/
|
||||
/** Procesa la actualización **/
|
||||
function actualizar() {
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
@@ -206,11 +196,7 @@ function actualizar() {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* “Soft-delete” (status = 0)
|
||||
*/
|
||||
/** “Soft-delete” (status = 0) **/
|
||||
function eliminar() {
|
||||
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -232,9 +218,7 @@ function eliminar() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formulario de importación masiva
|
||||
*/
|
||||
/** Formulario de importación masiva **/
|
||||
function masivo() {
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
header('Location: /IMPORTADORES/login');
|
||||
@@ -243,9 +227,7 @@ function masivo() {
|
||||
include __DIR__ . '/../../views/transportes/importar_masivo.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Procesa la importación masiva desde CSV
|
||||
*/
|
||||
/** Procesa la importación masiva desde CSV **/
|
||||
function importarGuardar() {
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
die("⚠️ No autorizado.");
|
||||
|
||||
@@ -460,7 +460,6 @@ function actualizar() {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
function eliminar() {
|
||||
session_start();
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
|
||||
132
views/agentes/bitacora.php
Normal file
132
views/agentes/bitacora.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Dashboard | Agente Aduanal</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
|
||||
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background-color: #f4f6f9;
|
||||
}
|
||||
.sidebar {
|
||||
width: 220px;
|
||||
height: 100vh;
|
||||
background-color: #343a40;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding-top: 56px; /* Alineado con la altura de la navbar */
|
||||
z-index: 1040; /* Asegura que esté por encima del contenido */
|
||||
}
|
||||
.sidebar .nav-link {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.sidebar .nav-link:hover,
|
||||
.sidebar .nav-link.active {
|
||||
background-color: #495057;
|
||||
color: #fff;
|
||||
}
|
||||
.content {
|
||||
margin-top: 56px; /* Ajusta debajo de navbar */
|
||||
padding: 40px 20px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background-color: #f4f6f9; /* Asegura fondo uniforme */
|
||||
transition: margin-left 0.3s ease;
|
||||
}
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1050;
|
||||
}
|
||||
/* A partir de dispositivos medianos (>=768px), deja espacio lateral */
|
||||
@media (min-width: 768px) {
|
||||
.content {
|
||||
margin-left: 250px; /* Ancho del sidebar */
|
||||
}
|
||||
}
|
||||
|
||||
/* En móviles, sin margen lateral */
|
||||
@media (max-width: 767.98px) {
|
||||
.content {
|
||||
margin-left: 0;
|
||||
}
|
||||
.sidebar .nav-link {
|
||||
font-weight: normal;
|
||||
color: #343a40;
|
||||
background-color: transparent;
|
||||
}
|
||||
.sidebar .nav-link:hover,
|
||||
.sidebar .nav-link.active {
|
||||
background-color: #e9ecef;
|
||||
color: #212529;
|
||||
}
|
||||
}
|
||||
.card { border-radius: 12px; }
|
||||
table.dataTable thead th { background: #343a40; color: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="content">
|
||||
<h4 class="mb-4">👥 Acceso de Usuarios</h4>
|
||||
|
||||
<div class="card p-3 shadow-sm">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="tabla-logins">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Nombre</th>
|
||||
<th>Correo</th>
|
||||
<th>IP</th>
|
||||
<th>Fecha</th>
|
||||
<th>Estatus</th>
|
||||
<th>Detalles</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($bitacoras as $b): ?>
|
||||
<tr>
|
||||
<td><?= htmlspecialchars($b['id_usuario']) ?></td>
|
||||
<td><?= htmlspecialchars($b['nombre']) ?></td>
|
||||
<td><?= htmlspecialchars($b['email']) ?></td>
|
||||
<td><?= htmlspecialchars($b['ip']) ?></td>
|
||||
<td><?= $b['fecha']->format('Y-m-d H:i:s') ?></td>
|
||||
<td>
|
||||
<?= $b['exito'] == 1 ? 'Éxito' : 'Fallido' ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($b['detalle']) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#tabla-logins').DataTable({
|
||||
language: {
|
||||
url: '//cdn.datatables.net/plug-ins/1.13.4/i18n/es-ES.json'
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +1,7 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../app/helpers/crypto.php';
|
||||
include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
@@ -47,40 +51,36 @@
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
require_once __DIR__ . '/../../app/helpers/crypto.php';
|
||||
include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
?>
|
||||
<!-- 📄 CONTENIDO -->
|
||||
<div class="content">
|
||||
<h4 class="mb-4">Panel principal del agente</h4>
|
||||
<!-- 📄 CONTENIDO -->
|
||||
<div class="content">
|
||||
<h4 class="mb-4">Panel principal del agente</h4>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-primary">Importadores activos</h5>
|
||||
<p>Consulta los que ya fueron autorizados.</p>
|
||||
<a href="/IMPORTADORES/importadores/activos" class="btn btn-primary btn-sm mt-2">Ver importadores</a>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-primary">Importadores activos</h5>
|
||||
<p>Consulta los que ya fueron autorizados.</p>
|
||||
<a href="/IMPORTADORES/AGENTES/activos" class="btn btn-primary btn-sm mt-2">Ver importadores</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Solicitudes pendientes</h5>
|
||||
<p>Valida nuevas solicitudes de registro.</p>
|
||||
<a href="/IMPORTADORES/AGENTES/solicitudes_pendientes" class="btn btn-success btn-sm mt-2">Ver solicitudes</a>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-success">Solicitudes pendientes</h5>
|
||||
<p>Valida nuevas solicitudes de registro.</p>
|
||||
<a href="/IMPORTADORES/AGENTES/solicitudes_pendientes" class="btn btn-success btn-sm mt-2">Ver solicitudes</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-warning">Bitácora del sistema</h5>
|
||||
<p>Revisa los accesos y acciones recientes.</p>
|
||||
<a href="/IMPORTADORES/bitacoras/login" class="btn btn-warning btn-sm mt-2">Ver bitácora</a>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm p-3">
|
||||
<h5 class="text-warning">Bitácora del sistema</h5>
|
||||
<p>Revisa los accesos y acciones recientes.</p>
|
||||
<a href="/IMPORTADORES/agentes/bitacora" class="btn btn-warning btn-sm mt-2">Ver bitácora</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -2,88 +2,95 @@
|
||||
require_once __DIR__ . '/../../app/helpers/crypto.php';
|
||||
include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
?>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<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>
|
||||
<html>
|
||||
<head>
|
||||
<title>Dashboard | Agente Aduanal</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<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>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background-color: #f4f6f9;
|
||||
}
|
||||
.sidebar {
|
||||
width: 220px;
|
||||
height: 100vh;
|
||||
background-color: #343a40;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding-top: 60px;
|
||||
}
|
||||
.sidebar .nav-link {
|
||||
color: #ccc;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active {
|
||||
background-color: #495057;
|
||||
color: #fff;
|
||||
}
|
||||
.content {
|
||||
margin-left: 220px;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background-color: #f4f6f9;
|
||||
}
|
||||
.sidebar {
|
||||
width: 220px;
|
||||
height: 100vh;
|
||||
background-color: #343a40;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding-top: 60px;
|
||||
}
|
||||
.sidebar .nav-link {
|
||||
color: #ccc;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
.sidebar .nav-link:hover, .sidebar .nav-link.active {
|
||||
background-color: #495057;
|
||||
color: #fff;
|
||||
}
|
||||
.content {
|
||||
margin-left: 220px;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 1000;
|
||||
}
|
||||
.card {
|
||||
border-radius: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<div class="content px-4 pt-5 mt-4">
|
||||
<h4>✅ Importadores Activos</h4>
|
||||
<body>
|
||||
<div class="content px-4 pt-5 mt-4">
|
||||
<h4>✅ Importadores Activos</h4>
|
||||
|
||||
<table class="table table-hover mt-3 align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nombre</th>
|
||||
<th>Correo</th>
|
||||
<th>Fecha Registro</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($importadores as $i): ?>
|
||||
<table class="table table-hover mt-3 align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<td><?= $i['id_usuario'] ?></td>
|
||||
<td><?= htmlspecialchars(($i['nombre'])) ?></td>
|
||||
<td><?= htmlspecialchars($i['email']) ?></td>
|
||||
<td><?= isset($i['creado_en']) && $i['creado_en'] instanceof DateTime ? $i['creado_en']->format('Y-m-d H:i') : '' ?></td>
|
||||
<td>
|
||||
<?php if (isset($i['activo']) && $i['activo'] == 1): ?>
|
||||
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-danger">Suspender</a>
|
||||
<?php else: ?>
|
||||
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-success">Activar</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<th>#</th>
|
||||
<th>Nombre</th>
|
||||
<th>Correo</th>
|
||||
<th>Fecha Registro</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($importadores as $i): ?>
|
||||
<tr>
|
||||
<td><?= $i['id_usuario'] ?></td>
|
||||
<td><?= htmlspecialchars(($i['nombre'])) ?></td>
|
||||
<td><?= htmlspecialchars($i['email']) ?></td>
|
||||
<td><?= isset($i['creado_en']) && $i['creado_en'] instanceof DateTime ? $i['creado_en']->format('Y-m-d H:i') : '' ?></td>
|
||||
<td>
|
||||
<?php if (isset($i['activo']) && $i['activo'] == 1): ?>
|
||||
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-danger">Suspender</a>
|
||||
<?php else: ?>
|
||||
<a href="/IMPORTADORES/agentes/toggle_estado?id=<?= $i['id_usuario'] ?>&success=1" class="btn btn-sm btn-success">Activar</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<script>
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Estado actualizado',
|
||||
text: 'El estado del usuario se ha actualizado correctamente.',
|
||||
confirmButtonColor: '#198754'
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
<?php if (isset($_GET['success'])): ?>
|
||||
<script>
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
title: 'Estado actualizado',
|
||||
text: 'El estado del usuario se ha actualizado correctamente.',
|
||||
confirmButtonColor: '#198754'
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -2,7 +2,10 @@
|
||||
require_once __DIR__ . '/../../app/helpers/crypto.php';
|
||||
include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
?>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<html>
|
||||
<head>
|
||||
<title>Dashboard | Agente Aduanal</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
@@ -43,43 +46,48 @@ include __DIR__ . '/../partials/sidebar_agente.php';
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<div class="content px-4 pt-5 mt-4">
|
||||
<h4>📥 Solicitudes Pendientes</h4>
|
||||
<body>
|
||||
|
||||
<table class="table table-hover mt-3 align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Empresa</th>
|
||||
<th>RFC</th>
|
||||
<th>Correo</th>
|
||||
<th>Teléfono</th>
|
||||
<th>Fecha</th>
|
||||
<th>Archivo SAT</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($solicitudes as $s): ?>
|
||||
<div class="content px-4 pt-5 mt-4">
|
||||
<h4>📥 Solicitudes Pendientes</h4>
|
||||
|
||||
<table class="table table-hover mt-3 align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<td><?= $s['request_id'] ?></td>
|
||||
<td><?= htmlspecialchars(decrypt($s['company_name'])) ?></td>
|
||||
<td><?= htmlspecialchars(decrypt($s['rfc'])) ?></td>
|
||||
<td><?= htmlspecialchars($s['email']) ?></td>
|
||||
<td><?= htmlspecialchars($s['phone']) ?></td>
|
||||
<td><?= $s['request_date'] ? $s['request_date']->format('Y-m-d H:i') : '' ?></td>
|
||||
<td>
|
||||
<?php if (!empty($s['opinion_file'])): ?>
|
||||
<a href="/IMPORTADORES/ver_opinion.php?file=<?= urlencode($s['opinion_file']) ?>" target="_blank" class="btn btn-sm btn-outline-secondary">Ver PDF</a>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">No adjunto</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/IMPORTADORES/agentes/aprobar_solicitud?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success">Aprobar</a>
|
||||
</td>
|
||||
<th>#</th>
|
||||
<th>Empresa</th>
|
||||
<th>RFC</th>
|
||||
<th>Correo</th>
|
||||
<th>Teléfono</th>
|
||||
<th>Fecha</th>
|
||||
<th>Archivo SAT</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($solicitudes as $s): ?>
|
||||
<tr>
|
||||
<td><?= $s['request_id'] ?></td>
|
||||
<td><?= htmlspecialchars(decrypt($s['company_name'])) ?></td>
|
||||
<td><?= htmlspecialchars(decrypt($s['rfc'])) ?></td>
|
||||
<td><?= htmlspecialchars($s['email']) ?></td>
|
||||
<td><?= htmlspecialchars($s['phone']) ?></td>
|
||||
<td><?= $s['request_date'] ? $s['request_date']->format('Y-m-d H:i') : '' ?></td>
|
||||
<td>
|
||||
<?php if (!empty($s['opinion_file'])): ?>
|
||||
<a href="/IMPORTADORES/ver_opinion.php?file=<?= urlencode($s['opinion_file']) ?>" target="_blank" class="btn btn-sm btn-outline-secondary">Ver PDF</a>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">No adjunto</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="/IMPORTADORES/agentes/aprobar_solicitud?id=<?= $s['request_id'] ?>" class="btn btn-sm btn-success">Aprobar</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -84,17 +84,22 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
|
||||
<h4 class="mb-4">ℹ️ Información General</h4>
|
||||
<div class="card shadow-sm p-4 mb-4 bg-white">
|
||||
<form>
|
||||
<div class="row mb-2">
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Clave:</label>
|
||||
<div class="col-md-3">
|
||||
<input type="text" class="form-control" value="<?= htmlspecialchars($datos['clave'] ?? '') ?>" disabled>
|
||||
</div>
|
||||
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-3"></div>
|
||||
|
||||
<label class="col-md-2 col-form-label">Tipo de identificador:</label>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control" value="<?= htmlspecialchars($datos['tipo_identificador'] ?? '') ?>" disabled>
|
||||
<div class="col-md-2">
|
||||
<select name="tipo_identificador" class="form-control" disabled>
|
||||
<option value="">-- Selecciona una opción --</option>
|
||||
<option value="1" <?= ($datos['tipo_identificador'] ?? '') == '1' ? 'selected' : '' ?>>1 - RFC</option>
|
||||
<option value="2" <?= ($datos['tipo_identificador'] ?? '') == '2' ? 'selected' : '' ?>>2 - CURP</option>
|
||||
<option value="3" <?= ($datos['tipo_identificador'] ?? '') == '3' ? 'selected' : '' ?>>3 - SIN TAX ID</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -88,20 +88,23 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
|
||||
<h4 class="mb-4">✏️ Editar Información</h4>
|
||||
<div class="card shadow-sm p-4 mb-4 bg-white">
|
||||
<form id="form-edicion" method="POST" action="/IMPORTADORES/configuracion/guardar">
|
||||
<div class="row mb-2">
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Clave:</label>
|
||||
<div class="col-md-3">
|
||||
<input type="text" name="clave" maxlength="8"
|
||||
class="form-control" value="<?= htmlspecialchars($datos['clave'] ?? '') ?>" disabled>
|
||||
</div>
|
||||
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-3"></div>
|
||||
|
||||
<label class="col-md-2 col-form-label">Tipo de identificador:</label>
|
||||
<div class="col-md-4">
|
||||
<input type="number" name="tipo_identificador"
|
||||
class="form-control" value="<?= htmlspecialchars($datos['tipo_identificador'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['tipo_identificador'] ?? '') ?>'">
|
||||
<div class="col-md-2">
|
||||
<select name="tipo_identificador" class="form-control" required>
|
||||
<option value="">-- Selecciona una opción --</option>
|
||||
<option value="1" <?= ($datos['tipo_identificador'] ?? '') == '1' ? 'selected' : '' ?>>1 - RFC</option>
|
||||
<option value="2" <?= ($datos['tipo_identificador'] ?? '') == '2' ? 'selected' : '' ?>>2 - CURP</option>
|
||||
<option value="3" <?= ($datos['tipo_identificador'] ?? '') == '3' ? 'selected' : '' ?>>3 - SIN TAX ID</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -123,87 +126,78 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
|
||||
<label class="col-md-1 col-form-label">CURP:</label>
|
||||
<div class="col-md-5">
|
||||
<input type="text" name="curp" maxlength="18"
|
||||
class="form-control" value="<?= htmlspecialchars($datos['curp'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['curp'] ?? '') ?>'">
|
||||
class="form-control" value="<?= htmlspecialchars($datos['curp'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Calle:</label>
|
||||
<div class="col-md-10">
|
||||
<input type="text" name="calle" class="form-control" value="<?= htmlspecialchars($datos['calle'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['calle'] ?? '') ?>'">
|
||||
<input type="text" name="calle" class="form-control" value="<?= htmlspecialchars($datos['calle'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Núm. Exterior:</label>
|
||||
<div class="col-md-2">
|
||||
<input type="number" name="num_exterior" class="form-control" value="<?= htmlspecialchars($datos['num_exterior'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['num_exterior'] ?? '') ?>'">
|
||||
<input type="text" name="num_exterior" class="form-control" value="<?= htmlspecialchars($datos['num_exterior'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4"></div>
|
||||
|
||||
<label class="col-md-2 col-form-label">Núm. Interior:</label>
|
||||
<div class="col-md-2">
|
||||
<input type="text" name="num_interior" class="form-control" value="<?= htmlspecialchars($datos['num_interior'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['num_interior'] ?? '') ?>'">
|
||||
<input type="text" name="num_interior" class="form-control" value="<?= htmlspecialchars($datos['num_interior'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Ciudad / Localidad:</label>
|
||||
<div class="col-md-3">
|
||||
<input type="text" name="ciudad" class="form-control" value="<?= htmlspecialchars($datos['ciudad'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['ciudad'] ?? '') ?>'">
|
||||
<input type="text" name="ciudad" class="form-control" value="<?= htmlspecialchars($datos['ciudad'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-1"></div>
|
||||
|
||||
<label class="col-md-1 col-form-label">Colonia:</label>
|
||||
<div class="col-md-5">
|
||||
<input type="text" name="colonia" class="form-control" value="<?= htmlspecialchars($datos['colonia'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['colonia'] ?? '') ?>'">
|
||||
<input type="text" name="colonia" class="form-control" value="<?= htmlspecialchars($datos['colonia'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">País:</label>
|
||||
<div class="col-md-3">
|
||||
<input type="text" name="pais" class="form-control" value="<?= htmlspecialchars($datos['pais'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['pais'] ?? '') ?>'">
|
||||
<input type="text" name="pais" class="form-control" value="<?= htmlspecialchars($datos['pais'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-3"></div>
|
||||
|
||||
<label class="col-md-2 col-form-label">Código Postal:</label>
|
||||
<div class="col-md-2">
|
||||
<input type="number" name="codigo_postal" class="form-control" value="<?= htmlspecialchars($datos['codigo_postal'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['codigo_postal'] ?? '') ?>'">
|
||||
<input type="number" name="codigo_postal" class="form-control" value="<?= htmlspecialchars($datos['codigo_postal'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Municipio:</label>
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="municipio" class="form-control" value="<?= htmlspecialchars($datos['municipio'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['municipio'] ?? '') ?>'">
|
||||
<input type="text" name="municipio" class="form-control" value="<?= htmlspecialchars($datos['municipio'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-1"></div>
|
||||
|
||||
<label class="col-md-1 col-form-label">Estado:</label>
|
||||
<div class="col-md-4">
|
||||
<input type="text" name="estado" class="form-control" value="<?= htmlspecialchars($datos['estado'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['estado'] ?? '') ?>'">
|
||||
<input type="text" name="estado" class="form-control" value="<?= htmlspecialchars($datos['estado'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-md-2 col-form-label">Teléfono:</label>
|
||||
<div class="col-md-5">
|
||||
<input type="text" class="form-control" value="<?= htmlspecialchars($datos['telefono'] ?? '') ?>" disabled>
|
||||
<input type="text" name="telefono" maxlength="11"
|
||||
class="form-control" value="<?= htmlspecialchars($datos['telefono'] ?? '') ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-1"></div>
|
||||
@@ -211,8 +205,7 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
|
||||
<label class="col-md-1 col-form-label">Fax:</label>
|
||||
<div class="col-md-3">
|
||||
<input type="text" name="fax" maxlength="12"
|
||||
class="form-control" value="<?= htmlspecialchars($datos['fax'] ?? '') ?>"
|
||||
onfocus="this.value=''" onblur="if(this.value=='') this.value='<?= htmlspecialchars($datos['fax'] ?? '') ?>'">
|
||||
class="form-control" value="<?= htmlspecialchars($datos['fax'] ?? '') ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -227,9 +220,7 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
|
||||
<label class="col-md-2 col-form-label">Observaciones:</label>
|
||||
<div class="col-md-10">
|
||||
<?php $valor_obs = htmlspecialchars($datos['observaciones'] ?? ''); ?>
|
||||
<textarea name="observaciones" class="form-control" rows="3"
|
||||
onfocus="if(this.value === '<?= $valor_obs ?>') this.value=''"
|
||||
onblur="if(this.value === '') this.value='<?= $valor_obs ?>'"><?= $valor_obs ?></textarea>
|
||||
<textarea name="observaciones" class="form-control" rows="3"><?= $valor_obs ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: right;">
|
||||
@@ -241,37 +232,43 @@ include __DIR__ . '/../partials/sidebar_configuracion.php';
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script>
|
||||
document.getElementById('form-edicion').addEventListener('submit', function (event) {
|
||||
event.preventDefault(); // Evita que el formulario se envíe
|
||||
document.getElementById('form-edicion').addEventListener('submit', function (event) {
|
||||
event.preventDefault(); // Evita que el formulario se envíe
|
||||
|
||||
const curp = document.querySelector('[name="curp"]').value.trim();
|
||||
const fax = document.querySelector('[name="fax"]').value.trim();
|
||||
const curp = document.querySelector('[name="curp"]').value.trim();
|
||||
const telefono = document.querySelector('input[name="telefono"]').value.trim();
|
||||
const fax = document.querySelector('[name="fax"]').value.trim();
|
||||
|
||||
let errores = [];
|
||||
let errores = [];
|
||||
|
||||
// Validación CURP
|
||||
if (!/^[A-Z]{4}[0-9]{6}[HM](AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS)[A-Z]{3}[A-Z0-9]{2}$/.test(curp)) {
|
||||
errores.push('La CURP no tiene el formato correcto.');
|
||||
}
|
||||
// Validación CURP
|
||||
if (!/^[A-Z]{4}[0-9]{6}[HM](AS|BC|BS|CC|CL|CM|CS|CH|DF|DG|GT|GR|HG|JC|MC|MN|MS|NT|NL|OC|PL|QT|QR|SP|SL|SR|TC|TS|TL|VZ|YN|ZS)[A-Z]{3}[A-Z0-9]{2}$/.test(curp)) {
|
||||
errores.push('La CURP no tiene el formato correcto.');
|
||||
}
|
||||
|
||||
// Validación Fax
|
||||
if (fax !== '' && !/^\d{3} \d{3} \d{4}$/.test(fax)) {
|
||||
errores.push('El número de fax debe tener el formato: 123 456 7890.');
|
||||
}
|
||||
// Validación Teléfono - Ajustada para permitir diferentes formatos
|
||||
if (telefono !== '' && !/^\d{10,11}$/.test(telefono.replace(/\s/g, ''))) {
|
||||
errores.push('El número de teléfono debe tener 10 u 11 dígitos.');
|
||||
}
|
||||
|
||||
// Si hay errores, mostrar alerta y no enviar
|
||||
if (errores.length > 0) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Errores en el formulario',
|
||||
html: errores.map(e => `<p>${e}</p>`).join('')
|
||||
});
|
||||
return; // Evita que el formulario se envíe
|
||||
}
|
||||
// Validación Fax
|
||||
if (fax !== '' && !/^\d{3}\s?\d{3}\s?\d{4}$/.test(fax)) {
|
||||
errores.push('El número de fax debe tener el formato: 123 456 7890 o 1234567890.');
|
||||
}
|
||||
|
||||
// Si no hay errores, enviar el formulario
|
||||
this.submit(); // Esto sí lo envía manualmente
|
||||
});
|
||||
// Si hay errores, mostrar alerta y no enviar
|
||||
if (errores.length > 0) {
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Errores en el formulario',
|
||||
html: errores.map(e => `<p>${e}</p>`).join('')
|
||||
});
|
||||
return; // Evita que el formulario se envíe
|
||||
}
|
||||
|
||||
// Si no hay errores, enviar el formulario
|
||||
this.submit(); // Esto sí lo envía manualmente
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -8,9 +8,6 @@ if (!isset($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'agente_adu
|
||||
$nombreAgente = $_SESSION['usuario_nombre'];
|
||||
?>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 🔷 NAVBAR -->
|
||||
<nav class="navbar navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
@@ -28,6 +25,6 @@ $nombreAgente = $_SESSION['usuario_nombre'];
|
||||
<a href="/IMPORTADORES/AGENTES/dashboard" class="nav-link active">📊 Dashboard</a>
|
||||
<a href="/IMPORTADORES/AGENTES/activos" class="nav-link">✅ Importadores Activos</a>
|
||||
<a href="/IMPORTADORES/AGENTES/solicitudes_pendientes" class="nav-link">📥 Solicitudes de Registro</a>
|
||||
<a href="/IMPORTADORES/bitacoras/login" class="nav-link">🕓 Bitácora</a>
|
||||
<a href="/IMPORTADORES/AGENTES/bitacora" class="nav-link">🕓 Bitácora</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@@ -108,15 +108,24 @@ $dos_factores_estado = obtenerEstadoDosFactores();
|
||||
<div class="card shadow-sm p-3">
|
||||
<h4 class="mb-4 text-dark">Recibe Notificaciones</h4>
|
||||
<p>Agrega un correo adicional para recibir notificaciones.</p>
|
||||
<form action="/IMPORTADORES/seguridad/correoExtra" method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Correo electrónico</label>
|
||||
<input type="email" name="email-extra" class="form-control" required value="">
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Registrar</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php if (!empty($correos['correo_extra'])): ?>
|
||||
<p><?= htmlspecialchars($correos['correo_extra']) ?></p>
|
||||
<form method="POST" action="/IMPORTADORES/seguridad/modificarCorreoExtra">
|
||||
<div class="mb-3">
|
||||
<input type="email" name="email-extra" class="form-control" value="<?= htmlspecialchars($correos['correo_extra']) ?>" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-success">Actualizar</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<form method="POST" action="/IMPORTADORES/seguridad/correoExtra">
|
||||
<div class="mb-3">
|
||||
<input type="email" name="email-extra" class="form-control" placeholder="Correo adicional" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Registrar</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -125,15 +134,22 @@ $dos_factores_estado = obtenerEstadoDosFactores();
|
||||
<div class="card shadow-sm p-3">
|
||||
<h4 class="mb-4 text-dark">Correo de Respaldo</h4>
|
||||
<p>Agrega un correo de respaldo para reuperación de tu cuenta.</p>
|
||||
<form action="/IMPORTADORES/seguridad/correoRespaldo" method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Correo electrónico respaldo</label>
|
||||
<input type="email" name="email-respaldo" class="form-control" required value="">
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-success">Registrar</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php if (!empty($correos['correo_respaldo'])): ?>
|
||||
<p><?= htmlspecialchars($correos['correo_respaldo']) ?></p>
|
||||
<form method="POST" action="/IMPORTADORES/seguridad/modificarCorreoRspaldo">
|
||||
<div class="mb-3">
|
||||
<input type="email" name="email-respaldo" class="form-control" value="<?= htmlspecialchars($correos['correo_respaldo']) ?>" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success">Actualizar</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<form method="POST" action="/IMPORTADORES/seguridad/correoRespaldo">
|
||||
<div class="mb-3">
|
||||
<input type="email" name="email-respaldo" class="form-control" placeholder="Correo de respaldo" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Registrar</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="pais_proveedor" class="form-label">País (Proveedor)</label>
|
||||
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable">
|
||||
<select id="pais_proveedor" name="pais_proveedor" class="form-select searchable" required>
|
||||
<option value="">-- Selecciona País --</option>
|
||||
<?php foreach($paises as $p): ?>
|
||||
<option value="<?= htmlspecialchars($p['id_pais']) ?>"><?= htmlspecialchars($p['nombre']) ?></option>
|
||||
@@ -108,7 +108,7 @@
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="tipo_moneda" class="form-label">Moneda</label>
|
||||
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable">
|
||||
<select id="tipo_moneda" name="tipo_moneda" class="form-select searchable" required>
|
||||
<?php foreach(['MXN'=>'Peso Mexicano','USD'=>'Dólar USD','EUR'=>'Euro','CNY'=>'Yuan','GBP'=>'Libra GBP','JPY'=>'Yen'] as $code=>$label): ?>
|
||||
<option value="<?= $code ?>"><?= "$label ($code)" ?></option>
|
||||
<?php endforeach; ?>
|
||||
@@ -139,7 +139,9 @@
|
||||
<select id="transportista_id" name="transportista_id" class="form-select searchable" required>
|
||||
<option value="">-- Selecciona --</option>
|
||||
<?php foreach($transportistas as $t): ?>
|
||||
<option value="<?= htmlspecialchars($t['id_transportista']) ?>"><?= htmlspecialchars($t['nombre']) ?></option>
|
||||
<option value="<?= htmlspecialchars($t['id_transportista']) ?>">
|
||||
<?= htmlspecialchars($t['clave_identificador'] . ' - ' . $t['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
@@ -148,7 +150,9 @@
|
||||
<select id="chofer_id" name="chofer_id" class="form-select searchable" required>
|
||||
<option value="">-- Selecciona Chofer --</option>
|
||||
<?php foreach($choferes as $c): ?>
|
||||
<option value="<?= htmlspecialchars($c['id_chofer']) ?>"><?= htmlspecialchars($c['nombre']) ?></option>
|
||||
<option value="<?= htmlspecialchars($c['id_chofer']) ?>">
|
||||
<?= htmlspecialchars($c['nombre']) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
@@ -179,12 +183,12 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><input name="partidas[0][descripcion]" class="form-control w-100"></td>
|
||||
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-100"></td>
|
||||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-100"></td>
|
||||
<td><input name="partidas[0][descripcion]" class="form-control w-100" required></td>
|
||||
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control w-100" min="0" required></td>
|
||||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control w-100" min="0" required></td>
|
||||
<td>
|
||||
<div class="mb-3">
|
||||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
|
||||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable" required>
|
||||
<option value="">-- Unidad --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
|
||||
@@ -192,11 +196,11 @@
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-100"></td>
|
||||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-100"></td>
|
||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida w-100" min="0" required></td>
|
||||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control w-100" min="0" required></td>
|
||||
<td>
|
||||
<div class="mb-3">
|
||||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
|
||||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable" required>
|
||||
<option value="">-- Selecciona --</option>
|
||||
<option>General</option>
|
||||
<option>TLC</option>
|
||||
|
||||
@@ -201,8 +201,8 @@
|
||||
<?php endforeach; else: ?>
|
||||
<tr>
|
||||
<td><input name="partidas[0][descripcion]" class="form-control"></td>
|
||||
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[0][cantidad_comercial]" type="number" step="0.0001" class="form-control" min="0"></td>
|
||||
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control" min="0"></td>
|
||||
<td>
|
||||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
|
||||
<option value="">-- Unidad --</option>
|
||||
@@ -211,8 +211,8 @@
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida"></td>
|
||||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida" min="0"></td>
|
||||
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control" min="0"></td>
|
||||
<td>
|
||||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
|
||||
<option value="">-- Selecciona --</option>
|
||||
@@ -243,104 +243,125 @@
|
||||
</div>
|
||||
|
||||
<!-- Choices.js & jQuery -->
|
||||
<!-- Choices.js JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<!-- Choices.js JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.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/select2@4.1.0/dist/js/select2.min.js"></script>
|
||||
|
||||
<
|
||||
<script>
|
||||
// 1) Inicializar Choices para todos los selects excepto proveedor_id
|
||||
document.querySelectorAll('.searchable:not(#proveedor_id)').forEach(el => {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
});
|
||||
|
||||
// 2) Cargar proveedores dinámicamente
|
||||
const proveedorEl = document.getElementById('proveedor_id');
|
||||
let proveedorChoices = null;
|
||||
|
||||
fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||||
.then(res => res.ok ? res.json() : Promise.reject(res.status))
|
||||
.then(json => {
|
||||
proveedorEl.innerHTML = '<option value="">-- Selecciona Proveedor --</option>';
|
||||
json.results.forEach(item => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = item.id;
|
||||
opt.text = item.text;
|
||||
proveedorEl.add(opt);
|
||||
});
|
||||
// destruir instancia previa si existe
|
||||
if (proveedorChoices) proveedorChoices.destroy();
|
||||
proveedorChoices = new Choices(proveedorEl, {
|
||||
searchEnabled: true,
|
||||
itemSelectText: '',
|
||||
shouldSort: false
|
||||
});
|
||||
// seleccionar valor actual
|
||||
const current = '<?= htmlspecialchars($factura['proveedor_id'], ENT_QUOTES) ?>';
|
||||
if (current) {
|
||||
proveedorChoices.setChoiceByValue(current);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error cargando proveedores:', err);
|
||||
proveedorEl.innerHTML = '<option value="">No fue posible cargar proveedores</option>';
|
||||
});
|
||||
|
||||
// 3) Agregar partida dinámica
|
||||
// add-partida & validation script
|
||||
document.getElementById('add-partida').addEventListener('click', () => {
|
||||
const tbody = document.querySelector('#tabla-partidas tbody');
|
||||
const idx = tbody.querySelectorAll('tr').length;
|
||||
const row = document.createElement('tr');
|
||||
row.innerHTML = `
|
||||
<td><input name="partidas[\${idx}][descripcion]" class="form-control"></td>
|
||||
<td><input name="partidas[\${idx}][cantidad_comercial]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[\${idx}][cantidad_tarifa]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><select name="partidas[\${idx}][unidad_comercial_id]" class="form-select searchable"><option value="">-- Unidad --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<td><input name="partidas[${idx}][descripcion]" class="form-control"></td>
|
||||
<td><input name="partidas[${idx}][cantidad_comercial]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><input name="partidas[${idx}][cantidad_tarifa]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td>
|
||||
<select name="partidas[${idx}][unidad_comercial_id]" class="form-select searchable">
|
||||
<option value="">-- Unidad --</option>
|
||||
<?php foreach($unidades_medida as $um): ?>
|
||||
<option value="<?= htmlspecialchars($um['id']) ?>"><?= htmlspecialchars($um['descripcion']) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select></td>
|
||||
<td><input name="partidas[\${idx}][valor_factura]" type="number" step="0.01" class="form-control valor-partida"></td>
|
||||
<td><input name="partidas[\${idx}][peso_bruto]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td><select name="partidas[\${idx}][tasa_preferencial]" class="form-select searchable"><option value="">-- Selecciona --</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td><input name="partidas[${idx}][valor_factura]" type="number" step="0.01" class="form-control valor-partida"></td>
|
||||
<td><input name="partidas[${idx}][peso_bruto]" type="number" step="0.0001" class="form-control"></td>
|
||||
<td>
|
||||
<select name="partidas[${idx}][tasa_preferencial]" class="form-select searchable">
|
||||
<option value="">-- Selecciona --</option>
|
||||
<option>General</option><option>TLC</option><option>PROSEC</option><option>ALADI</option><option>COMERCIALIZADORA</option>
|
||||
</select></td>
|
||||
<td class="hide"><input name="partidas[\${idx}][precio_unitario]" type="number" class="form-control"></td>
|
||||
<td class="hide"><input name="partidas[\${idx}][oma_factura]" class="form-control"></td>
|
||||
</select>
|
||||
</td>
|
||||
<td class="hide"><input name="partidas[${idx}][precio_unitario]" type="number" class="form-control"></td>
|
||||
<td class="hide"><input name="partidas[${idx}][oma_factura]" class="form-control"></td>
|
||||
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
||||
`;
|
||||
tbody.appendChild(row);
|
||||
// re-init Choices para nuevos selects
|
||||
// Re-inicializar Choices.js en los nuevos selects
|
||||
row.querySelectorAll('.searchable').forEach(el => {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
});
|
||||
});
|
||||
|
||||
// 4) Remover partida
|
||||
document.querySelector('#tabla-partidas tbody').addEventListener('click', e => {
|
||||
if (e.target.matches('.remove-row')) {
|
||||
e.target.closest('tr').remove();
|
||||
// Manejador para controlar el overflow al abrir dropdowns
|
||||
document.addEventListener('click', function(e) {
|
||||
const tableContainer = document.querySelector('.table-responsive');
|
||||
if (!tableContainer) return;
|
||||
|
||||
if (e.target.closest('.choices__inner')) {
|
||||
tableContainer.style.overflow = 'visible';
|
||||
} else {
|
||||
tableContainer.style.overflow = 'auto';
|
||||
}
|
||||
});
|
||||
|
||||
// 5) Validar suma de partidas
|
||||
$('#solicitudForm').submit(function(e) {
|
||||
const total = parseFloat($('.valor-total').val()) || 0;
|
||||
document.querySelector('#tabla-partidas tbody').addEventListener('click', e => {
|
||||
if (e.target.matches('.remove-row')) e.target.closest('tr').remove();
|
||||
});
|
||||
|
||||
// validate suma partidas == valor_factura
|
||||
$('#solicitudForm').submit(function(e){
|
||||
const total = parseFloat($('#valor_factura').val())||0;
|
||||
let sum = 0;
|
||||
$('.valor-partida').each(function() {
|
||||
sum += parseFloat($(this).val()) || 0;
|
||||
});
|
||||
if (Math.abs(sum - total) > 0.01) {
|
||||
$('.valor-partida').each(function(){ sum += parseFloat($(this).val())||0; });
|
||||
if(Math.abs(sum - total) > 0.001){
|
||||
e.preventDefault();
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Error de validación',
|
||||
text: `La suma de partidas (${sum.toFixed(2)}) no coincide con Valor Factura (${total.toFixed(2)})`
|
||||
icon:'error',
|
||||
title:'Error de validación',
|
||||
text:`La suma de partidas (${sum.toFixed(2)}) no coincide con Valor Factura (${total.toFixed(2)}).`
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// ✅ DIFERENCIA PRINCIPAL: Inicializar Choices.js en partidas existentes
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Inicializar Choices.js en selects existentes de partidas (para edición)
|
||||
document.querySelectorAll('#tabla-partidas .searchable').forEach(el => {
|
||||
if (el.id !== 'proveedor_id') {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
}
|
||||
});
|
||||
|
||||
// Inicializar otros selects searchable (excepto proveedor_id que se maneja aparte)
|
||||
document.querySelectorAll('.searchable').forEach(el => {
|
||||
if (el.id !== 'proveedor_id' && !el.closest('#tabla-partidas')) {
|
||||
new Choices(el, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// proveedores script - ✅ DIFERENCIA: Pre-seleccionar proveedor existente
|
||||
const proveedorEl = document.getElementById('proveedor_id');
|
||||
const proveedorActual = '<?= htmlspecialchars($factura['proveedor_clave'] ?? '') ?>'; // ← Proveedor actual
|
||||
|
||||
fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||||
.then(res => { if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); })
|
||||
.then(json => {
|
||||
proveedorEl.innerHTML = '<option value="">-- Selecciona Proveedor --</option>';
|
||||
json.results.forEach(item => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = item.id;
|
||||
opt.text = item.text;
|
||||
// ✅ Pre-seleccionar si coincide con el proveedor actual
|
||||
if (item.id === proveedorActual) {
|
||||
opt.selected = true;
|
||||
}
|
||||
proveedorEl.add(opt);
|
||||
});
|
||||
if (proveedorEl._choice) proveedorEl._choice.destroy();
|
||||
new Choices(proveedorEl, { searchEnabled: true, itemSelectText: '', shouldSort: false });
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('Error cargando proveedores:', err);
|
||||
proveedorEl.innerHTML = '<option value="">No fue posible cargar proveedores</option>';
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +1,5 @@
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
@@ -82,7 +84,7 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<div class="content">
|
||||
<h4>📄 Solicitudes de Importación</h4>
|
||||
<a href="/IMPORTADORES/solicitud_importacion/crear" class="btn btn-success mb-3">➕ Nueva Solicitud</a>
|
||||
@@ -114,7 +116,7 @@
|
||||
<td><?= htmlspecialchars($f['fecha_factura']) ?></td>
|
||||
<td><?= htmlspecialchars($f['numero_pedimento']) ?></td>
|
||||
<td><?= htmlspecialchars($f['incoterm']) ?></td>
|
||||
<td><?= htmlspecialchars($f['pais_proveedor']) ?></td>
|
||||
<td><?= htmlspecialchars($f['nombre_pais_proveedor']) ?></td>
|
||||
<td><?= htmlspecialchars($f['tipo_moneda']) ?></td>
|
||||
<td><?= number_format($f['valor_factura'],2) ?></td>
|
||||
<td>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
@@ -77,17 +79,15 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<div class="content">
|
||||
<br> <br>
|
||||
<h4>➕ Nuevo Transporte</h4>
|
||||
<form id="formTransCrear" action="/IMPORTADORES/transportes/guardar" method="POST" enctype="multipart/form-data" class="card p-4 shadow-sm">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Vehículo *</label>
|
||||
<label class="form-label">Contenedor *</label>
|
||||
<input name="vehiculo" id="vehiculo" class="form-control" required>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
@@ -104,7 +104,7 @@
|
||||
<option value="">Selecciona...</option>
|
||||
<?php foreach($transportistas as $tr): ?>
|
||||
<option value="<?= $tr['id_transportista'] ?>">
|
||||
<?= htmlspecialchars($tr['nombre']) ?>
|
||||
<?= htmlspecialchars(($tr['clave_identificador'] . ' - ' . $tr['nombre'])) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
@@ -143,6 +143,7 @@
|
||||
// Si todas las validaciones pasan, el formulario se envía.
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
<label class="form-label">Archivo CSV *</label>
|
||||
<input type="file" name="csv" accept=".csv" class="form-control" required>
|
||||
</div>
|
||||
<p>Descarga la plantilla y llena las columnas: <code>vehiculo, identificador_fiscal, id_transportista</code>.</p>
|
||||
<p>Descarga la plantilla y llena las columnas: <code>contenedor, identificador_fiscal, id_transportista</code>.</p>
|
||||
<a href="/IMPORTADORES/public/downloads/transportes_masivo_template.csv" class="btn btn-outline-secondary mb-3">
|
||||
📥 Descargar plantilla
|
||||
</a><br>
|
||||
@@ -120,9 +120,8 @@ if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
@@ -149,3 +148,6 @@ if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user