Requerimientos sprint 2
This commit is contained in:
@@ -20,7 +20,6 @@
|
||||
$caat = $_POST['caat'];
|
||||
$usr_id = $_SESSION['usuario_id'];
|
||||
|
||||
// Validaciones básicas…
|
||||
// INSERT incluyendo id_usuario
|
||||
$sql = "INSERT INTO dbo.transportistas
|
||||
(clave_identificador, nombre, rfc, curp, domicilio, pais,
|
||||
@@ -87,18 +86,12 @@ function ciudades() {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function lista() {
|
||||
|
||||
function lista()
|
||||
{
|
||||
include __DIR__ . '/../../views/transportistas/lista.php';
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Descarga la plantilla CSV para carga masiva
|
||||
*/
|
||||
/** Descarga la plantilla CSV para carga masiva **/
|
||||
function template() {
|
||||
$file = __DIR__ . '/../../public/downloads/transportistas_template.csv';
|
||||
if (!file_exists($file)) {
|
||||
@@ -112,10 +105,7 @@ function template() {
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Procesa la carga masiva desde un CSV
|
||||
*/
|
||||
/** Procesa la carga masiva desde un CSV **/
|
||||
function importar() {
|
||||
// 1) Verificar sesión
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -162,23 +152,58 @@ function importar() {
|
||||
continue;
|
||||
}
|
||||
// mapear valores y trim
|
||||
list($clave,$nombre,$rfc,$curp,$tel,$caat,$pais,$estado,$ciudad,$dom) = array_map('trim', $row);
|
||||
list($clave,$nombre,$rfc,$curp,$tel,$caat,$pais_id,$estado_id,$ciudad_id,$dom) = array_map('trim', $row);
|
||||
|
||||
// validar obligatorios
|
||||
if ($clave==='' || $nombre==='' || $rfc==='' || $tel==='' || $caat===''
|
||||
|| $pais==='' || $estado==='' || $ciudad==='' || $dom==='') {
|
||||
|| $pais_id==='' || $estado_id==='' || $ciudad_id==='' || $dom==='') {
|
||||
$errors[] = "Fila $rowNum: faltan datos obligatorios.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5) Insertar en BD
|
||||
// Convertir IDs a nombres
|
||||
$pais_nombre = '';
|
||||
$estado_nombre = '';
|
||||
$ciudad_nombre = '';
|
||||
|
||||
// Consultar nombre del país
|
||||
$sql = "SELECT nombre FROM dbo.paises WHERE id_pais = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$pais_id]);
|
||||
if ($row_pais = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$pais_nombre = $row_pais['nombre'];
|
||||
} else {
|
||||
$errors[] = "Fila $rowNum: país con ID $pais_id no encontrado.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Consultar nombre del estado
|
||||
$sql = "SELECT nombre FROM dbo.estados WHERE id_estado = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$estado_id]);
|
||||
if ($row_estado = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$estado_nombre = $row_estado['nombre'];
|
||||
} else {
|
||||
$errors[] = "Fila $rowNum: estado con ID $estado_id no encontrado.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Consultar nombre de la ciudad
|
||||
$sql = "SELECT nombre FROM dbo.ciudades WHERE id_ciudad = ?";
|
||||
$stmt = sqlsrv_query($conn, $sql, [$ciudad_id]);
|
||||
if ($row_ciudad = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||
$ciudad_nombre = $row_ciudad['nombre'];
|
||||
} else {
|
||||
$errors[] = "Fila $rowNum: ciudad con ID $ciudad_id no encontrada.";
|
||||
continue;
|
||||
}
|
||||
|
||||
// 5) Insertar en BD con nombres
|
||||
$sql = "INSERT INTO dbo.transportistas
|
||||
(clave_identificador, nombre, rfc, curp, telefono, caat,
|
||||
pais, entidad_federativa, ciudad, domicilio, id_usuario)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$params = [
|
||||
$clave, $nombre, $rfc, $curp, $tel,
|
||||
$caat, $pais, $estado, $ciudad, $dom,
|
||||
$caat, $pais_nombre, $estado_nombre, $ciudad_nombre, $dom,
|
||||
$usr_id
|
||||
];
|
||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||
@@ -204,7 +229,6 @@ function bulk_upload() {
|
||||
include __DIR__ . '/../../views/transportistas/bulk_upload.php';
|
||||
}
|
||||
|
||||
|
||||
function ajax_lista() {
|
||||
// 1) Autorización
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -222,11 +246,11 @@ function ajax_lista() {
|
||||
$length = intval($_GET['length'] ?? 10);
|
||||
$search = $_GET['search']['value'] ?? '';
|
||||
|
||||
// Mapeo columnas
|
||||
$cols = ['id_transportista','clave_identificador','nombre','rfc','ciudad','creado_en'];
|
||||
// Mapeo columnas - ahora incluimos el nombre de la ciudad
|
||||
$cols = ['t.id_transportista','t.clave_identificador','t.nombre','t.rfc','c.nombre','t.creado_en'];
|
||||
$orderColIdx = intval($_GET['order'][0]['column'] ?? 5);
|
||||
$orderDir = strtoupper($_GET['order'][0]['dir'] ?? 'ASC') === 'DESC' ? 'DESC' : 'ASC';
|
||||
$orderCol = in_array($orderColIdx, range(0,5)) ? $cols[$orderColIdx] : 'creado_en';
|
||||
$orderCol = in_array($orderColIdx, range(0,5)) ? $cols[$orderColIdx] : 't.creado_en';
|
||||
|
||||
// 3) Total registros sin filtro
|
||||
$sqlTotal = "SELECT COUNT(*) AS total FROM dbo.transportistas WHERE id_usuario = ? AND activo = 1";
|
||||
@@ -234,23 +258,55 @@ function ajax_lista() {
|
||||
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
|
||||
$recordsTotal = (int)$row['total'];
|
||||
|
||||
// 4) Total registros con filtro
|
||||
$where = "id_usuario = ? AND activo = 1 ";
|
||||
// 4) Construir condiciones de filtro
|
||||
$where = "t.id_usuario = ? AND t.activo = 1 ";
|
||||
$params = [$usr];
|
||||
|
||||
if ($search !== '') {
|
||||
$where .= " AND (clave_identificador LIKE ? OR nombre LIKE ? OR rfc LIKE ? OR ciudad LIKE ?)";
|
||||
// Ahora buscamos en campos de transportista Y en el nombre de la ciudad
|
||||
$where .= " AND (
|
||||
t.clave_identificador LIKE ? OR
|
||||
t.nombre LIKE ? OR
|
||||
t.rfc LIKE ? OR
|
||||
t.curp LIKE ? OR
|
||||
t.telefono LIKE ? OR
|
||||
t.caat LIKE ? OR
|
||||
c.nombre LIKE ? OR
|
||||
p.nombre LIKE ? OR
|
||||
e.nombre LIKE ?
|
||||
)";
|
||||
$like = "%{$search}%";
|
||||
$params = array_merge($params, [$like, $like, $like, $like]);
|
||||
// Agregamos el parámetro para cada campo de búsqueda
|
||||
$params = array_merge($params, array_fill(0, 9, $like));
|
||||
}
|
||||
$sqlFiltered = "SELECT COUNT(*) AS total FROM dbo.transportistas WHERE $where";
|
||||
|
||||
// 5) Total registros filtrados (CON JOIN)
|
||||
$sqlFiltered = "
|
||||
SELECT COUNT(*) AS total
|
||||
FROM dbo.transportistas t
|
||||
LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad
|
||||
LEFT JOIN dbo.estados e ON c.estado_id = e.id_estado
|
||||
LEFT JOIN dbo.paises p ON e.pais_id = p.id_pais
|
||||
WHERE $where
|
||||
";
|
||||
$stmtF = sqlsrv_query($conn, $sqlFiltered, $params);
|
||||
$rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC);
|
||||
$recordsFiltered = (int)$rowF['total'];
|
||||
|
||||
// 5) Datos de la página
|
||||
// 6) Datos de la página con JOIN completo
|
||||
$sqlData = "
|
||||
SELECT id_transportista, clave_identificador, nombre, rfc, ciudad, creado_en
|
||||
FROM dbo.transportistas
|
||||
SELECT t.id_transportista,
|
||||
t.clave_identificador,
|
||||
t.nombre,
|
||||
t.rfc,
|
||||
COALESCE(c.nombre, 'Ciudad no encontrada') as ciudad_nombre,
|
||||
COALESCE(e.nombre, '') as estado_nombre,
|
||||
COALESCE(p.nombre, '') as pais_nombre,
|
||||
t.creado_en
|
||||
FROM dbo.transportistas t
|
||||
LEFT JOIN dbo.ciudades c ON t.ciudad = c.id_ciudad
|
||||
LEFT JOIN dbo.estados e ON c.estado_id = e.id_estado
|
||||
LEFT JOIN dbo.paises p ON e.pais_id = p.id_pais
|
||||
WHERE $where
|
||||
ORDER BY $orderCol $orderDir
|
||||
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY
|
||||
@@ -267,14 +323,14 @@ function ajax_lista() {
|
||||
$r['clave_identificador'],
|
||||
$r['nombre'],
|
||||
$r['rfc'],
|
||||
$r['ciudad'],
|
||||
$r['ciudad_nombre'], // Ahora muestra el nombre real de la ciudad
|
||||
$r['creado_en'] instanceof DateTime
|
||||
? $r['creado_en']->format('Y-m-d H:i')
|
||||
: ''
|
||||
];
|
||||
}
|
||||
|
||||
// 6) Devolver JSON
|
||||
// 7) Devolver JSON
|
||||
header('Content-Type: application/json; charset=UTF-8');
|
||||
echo json_encode([
|
||||
"draw" => $draw,
|
||||
@@ -320,22 +376,14 @@ function editar() {
|
||||
|
||||
// --- Estados para el país actual ---
|
||||
$estados = [];
|
||||
$rs = sqlsrv_query(
|
||||
$conn,
|
||||
"SELECT id_estado, nombre FROM dbo.estados WHERE pais_id = ? ORDER BY nombre",
|
||||
[$t['pais']]
|
||||
);
|
||||
$rs = sqlsrv_query($conn, "SELECT id_estado, nombre FROM dbo.estados WHERE pais_id = ? ORDER BY nombre", [$t['pais']]);
|
||||
while ($r = sqlsrv_fetch_array($rs, SQLSRV_FETCH_ASSOC)) {
|
||||
$estados[] = $r;
|
||||
}
|
||||
|
||||
// --- Ciudades para el estado actual ---
|
||||
$ciudades = [];
|
||||
$rs = sqlsrv_query(
|
||||
$conn,
|
||||
"SELECT id_ciudad, nombre FROM dbo.ciudades WHERE estado_id = ? ORDER BY nombre",
|
||||
[$t['entidad_federativa']]
|
||||
);
|
||||
$rs = sqlsrv_query($conn, "SELECT id_ciudad, nombre FROM dbo.ciudades WHERE estado_id = ? ORDER BY nombre", [$t['entidad_federativa']]);
|
||||
while ($r = sqlsrv_fetch_array($rs, SQLSRV_FETCH_ASSOC)) {
|
||||
$ciudades[] = $r;
|
||||
}
|
||||
@@ -344,9 +392,7 @@ function editar() {
|
||||
include __DIR__ . '/../../views/transportistas/editar.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Procesa el POST de actualización
|
||||
*/
|
||||
/** Procesa el POST de actualización **/
|
||||
function actualizar() {
|
||||
session_start();
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -415,9 +461,6 @@ function actualizar() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function eliminar() {
|
||||
session_start();
|
||||
if (!($_SESSION['usuario_id'] ?? false)) {
|
||||
@@ -435,17 +478,15 @@ function eliminar() {
|
||||
// Verificar que el transportista exista y pertenezca al usuario
|
||||
$sqlChk = "SELECT COUNT(*) AS cnt
|
||||
FROM dbo.transportistas
|
||||
WHERE id_transportista = ? AND id_usuario = ? AND activo = 1";
|
||||
WHERE id_transportista = ? AND id_usuario = ?";
|
||||
$stmtChk = sqlsrv_query($conn, $sqlChk, [$id, $usr]);
|
||||
$rowChk = sqlsrv_fetch_array($stmtChk, SQLSRV_FETCH_ASSOC);
|
||||
if ($rowChk['cnt'] == 0) {
|
||||
die("❌ Transportista no encontrado o ya eliminado.");
|
||||
die("❌ Transportista no encontrado o no autorizado.");
|
||||
}
|
||||
|
||||
// Soft-delete
|
||||
$sqlDel = "UPDATE dbo.transportistas
|
||||
SET activo = 0
|
||||
WHERE id_transportista = ?";
|
||||
// ELIMINACIÓN REAL - DELETE en lugar de UPDATE
|
||||
$sqlDel = "DELETE FROM dbo.transportistas WHERE id_transportista = ?";
|
||||
$stmtDel = sqlsrv_query($conn, $sqlDel, [$id]);
|
||||
if ($stmtDel === false) {
|
||||
die("❌ Error al eliminar: " . print_r(sqlsrv_errors(), true));
|
||||
|
||||
@@ -123,7 +123,6 @@ $color2 = explode(',', $config['colores_primarios'] ?? '#003366,#0055A5')
|
||||
<!-- Contenedor del formulario -->
|
||||
<div class="container card-form">
|
||||
|
||||
|
||||
<form action="/IMPORTADORES/registro/enviar" method="POST" enctype="multipart/form-data" id="formRegistro">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
<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>
|
||||
|
||||
<!-- SweetAlert2 -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
@@ -69,16 +72,40 @@
|
||||
|
||||
<div class="content">
|
||||
<h4 class="mb-4">🚛 Alta de Transportista</h4>
|
||||
<form action="/IMPORTADORES/transportistas/guardar" method="POST" class="card p-4 shadow-sm">
|
||||
<form action="/IMPORTADORES/transportistas/guardar" method="POST" class="card p-4 shadow-sm" id="formAltaTransportista">
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4"><input name="clave" class="form-control" placeholder="Clave" required></div>
|
||||
<div class="col-md-4"><input name="nombre" class="form-control" placeholder="Nombre completo" required></div>
|
||||
<div class="col-md-4"><input name="rfc" class="form-control" placeholder="RFC" required></div>
|
||||
<div class="col-md-4"><input name="curp" class="form-control" placeholder="CURP"></div>
|
||||
<div class="col-md-4"><input name="telefono" class="form-control" placeholder="Teléfono" required></div>
|
||||
<div class="col-md-4"><input name="caat" class="form-control" placeholder="Código CAAT" required></div>
|
||||
<div class="col-md-4">
|
||||
<label for="clave" class="form-label">Clave *</label>
|
||||
<input name="clave" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="nombre" class="form-label">Nombre *</label>
|
||||
<input name="nombre" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="rfc" class="form-label">RFC *</label>
|
||||
<input name="rfc" class="form-control" maxlength="13" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="curp" class="form-label">CURP *</label>
|
||||
<input name="curp" class="form-control" maxlength="18" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="telefono" class="form-label">Teléfono *</label>
|
||||
<input name="telefono" class="form-control" maxlength="11" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="caat" class="form-label">Código CAAT *</label>
|
||||
<input name="caat" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="pais" class="form-label">País *</label>
|
||||
<select id="pais" name="pais" class="form-select" required>
|
||||
<option value="">Selecciona país</option>
|
||||
<?php foreach($paises as $p): ?>
|
||||
@@ -90,19 +117,25 @@
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="entidad" class="form-label">Entidad *</label>
|
||||
<select id="estado" name="entidad" class="form-select" required disabled>
|
||||
<option value="">Primero país…</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="ciudad" class="form-label">Ciudad *</label>
|
||||
<select id="ciudad" name="ciudad" class="form-select" required disabled>
|
||||
<option value="">Primero estado…</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8"><input name="domicilio" class="form-control" placeholder="Domicilio completo" required></div>
|
||||
<div class="col-md-8">
|
||||
<label for="domicilio" class="form-label">Domicilio *</label>
|
||||
<input name="domicilio" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-end mt-4">
|
||||
<button class="btn btn-success px-4">Guardar Transportista</button>
|
||||
</div>
|
||||
@@ -110,6 +143,49 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.getElementById('formAltaTransportista').addEventListener('submit', function(e) {
|
||||
const rfcInput = document.querySelector('input[name="rfc"]');
|
||||
const curpInput = document.querySelector('input[name="curp"]');
|
||||
const telefonoInput = document.querySelector('input[name="telefono"]');
|
||||
|
||||
const rfc = rfcInput.value.trim().toUpperCase();
|
||||
const curp = curpInput.value.trim();
|
||||
const telefono = telefonoInput.value.trim();
|
||||
|
||||
// Expresiones regulares
|
||||
const curpRegex = /^[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}$/;
|
||||
const rfcRegex = /^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/;
|
||||
const telefonoRegex = /^\d{3}\s\d{7}$/;
|
||||
|
||||
// Validación de correo
|
||||
if (!curpRegex.test(curp)) {
|
||||
e.preventDefault();
|
||||
Swal.fire("CURP inválido", "No tiene el formato correcto.", "error");
|
||||
emailInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Validación de RFC
|
||||
if (!rfcRegex.test(rfc)) {
|
||||
e.preventDefault();
|
||||
Swal.fire("RFC inválido", "El RFC debe tener 12 o 13 caracteres con el formato correcto (ej. ABC123456XYZ).", "error");
|
||||
rfcInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Validación de teléfono
|
||||
if (!telefonoRegex.test(telefono)) {
|
||||
e.preventDefault();
|
||||
Swal.fire("Teléfono inválido", "Debe tener 10 dígitos en el formato: 3 dígitos (LADA), espacio, y 7 dígitos. Ejemplo: 123 4567890", "error");
|
||||
phoneInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
// Si no hay errores, enviar el formulario
|
||||
this.submit(); // Esto sí lo envía manualmente
|
||||
});
|
||||
|
||||
// Active inputs entidad y ciudad
|
||||
// 1) Cuando elige país → cargo estados
|
||||
document.getElementById('pais').addEventListener('change', e => {
|
||||
const pid = e.target.value;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<!-- views/transportistas/lista.php -->
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
|
||||
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>🚚 Mis Transportistas</title>
|
||||
@@ -80,13 +79,7 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<body>
|
||||
<?php include __DIR__ . '/../partials/sidebar_importador.php'; ?>
|
||||
|
||||
<div class="content">
|
||||
<br>
|
||||
@@ -158,7 +151,7 @@
|
||||
function confirmDelete(id) {
|
||||
Swal.fire({
|
||||
title: '¿Eliminar transportista?',
|
||||
text: 'Esto sólo lo desactivará; no se podrá volver a usar.',
|
||||
text: 'Esto sólo lo eliminara completamente y no se podrá volver a usar.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, eliminar',
|
||||
|
||||
Reference in New Issue
Block a user