Productos frecuenes
This commit is contained in:
@@ -5,8 +5,61 @@ require_once __DIR__ . '/../../config/database.php';
|
|||||||
require_once __DIR__ . '/../../vendor/autoload.php';
|
require_once __DIR__ . '/../../vendor/autoload.php';
|
||||||
// 2) Carga nuestro helper de entorno y dispara la carga de .env
|
// 2) Carga nuestro helper de entorno y dispara la carga de .env
|
||||||
require_once __DIR__ . '/../helpers/env.php';
|
require_once __DIR__ . '/../helpers/env.php';
|
||||||
|
|
||||||
loadEnv();
|
loadEnv();
|
||||||
|
|
||||||
|
/** Obtiene (y cachea en sesión) el JWT de la API usando las credenciales de $_ENV **/
|
||||||
|
/** Obtiene (y cachea) el JWT de la API usando credenciales de $_ENV
|
||||||
|
* Gestiona expiración: asume 1 hora de vida y renueva si ha pasado. **/
|
||||||
|
function getApiToken(): ?string
|
||||||
|
{
|
||||||
|
// Duración en segundos del token (60 min)
|
||||||
|
$ttl = 3600;
|
||||||
|
|
||||||
|
// 1) Si ya tenemos token y no ha expirado, lo devolvemos
|
||||||
|
if (!empty($_SESSION['api_token']) && !empty($_SESSION['api_token_time'])) {
|
||||||
|
$age = time() - $_SESSION['api_token_time'];
|
||||||
|
if ($age < $ttl) {
|
||||||
|
error_log("[getApiToken] Usando token en caché (edad: {$age}s)");
|
||||||
|
return $_SESSION['api_token'];
|
||||||
|
}
|
||||||
|
error_log("[getApiToken] Token expirado (edad: {$age}s), obteniendo uno nuevo");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Sí o sí hacemos login en la API
|
||||||
|
$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");
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
|
||||||
|
CURLOPT_POSTFIELDS => $body,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_TIMEOUT => 5,
|
||||||
|
]);
|
||||||
|
$resp = curl_exec($ch);
|
||||||
|
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
error_log("[getApiToken] HTTP $http");
|
||||||
|
|
||||||
|
if ($http === 200 && ($data = json_decode($resp, true)) && !empty($data['token'])) {
|
||||||
|
// 3) Guardamos token y tiempo actual
|
||||||
|
$_SESSION['api_token'] = $data['token'];
|
||||||
|
$_SESSION['api_token_time'] = time();
|
||||||
|
return $data['token'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) Si no se pudo obtener, devolvemos null
|
||||||
|
error_log('[getApiToken] No se pudo obtener token de la API');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/** GET /IMPORTADORES/productos_frecuentes
|
/** GET /IMPORTADORES/productos_frecuentes
|
||||||
* Muestra el listado **/
|
* Muestra el listado **/
|
||||||
function index()
|
function index()
|
||||||
@@ -14,6 +67,90 @@ function index()
|
|||||||
lista();
|
lista();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lista()
|
||||||
|
{
|
||||||
|
if (empty($_SESSION['usuario_id'])) {
|
||||||
|
header('Location: /IMPORTADORES/login');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn = getConnection();
|
||||||
|
|
||||||
|
// === Obtener proveedores desde API ===
|
||||||
|
$token = getApiToken();
|
||||||
|
$proveedoresApi = [];
|
||||||
|
|
||||||
|
if ($token) {
|
||||||
|
$apiBase = rtrim($_ENV['API_URL'] ?? '', '/');
|
||||||
|
$url = $apiBase . '/proveedores';
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt_array($ch, [
|
||||||
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'],
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
CURLOPT_TIMEOUT => 5,
|
||||||
|
]);
|
||||||
|
$resp = curl_exec($ch);
|
||||||
|
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($status === 200 && ($json = json_decode($resp, true)) && is_array($json)) {
|
||||||
|
foreach ($json as $p) {
|
||||||
|
$clave = $p['Clave'] ?? '';
|
||||||
|
$nombre = $p['Nombre'] ?? '';
|
||||||
|
if ($clave) {
|
||||||
|
$proveedoresApi[$clave] = $nombre;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Consulta de productos frecuentes ===
|
||||||
|
$sql = "SELECT
|
||||||
|
pf.id_producto_frecuente,
|
||||||
|
pf.sinonimo,
|
||||||
|
pf.fraccion,
|
||||||
|
pf.nico,
|
||||||
|
pf.numero_parte,
|
||||||
|
pf.proveedor AS proveedor_guardado,
|
||||||
|
u.descripcion AS unidad_de_medida,
|
||||||
|
por.nombre AS pais_origen_destino,
|
||||||
|
pc.nombre AS pais_comprador_vendedor,
|
||||||
|
pf.uso_mercancia,
|
||||||
|
pf.estado_mercancia,
|
||||||
|
pf.preferencia,
|
||||||
|
pf.frecuencia_uso
|
||||||
|
FROM dbo.productos_frecuentes pf
|
||||||
|
LEFT JOIN dbo.unidades_medida_apendice7 u
|
||||||
|
ON pf.umc_id = u.id
|
||||||
|
LEFT JOIN dbo.paises por
|
||||||
|
ON pf.pais_origen_destino = por.nombre
|
||||||
|
LEFT JOIN dbo.paises pc
|
||||||
|
ON pf.pais_comprador_vendedor = pc.nombre
|
||||||
|
WHERE pf.id_importador = ?
|
||||||
|
AND pf.status = 1
|
||||||
|
ORDER BY pf.fecha_alta DESC
|
||||||
|
";
|
||||||
|
$stmt = sqlsrv_query($conn, $sql, [$_SESSION['usuario_id']]);
|
||||||
|
|
||||||
|
if ($stmt === false) {
|
||||||
|
echo '<pre>', print_r(sqlsrv_errors(), true), '</pre>';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Construir arreglo de productos con nombre de proveedor ===
|
||||||
|
$productos = [];
|
||||||
|
|
||||||
|
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||||
|
$clave = $row['proveedor_guardado'];
|
||||||
|
$row['nombre_proveedor'] = $proveedoresApi[$clave] ?? 'N/D';
|
||||||
|
$productos[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
// === Cargar la vista con productos y nombres de proveedor ===
|
||||||
|
include __DIR__ . '/../../views/productos_frecuentes/lista.php';
|
||||||
|
}
|
||||||
|
|
||||||
function ajax_paises()
|
function ajax_paises()
|
||||||
{
|
{
|
||||||
// Sólo importadores pueden usarlo
|
// Sólo importadores pueden usarlo
|
||||||
@@ -58,7 +195,7 @@ function ajax_proveedores()
|
|||||||
|
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_HTTPHEADER => ["Authorization: $token", 'Accept: application/json'],
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'],
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_TIMEOUT => 5,
|
CURLOPT_TIMEOUT => 5,
|
||||||
]);
|
]);
|
||||||
@@ -84,14 +221,30 @@ function ajax_proveedores()
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
function lista()
|
function ajax_unidades()
|
||||||
{
|
{
|
||||||
if (empty($_SESSION['usuario_id'])) {
|
// Sólo importadores pueden usarlo
|
||||||
header('Location: /IMPORTADORES/login');
|
if (empty($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador') {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(['results' => []]);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
include __DIR__ . '/../../views/productos_frecuentes/lista.php';
|
$conn = getConnection();
|
||||||
|
|
||||||
|
$sql = "SELECT id, descripcion FROM dbo.unidades_medida_apendice7 ORDER BY descripcion";
|
||||||
|
$stmt = sqlsrv_query($conn, $sql);
|
||||||
|
|
||||||
|
$out = ['results' => []];
|
||||||
|
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
||||||
|
$out['results'][] = [
|
||||||
|
'id' => $row['id'],
|
||||||
|
'text' => $row['descripcion']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($out);
|
||||||
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** GET /IMPORTADORES/productos_frecuentes/alta
|
/** GET /IMPORTADORES/productos_frecuentes/alta
|
||||||
@@ -117,38 +270,118 @@ function guardar()
|
|||||||
|
|
||||||
$conn = getConnection();
|
$conn = getConnection();
|
||||||
|
|
||||||
|
$errores = [];
|
||||||
|
$id_importador = $_SESSION['usuario_id'];
|
||||||
|
|
||||||
// Recoger y sanear
|
// Recoger y sanear
|
||||||
$sinonimo = trim($_POST['sinonimo'] ?? '');
|
$sinonimo = trim($_POST['sinonimo'] ?? '');
|
||||||
$fraccion = trim($_POST['fraccion'] ?? '');
|
$fraccion = trim($_POST['fraccion'] ?? '');
|
||||||
$nico = trim($_POST['nico'] ?? '');
|
$nico = trim($_POST['nico'] ?? '');
|
||||||
$numero_parte = trim($_POST['numero_parte'] ?? null);
|
$numero_parte = trim($_POST['numero_parte'] ?? '');
|
||||||
$descripcion = trim($_POST['descripcion'] ?? null);
|
$descripcion = trim($_POST['descripcion'] ?? '');
|
||||||
$umc_id = intval($_POST['umc_id'] ?? 0);
|
$umc_id = intval($_POST['umc_id'] ?? 0);
|
||||||
$pais_origen_destino = trim($_POST['pais_origen_destino'] ?? null);
|
$pais_origen_destino = trim($_POST['pais_origen_destino'] ?? '');
|
||||||
$pais_comprador_vendedor = trim($_POST['pais_comprador_vendedor'] ?? null);
|
$pais_comprador_vendedor = trim($_POST['pais_comprador_vendedor'] ?? '');
|
||||||
$uso_mercancia = trim($_POST['uso_mercancia'] ?? null);
|
$uso_mercancia = trim($_POST['uso_mercancia'] ?? '');
|
||||||
$estado_mercancia = trim($_POST['estado_mercancia'] ?? null);
|
$estado_mercancia = trim($_POST['estado_mercancia'] ?? '');
|
||||||
$vinculacion = trim($_POST['vinculacion'] ?? null);
|
$vinculacion = trim($_POST['vinculacion'] ?? '');
|
||||||
$observaciones = trim($_POST['observaciones'] ?? null);
|
$observaciones = trim($_POST['observaciones'] ?? '');
|
||||||
$preferencia = trim($_POST['preferencia'] ?? null);
|
$preferencia = trim($_POST['preferencia'] ?? '');
|
||||||
$criterio_preferencia = trim($_POST['criterio_preferencia'] ?? null);
|
$criterio_preferencia = trim($_POST['criterio_preferencia'] ?? '');
|
||||||
$uso_producto = trim($_POST['uso_producto'] ?? null);
|
$uso_producto = trim($_POST['uso_producto'] ?? '');
|
||||||
$descripcion_producto = trim($_POST['descripcion_producto'] ?? null);
|
$descripcion_producto = trim($_POST['descripcion_producto'] ?? '');
|
||||||
$certificado_origen = isset($_POST['certificado_origen']) ? 1 : 0;
|
$certificado_origen = trim($_POST['certificado_origen'] ?? '');
|
||||||
$tipo_mercancia = trim($_POST['tipo_mercancia'] ?? null);
|
$tipo_mercancia = trim($_POST['tipo_mercancia'] ?? '');
|
||||||
$documento_en_original = isset($_POST['documento_en_original']) ? 1 : 0;
|
$documento_en_original = isset($_POST['documento_en_original']) ? 1 : 0;
|
||||||
$proveedor = trim($_POST['proveedor'] ?? null);
|
$proveedor = trim($_POST['proveedor'] ?? '');
|
||||||
$id_importador = intval($_SESSION['usuario_id']);
|
$status = intval($_POST['status'] ?? 1);
|
||||||
$status = 1;
|
|
||||||
$frecuencia_uso = intval($_POST['frecuencia_uso'] ?? 1);
|
$frecuencia_uso = intval($_POST['frecuencia_uso'] ?? 1);
|
||||||
|
|
||||||
// Validación mínima
|
// Validación de campos obligatorios (según tu formulario)
|
||||||
if ($sinonimo === '' || $fraccion === '' || $nico === '' || $umc_id <= 0) {
|
if ($sinonimo === '') {
|
||||||
$_SESSION['flash_error'] = 'Sinónimo, Fracción, NICO y Unidad de Medida son obligatorios.';
|
$errores[] = 'El sinónimo es obligatorio';
|
||||||
|
}
|
||||||
|
if ($fraccion === '') {
|
||||||
|
$errores[] = 'La fracción es obligatoria';
|
||||||
|
}
|
||||||
|
if ($nico === '') {
|
||||||
|
$errores[] = 'El NICO es obligatorio';
|
||||||
|
}
|
||||||
|
if ($numero_parte === '') {
|
||||||
|
$errores[] = 'El número de parte es obligatorio';
|
||||||
|
}
|
||||||
|
if ($pais_origen_destino === '') {
|
||||||
|
$errores[] = 'El país de origen/destino es obligatorio';
|
||||||
|
}
|
||||||
|
if ($pais_comprador_vendedor === '') {
|
||||||
|
$errores[] = 'El país comprador/vendedor es obligatorio';
|
||||||
|
}
|
||||||
|
if ($umc_id <= 0) {
|
||||||
|
$errores[] = 'La unidad de medida es obligatoria';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar que NICO solo contenga números
|
||||||
|
if (!preg_match('/^[0-9]+$/', $nico)) {
|
||||||
|
$errores[] = 'El NICO solo puede contener números';
|
||||||
|
}
|
||||||
|
|
||||||
|
// **SOLUCIÓN PRINCIPAL: Convertir IDs de países a nombres**
|
||||||
|
$pais_origen_nombre = null;
|
||||||
|
$pais_comprador_nombre = null;
|
||||||
|
|
||||||
|
if (!empty($pais_origen_destino)) {
|
||||||
|
$sql_pais = "SELECT nombre FROM dbo.paises WHERE id_pais = ?";
|
||||||
|
$stmt_pais = sqlsrv_query($conn, $sql_pais, [intval($pais_origen_destino)]);
|
||||||
|
|
||||||
|
if ($stmt_pais && $row = sqlsrv_fetch_array($stmt_pais, SQLSRV_FETCH_ASSOC)) {
|
||||||
|
$pais_origen_nombre = $row['nombre'];
|
||||||
|
} else {
|
||||||
|
$errores[] = 'País de origen/destino no válido';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($pais_comprador_vendedor)) {
|
||||||
|
$sql_pais = "SELECT nombre FROM dbo.paises WHERE id_pais = ?";
|
||||||
|
$stmt_pais = sqlsrv_query($conn, $sql_pais, [intval($pais_comprador_vendedor)]);
|
||||||
|
|
||||||
|
if ($stmt_pais && $row = sqlsrv_fetch_array($stmt_pais, SQLSRV_FETCH_ASSOC)) {
|
||||||
|
$pais_comprador_nombre = $row['nombre'];
|
||||||
|
} else {
|
||||||
|
$errores[] = 'País comprador/vendedor no válido';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar que existe la unidad de medida
|
||||||
|
$sql_umc = "SELECT COUNT(*) as count FROM dbo.unidades_medida_apendice7 WHERE id = ?";
|
||||||
|
$stmt_umc = sqlsrv_query($conn, $sql_umc, [$umc_id]);
|
||||||
|
|
||||||
|
if ($stmt_umc && $row = sqlsrv_fetch_array($stmt_umc, SQLSRV_FETCH_ASSOC)) {
|
||||||
|
if ($row['count'] == 0) {
|
||||||
|
$errores[] = 'Unidad de medida no válida';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si hay errores, regresar
|
||||||
|
if (!empty($errores)) {
|
||||||
|
$_SESSION['flash_error'] = implode('. ', $errores);
|
||||||
header('Location: /IMPORTADORES/productos_frecuentes/alta');
|
header('Location: /IMPORTADORES/productos_frecuentes/alta');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convertir valores vacíos a NULL para campos opcionales
|
||||||
|
if ($numero_parte === '') $numero_parte = null;
|
||||||
|
if ($descripcion === '') $descripcion = null;
|
||||||
|
if ($uso_mercancia === '') $uso_mercancia = null;
|
||||||
|
if ($estado_mercancia === '') $estado_mercancia = null;
|
||||||
|
if ($vinculacion === '') $vinculacion = null;
|
||||||
|
if ($observaciones === '') $observaciones = null;
|
||||||
|
if ($preferencia === '') $preferencia = null;
|
||||||
|
if ($criterio_preferencia === '') $criterio_preferencia = null;
|
||||||
|
if ($uso_producto === '') $uso_producto = null;
|
||||||
|
if ($descripcion_producto === '') $descripcion_producto = null;
|
||||||
|
if ($tipo_mercancia === '') $tipo_mercancia = null;
|
||||||
|
if ($proveedor === '') $proveedor = null;
|
||||||
|
|
||||||
// INSERT
|
// INSERT
|
||||||
$sql = "INSERT INTO dbo.productos_frecuentes
|
$sql = "INSERT INTO dbo.productos_frecuentes
|
||||||
(sinonimo, fraccion, nico, numero_parte, descripcion, umc_id,
|
(sinonimo, fraccion, nico, numero_parte, descripcion, umc_id,
|
||||||
@@ -160,20 +393,26 @@ function guardar()
|
|||||||
";
|
";
|
||||||
$params = [
|
$params = [
|
||||||
$sinonimo, $fraccion, $nico, $numero_parte, $descripcion, $umc_id,
|
$sinonimo, $fraccion, $nico, $numero_parte, $descripcion, $umc_id,
|
||||||
$pais_origen_destino, $pais_comprador_vendedor, $uso_mercancia, $estado_mercancia, $vinculacion,
|
$pais_origen_nombre, $pais_comprador_nombre, $uso_mercancia, $estado_mercancia, $vinculacion,
|
||||||
$observaciones, $preferencia, $criterio_preferencia, $uso_producto, $descripcion_producto,
|
$observaciones, $preferencia, $criterio_preferencia, $uso_producto, $descripcion_producto,
|
||||||
$certificado_origen, $tipo_mercancia, $documento_en_original, $proveedor,
|
$certificado_origen, $tipo_mercancia, $documento_en_original, $proveedor,
|
||||||
$id_importador, $status, $frecuencia_uso
|
$id_importador, $status, $frecuencia_uso
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Para debug - remover en producción
|
||||||
|
error_log("Datos a insertar: " . print_r($params, true));
|
||||||
|
|
||||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||||
|
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
$_SESSION['flash_error'] = 'Error al guardar el producto frecuente.';
|
$errors = sqlsrv_errors();
|
||||||
|
error_log("Error en SQL: " . print_r($errors, true));
|
||||||
|
$_SESSION['flash_error'] = 'Error al guardar el producto.';
|
||||||
header('Location: /IMPORTADORES/productos_frecuentes/alta');
|
header('Location: /IMPORTADORES/productos_frecuentes/alta');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
$_SESSION['flash_success'] = 'Producto frecuente registrado correctamente.';
|
$_SESSION['flash_success'] = 'Producto registrado correctamente.';
|
||||||
header('Location: /IMPORTADORES/productos_frecuentes');
|
header('Location: /IMPORTADORES/productos_frecuentes');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -205,6 +444,17 @@ function editar()
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Recuperar IDs reales desde nombres de país
|
||||||
|
foreach (['pais_origen_destino', 'pais_comprador_vendedor'] as $campo) {
|
||||||
|
$nombre = $producto[$campo];
|
||||||
|
$stmtPais = sqlsrv_query($conn, "SELECT id_pais FROM dbo.paises WHERE nombre = ?", [$nombre]);
|
||||||
|
if ($stmtPais && ($row = sqlsrv_fetch_array($stmtPais, SQLSRV_FETCH_ASSOC))) {
|
||||||
|
$producto[$campo] = $row['id_pais'];
|
||||||
|
} else {
|
||||||
|
$producto[$campo] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
include __DIR__ . '/../../views/productos_frecuentes/editar.php';
|
include __DIR__ . '/../../views/productos_frecuentes/editar.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,29 +469,91 @@ function actualizar()
|
|||||||
|
|
||||||
$conn = getConnection();
|
$conn = getConnection();
|
||||||
|
|
||||||
|
$errores = [];
|
||||||
|
|
||||||
$id = intval($_POST['id_producto_frecuente'] ?? 0);
|
$id = intval($_POST['id_producto_frecuente'] ?? 0);
|
||||||
$sinonimo = trim($_POST['sinonimo'] ?? '');
|
$sinonimo = trim($_POST['sinonimo'] ?? '');
|
||||||
|
$fraccion = trim($_POST['fraccion'] ?? '');
|
||||||
|
$nico = trim($_POST['nico'] ?? '');
|
||||||
|
$numero_parte = trim($_POST['numero_parte'] ?? '');
|
||||||
|
$descripcion = trim($_POST['descripcion'] ?? '');
|
||||||
|
$umc_id = intval($_POST['umc_id'] ?? 0);
|
||||||
|
$pais_origen_destino = trim($_POST['pais_origen_destino'] ?? '');
|
||||||
|
$pais_comprador_vendedor = trim($_POST['pais_comprador_vendedor'] ?? '');
|
||||||
|
$uso_mercancia = trim($_POST['uso_mercancia'] ?? '');
|
||||||
|
$estado_mercancia = trim($_POST['estado_mercancia'] ?? '');
|
||||||
|
$vinculacion = trim($_POST['vinculacion'] ?? '');
|
||||||
|
$observaciones = trim($_POST['observaciones'] ?? '');
|
||||||
|
$preferencia = trim($_POST['preferencia'] ?? '');
|
||||||
|
$criterio_preferencia = trim($_POST['criterio_preferencia'] ?? '');
|
||||||
|
$uso_producto = trim($_POST['uso_producto'] ?? '');
|
||||||
|
$descripcion_producto = trim($_POST['descripcion_producto'] ?? '');
|
||||||
|
$certificado_origen = trim($_POST['certificado_origen'] ?? '');
|
||||||
|
$tipo_mercancia = trim($_POST['tipo_mercancia'] ?? '');
|
||||||
|
$documento_en_original = isset($_POST['documento_en_original']) ? 1 : 0;
|
||||||
|
$proveedor = trim($_POST['proveedor'] ?? '');
|
||||||
|
|
||||||
|
// Validar países
|
||||||
|
$pais_origen_nombre = null;
|
||||||
|
$pais_comprador_nombre = null;
|
||||||
|
|
||||||
|
if (!empty($pais_origen_destino)) {
|
||||||
|
$sql_pais = "SELECT nombre FROM dbo.paises WHERE id_pais = ?";
|
||||||
|
$stmt_pais = sqlsrv_query($conn, $sql_pais, [intval($pais_origen_destino)]);
|
||||||
|
if ($stmt_pais && ($row = sqlsrv_fetch_array($stmt_pais, SQLSRV_FETCH_ASSOC))) {
|
||||||
|
$pais_origen_nombre = $row['nombre'];
|
||||||
|
} else {
|
||||||
|
$errores[] = 'País de origen/destino no válido';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($pais_comprador_vendedor)) {
|
||||||
|
$sql_pais = "SELECT nombre FROM dbo.paises WHERE id_pais = ?";
|
||||||
|
$stmt_pais = sqlsrv_query($conn, $sql_pais, [intval($pais_comprador_vendedor)]);
|
||||||
|
if ($stmt_pais && ($row = sqlsrv_fetch_array($stmt_pais, SQLSRV_FETCH_ASSOC))) {
|
||||||
|
$pais_comprador_nombre = $row['nombre'];
|
||||||
|
} else {
|
||||||
|
$errores[] = 'País comprador/vendedor no válido';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validar unidad
|
||||||
|
$sql_umc = "SELECT COUNT(*) as count FROM dbo.unidades_medida_apendice7 WHERE id = ?";
|
||||||
|
$stmt_umc = sqlsrv_query($conn, $sql_umc, [$umc_id]);
|
||||||
|
if (!$stmt_umc || ($row = sqlsrv_fetch_array($stmt_umc, SQLSRV_FETCH_ASSOC))['count'] == 0) {
|
||||||
|
$errores[] = 'Unidad de medida no válida';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si hay errores
|
||||||
|
if (!empty($errores)) {
|
||||||
|
$_SESSION['flash_error'] = implode('. ', $errores);
|
||||||
|
header("Location: /IMPORTADORES/productos_frecuentes/editar?id=$id");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UPDATE
|
||||||
$sql = "UPDATE dbo.productos_frecuentes SET
|
$sql = "UPDATE dbo.productos_frecuentes SET
|
||||||
sinonimo = ?, fraccion = ?, nico = ?, numero_parte = ?, descripcion = ?, umc_id = ?,
|
sinonimo = ?, fraccion = ?, nico = ?, numero_parte = ?, descripcion = ?,
|
||||||
pais_origen_destino = ?, pais_comprador_vendedor = ?, uso_mercancia = ?, estado_mercancia = ?, vinculacion = ?,
|
umc_id = ?, pais_origen_destino = ?, pais_comprador_vendedor = ?,
|
||||||
observaciones = ?, preferencia = ?, criterio_preferencia = ?, uso_producto = ?, descripcion_producto = ?,
|
uso_mercancia = ?, estado_mercancia = ?, vinculacion = ?, observaciones = ?,
|
||||||
|
preferencia = ?, criterio_preferencia = ?, uso_producto = ?, descripcion_producto = ?,
|
||||||
certificado_origen = ?, tipo_mercancia = ?, documento_en_original = ?, proveedor = ?
|
certificado_origen = ?, tipo_mercancia = ?, documento_en_original = ?, proveedor = ?
|
||||||
WHERE id_producto_frecuente = ?
|
WHERE id_producto_frecuente = ?
|
||||||
";
|
";
|
||||||
$params = [
|
$params = [
|
||||||
$sinonimo, $fraccion, $nico, $numero_parte, $descripcion, $umc_id,
|
$sinonimo, $fraccion, $nico, $numero_parte, $descripcion, $umc_id,
|
||||||
$pais_origen_destino, $pais_comprador_vendedor, $uso_mercancia, $estado_mercancia, $vinculacion,
|
$pais_origen_nombre, $pais_comprador_nombre, $uso_mercancia, $estado_mercancia, $vinculacion,
|
||||||
$observaciones, $preferencia, $criterio_preferencia, $uso_producto, $descripcion_producto,
|
$observaciones, $preferencia, $criterio_preferencia, $uso_producto, $descripcion_producto,
|
||||||
$certificado_origen, $tipo_mercancia, $documento_en_original, $proveedor, $id
|
$certificado_origen, $tipo_mercancia, $documento_en_original, $proveedor, $id
|
||||||
];
|
];
|
||||||
$stmt = sqlsrv_query($conn, $sql, $params);
|
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||||
|
|
||||||
if ($stmt === false) {
|
if ($stmt === false) {
|
||||||
$_SESSION['flash_error'] = 'Error al actualizar el producto frecuente.';
|
$_SESSION['flash_error'] = 'Error al actualizar el producto.';
|
||||||
} else {
|
} else {
|
||||||
$_SESSION['flash_success'] = 'Producto frecuente actualizado correctamente.';
|
$_SESSION['flash_success'] = 'Producto actualizado correctamente.';
|
||||||
}
|
}
|
||||||
|
|
||||||
header('Location: /IMPORTADORES/productos_frecuentes');
|
header('Location: /IMPORTADORES/productos_frecuentes');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -258,32 +570,6 @@ function importacion_csv()
|
|||||||
include __DIR__ . '/../../views/productos_frecuentes/importacion_csv.php';
|
include __DIR__ . '/../../views/productos_frecuentes/importacion_csv.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
function ajax_unidades()
|
|
||||||
{
|
|
||||||
// Sólo importadores pueden usarlo
|
|
||||||
if (empty($_SESSION['usuario_id']) || $_SESSION['tipo_usuario'] !== 'importador') {
|
|
||||||
http_response_code(401);
|
|
||||||
echo json_encode(['results' => []]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$conn = getConnection();
|
|
||||||
|
|
||||||
$sql = "SELECT id, descripcion FROM dbo.unidades_medida_apendice7 ORDER BY descripcion";
|
|
||||||
$stmt = sqlsrv_query($conn, $sql);
|
|
||||||
|
|
||||||
$out = ['results' => []];
|
|
||||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
|
|
||||||
$out['results'][] = [
|
|
||||||
'id' => $row['id'],
|
|
||||||
'text' => $row['descripcion']
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode($out);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** POST /IMPORTADORES/productos_frecuentes/procesar_csv
|
/** POST /IMPORTADORES/productos_frecuentes/procesar_csv
|
||||||
* Procesa el upload y la inserción de CSV **/
|
* Procesa el upload y la inserción de CSV **/
|
||||||
function procesar_csv()
|
function procesar_csv()
|
||||||
@@ -321,3 +607,33 @@ function procesar_csv()
|
|||||||
header('Location: /IMPORTADORES/productos_frecuentes');
|
header('Location: /IMPORTADORES/productos_frecuentes');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function eliminar()
|
||||||
|
{
|
||||||
|
if (empty($_SESSION['usuario_id'])) {
|
||||||
|
header('Location: /IMPORTADORES/login');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = $_GET['id'] ?? null;
|
||||||
|
|
||||||
|
if (!$id || !is_numeric($id)) {
|
||||||
|
http_response_code(400);
|
||||||
|
echo "ID inválido";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn = getConnection();
|
||||||
|
|
||||||
|
$sql = "UPDATE productos_frecuentes SET status = 0 WHERE id_producto_frecuente = ? AND id_importador = ?";
|
||||||
|
$params = [$id, $_SESSION['usuario_id']];
|
||||||
|
$stmt = sqlsrv_query($conn, $sql, $params);
|
||||||
|
|
||||||
|
if ($stmt === false) {
|
||||||
|
echo '<pre>', print_r(sqlsrv_errors(), true), '</pre>';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Location: /IMPORTADORES/productos_frecuentes?deleted=ok');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
@@ -931,7 +931,7 @@ function generarPedimentoDesdeSolicitud($conn, $id, $usuarioId, $token)
|
|||||||
$ch = curl_init($urlPed);
|
$ch = curl_init($urlPed);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||||
CURLOPT_HTTPHEADER => ["Authorization: $token", 'Content-Type: application/json'],
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Content-Type: application/json'],
|
||||||
CURLOPT_POSTFIELDS => $jsonPayload,
|
CURLOPT_POSTFIELDS => $jsonPayload,
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_TIMEOUT => 10,
|
CURLOPT_TIMEOUT => 10,
|
||||||
@@ -1025,7 +1025,7 @@ function ajax_lista()
|
|||||||
// 4) Ejecutamos cURL
|
// 4) Ejecutamos cURL
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_HTTPHEADER => ["Authorization: $token", 'Accept: application/json'],
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'],
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_TIMEOUT => 5,
|
CURLOPT_TIMEOUT => 5,
|
||||||
]);
|
]);
|
||||||
@@ -1332,7 +1332,7 @@ function update_status()
|
|||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_CUSTOMREQUEST => 'POST',
|
CURLOPT_CUSTOMREQUEST => 'POST',
|
||||||
CURLOPT_HTTPHEADER => [
|
CURLOPT_HTTPHEADER => [
|
||||||
"Authorization: $token",
|
"Authorization: Bearer $token",
|
||||||
'Content-Type: application/json'
|
'Content-Type: application/json'
|
||||||
],
|
],
|
||||||
CURLOPT_POSTFIELDS => $jsonPayload,
|
CURLOPT_POSTFIELDS => $jsonPayload,
|
||||||
@@ -1450,7 +1450,7 @@ function obtenerInfoStatus($status) {
|
|||||||
$statusMap = [
|
$statusMap = [
|
||||||
1 => ['emoji' => '🔄', 'descripcion' => 'En proceso', 'color' => '#17a2b8'],
|
1 => ['emoji' => '🔄', 'descripcion' => 'En proceso', 'color' => '#17a2b8'],
|
||||||
2 => ['emoji' => '📋', 'descripcion' => 'Solicitar importación', 'color' => '#ffc107'],
|
2 => ['emoji' => '📋', 'descripcion' => 'Solicitar importación', 'color' => '#ffc107'],
|
||||||
3 => ['emoji' => '🏢', 'descripcion' => 'Con agencia aduana', 'color' => '#6f42c1'],
|
3 => ['emoji' => '🏢', 'descripcion' => 'Con agencia aduanal', 'color' => '#6f42c1'],
|
||||||
4 => ['emoji' => '💳', 'descripcion' => 'En proceso de pago', 'color' => '#fd7e14'],
|
4 => ['emoji' => '💳', 'descripcion' => 'En proceso de pago', 'color' => '#fd7e14'],
|
||||||
5 => ['emoji' => '✅', 'descripcion' => 'Pedimento generado', 'color' => '#28a745'],
|
5 => ['emoji' => '✅', 'descripcion' => 'Pedimento generado', 'color' => '#28a745'],
|
||||||
6 => ['emoji' => '📦', 'descripcion' => 'En tránsito', 'color' => '#007bff'],
|
6 => ['emoji' => '📦', 'descripcion' => 'En tránsito', 'color' => '#007bff'],
|
||||||
@@ -1703,7 +1703,7 @@ function obtenerProveedorPorClave($clave) {
|
|||||||
// Ejecutar cURL para obtener todos los proveedores
|
// Ejecutar cURL para obtener todos los proveedores
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
curl_setopt_array($ch, [
|
curl_setopt_array($ch, [
|
||||||
CURLOPT_HTTPHEADER => ["Authorization: $token", 'Accept: application/json'],
|
CURLOPT_HTTPHEADER => ["Authorization: Bearer $token", 'Accept: application/json'],
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_TIMEOUT => 10,
|
CURLOPT_TIMEOUT => 10,
|
||||||
]);
|
]);
|
||||||
|
|||||||
11
productos_frecuentes.txt
Normal file
11
productos_frecuentes.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
-- 1. Elimina la restricción DEFAULT
|
||||||
|
ALTER TABLE [Importaciones_HC].[dbo].[productos_frecuentes]
|
||||||
|
DROP CONSTRAINT [DF__productos__certi__3EDC53F0];
|
||||||
|
|
||||||
|
-- 2. Modifica el tipo de dato
|
||||||
|
ALTER TABLE [Importaciones_HC].[dbo].[productos_frecuentes]
|
||||||
|
ALTER COLUMN [certificado_origen] NVARCHAR(100);
|
||||||
|
|
||||||
|
-- 3. (Opcional) Si quieres volver a agregar un valor por defecto
|
||||||
|
ALTER TABLE [Importaciones_HC].[dbo].[productos_frecuentes]
|
||||||
|
ADD CONSTRAINT DF_productos_certificado_origen DEFAULT '' FOR [certificado_origen];
|
||||||
@@ -319,8 +319,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!soloNumerosRegex.test(numero_licencia)) {
|
if (!soloNumerosRegex.test(numero_licencia)) {
|
||||||
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545'
|
Swal.fire({ icon: 'error', title: 'Número de Licencia inválido', text: 'El número de licencia solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||||
});
|
|
||||||
document.getElementById('numero_licencia').focus();
|
document.getElementById('numero_licencia').focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,12 +168,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<a href="/IMPORTADORES/productos_frecuentes/editar"
|
<a href="/IMPORTADORES/productos_frecuentes/editar"
|
||||||
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/editar') ? 'active' : '' ?>">
|
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/editar') ? 'active' : '' ?>">
|
||||||
• Editar Producto
|
• Ver Productos
|
||||||
</a>
|
</a>
|
||||||
|
<!--
|
||||||
<a href="/IMPORTADORES/productos_frecuentes/importacion_csv"
|
<a href="/IMPORTADORES/productos_frecuentes/importacion_csv"
|
||||||
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/importacion_csv') ? 'active' : '' ?>">
|
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/importacion_csv') ? 'active' : '' ?>">
|
||||||
• Importación Masiva CSV
|
• Importación Masiva CSV
|
||||||
</a>
|
</a>
|
||||||
|
-->
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -364,12 +366,14 @@
|
|||||||
</a>
|
</a>
|
||||||
<a href="/IMPORTADORES/productos_frecuentes/editar"
|
<a href="/IMPORTADORES/productos_frecuentes/editar"
|
||||||
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/editar') ? 'active' : '' ?>">
|
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/editar') ? 'active' : '' ?>">
|
||||||
• Editar Producto
|
• Ver Productos
|
||||||
</a>
|
</a>
|
||||||
|
<!--
|
||||||
<a href="/IMPORTADORES/productos_frecuentes/importacion_csv"
|
<a href="/IMPORTADORES/productos_frecuentes/importacion_csv"
|
||||||
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/importacion_csv') ? 'active' : '' ?>">
|
class="nav-link px-3 py-1 <?= str_contains($_SERVER['REQUEST_URI'], '/productos_frecuentes/importacion_csv') ? 'active' : '' ?>">
|
||||||
• Importación Masiva CSV
|
• Importación Masiva CSV
|
||||||
</a>
|
</a>
|
||||||
|
-->
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,12 @@
|
|||||||
<!-- views/productos_frecuentes/alta.php -->
|
<!-- views/productos_frecuentes/alta.php -->
|
||||||
<?php
|
<?php
|
||||||
include __DIR__ . '/../partials/sidebar_importador.php';
|
include __DIR__ . '/../partials/sidebar_importador.php';
|
||||||
|
|
||||||
// Opciones de Vinculación y Criterio Preferencia
|
// Opciones de Vinculación y Criterio Preferencia
|
||||||
$vinculaciones = [
|
$vinculaciones = [ '0' => 'No existe', '1' => 'Existe, no afecta', '2' => 'Existe y afecta' ];
|
||||||
'0' => 'No existe',
|
$criterios = [ 'A' => 'Criterio A', 'B' => 'Criterio B', 'C' => 'Criterio C', 'D' => 'Criterio D', 'E' => 'Criterio E', 'F' => 'Criterio F' ];
|
||||||
'1' => 'Existe, no afecta',
|
|
||||||
'2' => 'Existe y afecta'
|
|
||||||
];
|
|
||||||
$criterios = [
|
|
||||||
'A' => 'Criterio A',
|
|
||||||
'B' => 'Criterio B',
|
|
||||||
'C' => 'Criterio C',
|
|
||||||
'D' => 'Criterio D',
|
|
||||||
'E' => 'Criterio E',
|
|
||||||
'F' => 'Criterio F'
|
|
||||||
];
|
|
||||||
// Proveedores, unidades y países se cargan por AJAX
|
// Proveedores, unidades y países se cargan por AJAX
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="es">
|
<html lang="es">
|
||||||
<head>
|
<head>
|
||||||
@@ -48,9 +37,8 @@
|
|||||||
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
||||||
.btn-pulse { animation: pulse 2s infinite; }
|
.btn-pulse { animation: pulse 2s infinite; }
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0% { transform: scale(1); }
|
0%, 100% { transform: scale(1); }
|
||||||
50% { transform: scale(1.05); }
|
50% { transform: scale(1.05); }
|
||||||
100% { transform: scale(1); }
|
|
||||||
}
|
}
|
||||||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
||||||
@keyframes fadeInUp {
|
@keyframes fadeInUp {
|
||||||
@@ -137,27 +125,28 @@
|
|||||||
<form id="altaProductoFrecuenteForm" action="/IMPORTADORES/productos_frecuentes/guardar" method="POST">
|
<form id="altaProductoFrecuenteForm" action="/IMPORTADORES/productos_frecuentes/guardar" method="POST">
|
||||||
<div class="row g-3 form-group-animated">
|
<div class="row g-3 form-group-animated">
|
||||||
<!-- Sinónimo, Fracción, NICO -->
|
<!-- Sinónimo, Fracción, NICO -->
|
||||||
<div class="col-md-4 form-group-animated">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="sinonimo" class="form-label">Sinónimo *</label>
|
<label for="sinonimo" class="form-label">Sinónimo *</label>
|
||||||
<input type="text" id="sinonimo" name="sinonimo" class="form-control" required>
|
<input type="text" id="sinonimo" name="sinonimo" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 form-group-animated">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="fraccion" class="form-label">Fracción *</label>
|
<label for="fraccion" class="form-label">Fracción *</label>
|
||||||
<input type="text" id="fraccion" name="fraccion" class="form-control" required>
|
<input type="text" id="fraccion" name="fraccion" class="form-control" maxlegth="8" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 form-group-animated">
|
<div class="col-md-2 form-group-animated">
|
||||||
<label for="nico" class="form-label">NICO *</label>
|
<label for="nico" class="form-label">NICO *</label>
|
||||||
<input type="text" id="nico" name="nico" class="form-control" required>
|
<input type="text" id="nico" name="nico" class="form-control" maxlength="2" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Número de Parte / Proveedor -->
|
<!-- Número de Parte / Proveedor -->
|
||||||
<div class="col-md-6 form-group-animated">
|
<div class="col-md-5 form-group-animated">
|
||||||
<label for="numero_parte" class="form-label">Número de Parte</label>
|
<label for="numero_parte" class="form-label">Número de Parte *</label>
|
||||||
<input type="text" id="numero_parte" name="numero_parte" class="form-control">
|
<input type="text" id="numero_parte" name="numero_parte" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-3"></div>
|
||||||
<label for="proveedor" class="form-label">Proveedor *</label>
|
<div class="col-md-4">
|
||||||
<select id="proveedor" name="proveedor" class="form-select searchable" required>
|
<label for="proveedor" class="form-label">Proveedor</label>
|
||||||
|
<select id="proveedor" name="proveedor" class="form-select searchable">
|
||||||
<option value="">Cargando proveedores…</option>
|
<option value="">Cargando proveedores…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,35 +158,42 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- País Origen/Destino -->
|
<!-- País Origen/Destino -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="pais_origen_destino" class="form-label">País Origen/Destino</label>
|
<label for="pais_origen_destino" class="form-label">País Origen/Destino *</label>
|
||||||
<select id="pais_origen_destino" name="pais_origen_destino" class="form-select searchable" required>
|
<select id="pais_origen_destino" name="pais_origen_destino" class="form-select searchable">
|
||||||
<option value="">Cargando países…</option>
|
<option value="">Cargando países…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<!-- País Comprador/Vendedor -->
|
<!-- País Comprador/Vendedor -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="pais_comprador_vendedor" class="form-label">País Comprador/Vendedor</label>
|
<label for="pais_comprador_vendedor" class="form-label">País Comprador/Vendedor *</label>
|
||||||
<select id="pais_comprador_vendedor" name="pais_comprador_vendedor" class="form-select searchable" required>
|
<select id="pais_comprador_vendedor" name="pais_comprador_vendedor" class="form-select searchable">
|
||||||
<option value="">Cargando países…</option>
|
<option value="">Cargando países…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Uso de la Mercancía -->
|
<!-- Uso de la Mercancía -->
|
||||||
<div class="col-md-4 form-group-animated">
|
<div class="col-md-3 form-group-animated">
|
||||||
<label for="uso_mercancia" class="form-label">Uso de la Mercancía</label>
|
<label for="uso_mercancia" class="form-label">Uso de la Mercancía</label>
|
||||||
<input type="text" id="uso_mercancia" name="uso_mercancia" class="form-control">
|
<input type="text" id="uso_mercancia" name="uso_mercancia" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Estado de la Mercancia -->
|
||||||
|
<div class="col-md-3 form-group-animated">
|
||||||
|
<label for="estado_mercancia" class="form-label">Estado de la Mercancía</label>
|
||||||
|
<input type="text" id="estado_mercancia" name="estado_mercancia" class="form-control">
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Unidad de Medida -->
|
<!-- Unidad de Medida -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="umc_id" class="form-label">Unidad de Medida *</label>
|
<label for="umc_id" class="form-label">Unidad de Medida *</label>
|
||||||
<select id="umc_id" name="umc_id" class="form-select searchable" required>
|
<select id="umc_id" name="umc_id" class="form-select searchable">
|
||||||
<option value="">Cargando unidades…</option>
|
<option value="">Cargando unidades…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Vinculación -->
|
<!-- Vinculación -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="vinculacion" class="form-label">Vinculación</label>
|
<label for="vinculacion" class="form-label">Vinculación</label>
|
||||||
<select id="vinculacion" name="vinculacion" class="form-select searchable">
|
<select id="vinculacion" name="vinculacion" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -208,7 +204,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Preferencia (fijas) -->
|
<!-- Preferencia (fijas) -->
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="preferencia" class="form-label">Preferencia</label>
|
<label for="preferencia" class="form-label">Preferencia</label>
|
||||||
<select id="preferencia" name="preferencia" class="form-select searchable">
|
<select id="preferencia" name="preferencia" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -220,8 +216,8 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Criterio Preferencia / Tipo Mercancía -->
|
<!-- Criterio Preferencia -->
|
||||||
<div class="col-md-6">
|
<div class="col-md-3">
|
||||||
<label for="criterio_preferencia" class="form-label">Criterio Preferencia</label>
|
<label for="criterio_preferencia" class="form-label">Criterio Preferencia</label>
|
||||||
<!-- Agrega `disabled` al select de criterio -->
|
<!-- Agrega `disabled` al select de criterio -->
|
||||||
<select id="criterio_preferencia" name="criterio_preferencia" class="form-select searchable" disabled>
|
<select id="criterio_preferencia" name="criterio_preferencia" class="form-select searchable" disabled>
|
||||||
@@ -231,18 +227,27 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 form-group-animated">
|
|
||||||
|
<!-- Tipo Mercancía -->
|
||||||
|
<div class="col-md-5 form-group-animated">
|
||||||
<label for="tipo_mercancia" class="form-label">Tipo de Mercancía</label>
|
<label for="tipo_mercancia" class="form-label">Tipo de Mercancía</label>
|
||||||
<input type="text" id="tipo_mercancia" name="tipo_mercancia" class="form-control">
|
<input type="text" id="tipo_mercancia" name="tipo_mercancia" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-2"></div>
|
||||||
|
|
||||||
<!-- Checkboxes -->
|
<!-- Certificado de Origen -->
|
||||||
<div class="col-md-3 form-group-animated">
|
<div class="col-md-5 form-group-animated">
|
||||||
<div class="form-check mt-2">
|
<label for="certificado_origen" class="form-label">Certificado de Origen</label>
|
||||||
<input class="form-check-input" type="checkbox" id="certificado_origen" name="certificado_origen" value="1">
|
<input type="text" id="certificado_origen" name="certificado_origen" class="form-control">
|
||||||
<label class="form-check-label" for="certificado_origen">Certificado de Origen</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Observaciones -->
|
||||||
|
<div class="col-12 form-group-animated">
|
||||||
|
<label for="observaciones" class="form-label">Observaciones</label>
|
||||||
|
<textarea id="observaciones" name="observaciones" class="form-control" rows="2"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Checkbox -->
|
||||||
<div class="col-md-3 form-group-animated">
|
<div class="col-md-3 form-group-animated">
|
||||||
<div class="form-check mt-2">
|
<div class="form-check mt-2">
|
||||||
<input class="form-check-input" type="checkbox" id="documento_en_original" name="documento_en_original" value="1">
|
<input class="form-check-input" type="checkbox" id="documento_en_original" name="documento_en_original" value="1">
|
||||||
@@ -272,6 +277,88 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
document.getElementById('altaProductoFrecuenteForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const sinonimo = document.getElementById('sinonimo').value.trim();
|
||||||
|
const fraccion = document.getElementById('fraccion').value.trim();
|
||||||
|
const nico = document.getElementById('nico').value.trim();
|
||||||
|
const numero_parte = document.getElementById('numero_parte').value.trim();
|
||||||
|
const pais_o_d = document.getElementById('pais_origen_destino').value;
|
||||||
|
const pais_c_v = document.getElementById('pais_comprador_vendedor').value;
|
||||||
|
const unidad_medida = document.getElementById('umc_id').value;
|
||||||
|
|
||||||
|
const soloNumRegex = /^[0-9]+$/;
|
||||||
|
|
||||||
|
if (!sinonimo) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa el sinónimo.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('sinonimo').focus();
|
||||||
|
}
|
||||||
|
if (!fraccion) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa la fracción.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('fraccion').focus();
|
||||||
|
}
|
||||||
|
if (!soloNumRegex.test(fraccion)) {
|
||||||
|
Swal.fire({ icon: 'error', title: 'Fracción inválida', text: 'La fracción solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||||
|
document.getElementById('fraccion').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!nico) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa el NICO.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('nico').focus();
|
||||||
|
}
|
||||||
|
if (!soloNumRegex.test(nico)) {
|
||||||
|
Swal.fire({ icon: 'error', title: 'NICO inválido', text: 'El NICO solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||||
|
document.getElementById('nico').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!numero_parte) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa el número de parte.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('numero_parte').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función helper para hacer focus en elementos con Choices.js
|
||||||
|
function focusChoicesElement(selectId) {
|
||||||
|
const choicesContainer = document.querySelector(`#${selectId}`).parentElement.querySelector('.choices');
|
||||||
|
if (choicesContainer) {
|
||||||
|
choicesContainer.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// En tu validación del submit:
|
||||||
|
if (!pais_o_d) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor selecciona el país de origen.', confirmButtonColor: '#dc3545' });
|
||||||
|
focusChoicesElement('pais_origen_destino');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!pais_c_v) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor selecciona el país de destino.', confirmButtonColor: '#dc3545' });
|
||||||
|
focusChoicesElement('pais_comprador_vendedor');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!unidad_medida) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor selecciona la unidad de medida.', confirmButtonColor: '#dc3545' });
|
||||||
|
focusChoicesElement('umc_id');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener todos los inputs y selects para validación
|
||||||
|
const inputs = document.querySelectorAll('#altaProductoFrecuenteForm input[required], #altaProductoFrecuenteForm select[required]');
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isValid) {
|
||||||
|
// Si pasa la validación, enviamos el formulario manualmente
|
||||||
|
this.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
function fetchJsonOrThrow(url) {
|
function fetchJsonOrThrow(url) {
|
||||||
return fetch(url)
|
return fetch(url)
|
||||||
@@ -412,19 +499,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validación del formulario
|
|
||||||
document.getElementById('altaProductoFrecuenteForm').addEventListener('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
let isValid = true;
|
|
||||||
inputs.forEach(input => {
|
|
||||||
if (!input.checkValidity()) {
|
|
||||||
input.classList.add('shake');
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,13 @@
|
|||||||
<!-- views/productos_frecuentes/editar.php -->
|
<!-- views/productos_frecuentes/editar.php -->
|
||||||
<?php
|
<?php
|
||||||
include __DIR__ . '/../partials/sidebar_importador.php';
|
include __DIR__ . '/../partials/sidebar_importador.php';
|
||||||
|
// Opciones de Vinculación y Criterio Preferencia
|
||||||
$vinculaciones = [
|
$vinculaciones = [ '0' => 'No existe', '1' => 'Existe, no afecta', '2' => 'Existe y afecta' ];
|
||||||
'0' => 'No existe',
|
$criterios = [ 'A' => 'Criterio A', 'B' => 'Criterio B', 'C' => 'Criterio C', 'D' => 'Criterio D', 'E' => 'Criterio E', 'F' => 'Criterio F' ];
|
||||||
'1' => 'Existe, no afecta',
|
// Proveedores, unidades y países se cargan por AJAX
|
||||||
'2' => 'Existe y afecta'
|
|
||||||
];
|
|
||||||
$criterios = [
|
|
||||||
'A' => 'Criterio A',
|
|
||||||
'B' => 'Criterio B',
|
|
||||||
'C' => 'Criterio C',
|
|
||||||
'D' => 'Criterio D',
|
|
||||||
'E' => 'Criterio E',
|
|
||||||
'F' => 'Criterio F'
|
|
||||||
];
|
|
||||||
// $producto proviene del controlador
|
// $producto proviene del controlador
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="es">
|
<html lang="es">
|
||||||
<head>
|
<head>
|
||||||
@@ -41,9 +32,8 @@
|
|||||||
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
.card-hover:hover { transform: translateY(-8px) scale(1.02); box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.15) !important; }
|
||||||
.btn-pulse { animation: pulse 2s infinite; }
|
.btn-pulse { animation: pulse 2s infinite; }
|
||||||
@keyframes pulse {
|
@keyframes pulse {
|
||||||
0% { transform: scale(1); }
|
0%, 100% { transform: scale(1); }
|
||||||
50% { transform: scale(1.05); }
|
50% { transform: scale(1.05); }
|
||||||
100% { transform: scale(1); }
|
|
||||||
}
|
}
|
||||||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
||||||
@keyframes fadeInUp {
|
@keyframes fadeInUp {
|
||||||
@@ -63,6 +53,51 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.form-label { font-weight: 500; }
|
.form-label { font-weight: 500; }
|
||||||
|
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
||||||
|
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
||||||
|
.form-control:not(.no-animation):focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px); }
|
||||||
|
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
||||||
|
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
||||||
|
@keyframes shake {
|
||||||
|
0%, 100% { transform: translateX(0); }
|
||||||
|
25% { transform: translateX(-5px); }
|
||||||
|
75% { transform: translateX(5px); }
|
||||||
|
}
|
||||||
|
/* Floating labels para inputs texto */
|
||||||
|
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
|
||||||
|
.form-floating-custom .form-control { padding: 1rem 0.75rem 0.5rem 0.75rem; height: auto; }
|
||||||
|
.form-floating-custom .form-label { position: absolute; top: 0.75rem; left: 0.75rem; transition: all 0.3s ease; pointer-events: none; color: #6c757d; z-index: 2; }
|
||||||
|
.form-floating-custom .form-control:focus ~ .form-label,
|
||||||
|
.form-floating-custom .form-control:not(:placeholder-shown) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
|
||||||
|
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
||||||
|
@keyframes inputPulse {
|
||||||
|
0% { transform: scale(1); }
|
||||||
|
50% { transform: scale(1.02); }
|
||||||
|
100% { transform: scale(1); }
|
||||||
|
}
|
||||||
|
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
||||||
|
.input-gradient:not(.no-animation)::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
||||||
|
background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
|
||||||
|
.input-gradient:not(.no-animation):focus::before { left: 100%; }
|
||||||
|
.form-control.valid:not(.no-animation) { /*border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9);*/ animation: successGlow 1s ease-in-out; }
|
||||||
|
@keyframes successGlow {
|
||||||
|
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
|
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
||||||
|
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
||||||
|
}
|
||||||
|
/* Animación para los campos del formulario */
|
||||||
|
.form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; }
|
||||||
|
.form-group-animated:nth-child(1) { animation-delay: 0.1s; }
|
||||||
|
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
||||||
|
.form-group-animated:nth-child(3) { animation-delay: 0.3s; }
|
||||||
|
.form-group-animated:nth-child(4) { animation-delay: 0.4s; }
|
||||||
|
.form-group-animated:nth-child(5) { animation-delay: 0.5s; }
|
||||||
|
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
|
||||||
|
.form-group-animated:nth-child(7) { animation-delay: 0.7s; }
|
||||||
|
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
||||||
|
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
||||||
|
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
||||||
|
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -82,65 +117,74 @@
|
|||||||
<div class="card p-4 shadow-sm bg-white card-hover position-relative h-auto">
|
<div class="card p-4 shadow-sm bg-white card-hover position-relative h-auto">
|
||||||
<form id="editarProductoFrecuenteForm" action="/IMPORTADORES/productos_frecuentes/actualizar" method="POST">
|
<form id="editarProductoFrecuenteForm" action="/IMPORTADORES/productos_frecuentes/actualizar" method="POST">
|
||||||
<input type="hidden" name="id_producto_frecuente" value="<?= htmlspecialchars($producto['id_producto_frecuente']) ?>">
|
<input type="hidden" name="id_producto_frecuente" value="<?= htmlspecialchars($producto['id_producto_frecuente']) ?>">
|
||||||
<div class="row g-3">
|
<div class="row g-3 form-group-animated">
|
||||||
<div class="col-md-4">
|
<div class="col-md-6 form-group-animated">
|
||||||
<label for="sinonimo" class="form-label">Sinónimo *</label>
|
<label for="sinonimo" class="form-label">Sinónimo</label>
|
||||||
<input type="text" id="sinonimo" name="sinonimo" class="form-control"
|
<input type="text" id="sinonimo" name="sinonimo" class="form-control"
|
||||||
value="<?= htmlspecialchars($producto['sinonimo']) ?>" required>
|
value="<?= htmlspecialchars($producto['sinonimo']) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-4 form-group-animated">
|
||||||
<label for="fraccion" class="form-label">Fracción *</label>
|
<label for="fraccion" class="form-label">Fracción</label>
|
||||||
<input type="text" id="fraccion" name="fraccion" class="form-control"
|
<input type="text" id="fraccion" name="fraccion" class="form-control" maxlegth="8"
|
||||||
value="<?= htmlspecialchars($producto['fraccion']) ?>" required>
|
value="<?= htmlspecialchars($producto['fraccion']) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-2 form-group-animated">
|
||||||
<label for="nico" class="form-label">NICO *</label>
|
<label for="nico" class="form-label">NICO</label>
|
||||||
<input type="text" id="nico" name="nico" class="form-control"
|
<input type="text" id="nico" name="nico" class="form-control" maxlength="2"
|
||||||
value="<?= htmlspecialchars($producto['nico']) ?>" required>
|
value="<?= htmlspecialchars($producto['nico']) ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-5 form-group-animated">
|
||||||
<label for="numero_parte" class="form-label">Número de Parte</label>
|
<label for="numero_parte" class="form-label">Número de Parte</label>
|
||||||
<input type="text" id="numero_parte" name="numero_parte" class="form-control"
|
<input type="text" id="numero_parte" name="numero_parte" class="form-control"
|
||||||
value="<?= htmlspecialchars($producto['numero_parte']) ?>">
|
value="<?= htmlspecialchars($producto['numero_parte']) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-3"></div>
|
||||||
<label for="proveedor" class="form-label">Proveedor *</label>
|
<div class="col-md-4">
|
||||||
<select id="proveedor" name="proveedor" class="form-select searchable" required>
|
<label for="proveedor" class="form-label">Proveedor</label>
|
||||||
|
<select id="proveedor" name="proveedor" class="form-select searchable">
|
||||||
<option value="">Cargando proveedores…</option>
|
<option value="">Cargando proveedores…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-12">
|
<div class="col-12 form-group-animated">
|
||||||
<label for="descripcion" class="form-label">Descripción</label>
|
<label for="descripcion" class="form-label">Descripción</label>
|
||||||
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"><?= htmlspecialchars($producto['descripcion']) ?></textarea>
|
<textarea id="descripcion" name="descripcion" class="form-control" rows="2"><?= htmlspecialchars($producto['descripcion']) ?></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="pais_origen_destino" class="form-label">País Origen/Destino</label>
|
<label for="pais_origen_destino" class="form-label">País Origen/Destino</label>
|
||||||
<select id="pais_origen_destino" name="pais_origen_destino" class="form-select searchable" required>
|
<select id="pais_origen_destino" name="pais_origen_destino" class="form-select searchable">
|
||||||
<option value="">Cargando países…</option>
|
<option value="">Cargando países…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="pais_comprador_vendedor" class="form-label">País Comprador/Vendedor</label>
|
<label for="pais_comprador_vendedor" class="form-label">País Comprador/Vendedor</label>
|
||||||
<select id="pais_comprador_vendedor" name="pais_comprador_vendedor" class="form-select searchable" required>
|
<select id="pais_comprador_vendedor" name="pais_comprador_vendedor" class="form-select searchable">
|
||||||
<option value="">Cargando países…</option>
|
<option value="">Cargando países…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
|
<div class="col-md-3 form-group-animated">
|
||||||
<label for="uso_mercancia" class="form-label">Uso de la Mercancía</label>
|
<label for="uso_mercancia" class="form-label">Uso de la Mercancía</label>
|
||||||
<input type="text" id="uso_mercancia" name="uso_mercancia" class="form-control"
|
<input type="text" id="uso_mercancia" name="uso_mercancia" class="form-control"
|
||||||
value="<?= htmlspecialchars($producto['uso_mercancia']) ?>">
|
value="<?= htmlspecialchars($producto['uso_mercancia']) ?>">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-3 form-group-animated">
|
||||||
<label for="umc_id" class="form-label">Unidad de Medida *</label>
|
<label for="estado_mercancia" class="form-label">Estado de la Mercancía</label>
|
||||||
<select id="umc_id" name="umc_id" class="form-select searchable" required>
|
<input type="text" id="estado_mercancia" name="estado_mercancia" class="form-control"
|
||||||
|
value="<?= htmlspecialchars($producto['estado_mercancia']) ?>">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label for="umc_id" class="form-label">Unidad de Medida</label>
|
||||||
|
<select id="umc_id" name="umc_id" class="form-select searchable">
|
||||||
<option value="">Cargando unidades…</option>
|
<option value="">Cargando unidades…</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
|
<div class="col-md-3">
|
||||||
<label for="vinculacion" class="form-label">Vinculación</label>
|
<label for="vinculacion" class="form-label">Vinculación</label>
|
||||||
<select id="vinculacion" name="vinculacion" class="form-select searchable">
|
<select id="vinculacion" name="vinculacion" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -151,7 +195,8 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
|
||||||
|
<div class="col-md-3">
|
||||||
<label for="preferencia" class="form-label">Preferencia</label>
|
<label for="preferencia" class="form-label">Preferencia</label>
|
||||||
<select id="preferencia" name="preferencia" class="form-select searchable">
|
<select id="preferencia" name="preferencia" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -161,7 +206,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-3">
|
||||||
<label for="criterio_preferencia" class="form-label">Criterio Preferencia</label>
|
<label for="criterio_preferencia" class="form-label">Criterio Preferencia</label>
|
||||||
<select id="criterio_preferencia" name="criterio_preferencia" class="form-select searchable" disabled>
|
<select id="criterio_preferencia" name="criterio_preferencia" class="form-select searchable" disabled>
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -172,20 +217,26 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
|
||||||
|
<div class="col-md-5 form-group-animated">
|
||||||
<label for="tipo_mercancia" class="form-label">Tipo de Mercancía</label>
|
<label for="tipo_mercancia" class="form-label">Tipo de Mercancía</label>
|
||||||
<input type="text" id="tipo_mercancia" name="tipo_mercancia" class="form-control"
|
<input type="text" id="tipo_mercancia" name="tipo_mercancia" class="form-control"
|
||||||
value="<?= htmlspecialchars($producto['tipo_mercancia']) ?>">
|
value="<?= htmlspecialchars($producto['tipo_mercancia']) ?>">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-2"></div>
|
||||||
|
|
||||||
<div class="col-md-3">
|
<div class="col-md-5 form-group-animated">
|
||||||
<div class="form-check mt-2">
|
<label for="certificado_origen" class="form-label">Certificado de Origen</label>
|
||||||
<input class="form-check-input" type="checkbox" id="certificado_origen" name="certificado_origen" value="1"
|
<input type="text" id="certificado_origen" name="certificado_origen" class="form-control"
|
||||||
<?= $producto['certificado_origen']?'checked':'' ?>>
|
value="<?= htmlspecialchars($producto['certificado_origen']) ?>">
|
||||||
<label class="form-check-label" for="certificado_origen">Certificado de Origen</label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 form-group-animated">
|
||||||
|
<label for="observaciones" class="form-label">Observaciones</label>
|
||||||
|
<textarea id="observaciones" name="observaciones" class="form-control" rows="2"><?= htmlspecialchars($producto['observaciones']) ?></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3">
|
|
||||||
|
<div class="col-md-3 form-group-animated">
|
||||||
<div class="form-check mt-2">
|
<div class="form-check mt-2">
|
||||||
<input class="form-check-input" type="checkbox" id="documento_en_original" name="documento_en_original" value="1"
|
<input class="form-check-input" type="checkbox" id="documento_en_original" name="documento_en_original" value="1"
|
||||||
<?= $producto['documento_en_original']?'checked':'' ?>>
|
<?= $producto['documento_en_original']?'checked':'' ?>>
|
||||||
@@ -194,7 +245,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 text-end">
|
<div class="col-12 mt-4 text-end form-group-animated">
|
||||||
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Actualizar</button>
|
<button type="submit" class="btn btn-primary mt-auto w-auto btn-animated">Actualizar</button>
|
||||||
<a href="/IMPORTADORES/productos_frecuentes" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/productos_frecuentes" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -206,6 +257,88 @@
|
|||||||
<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/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
document.getElementById('editarProductoFrecuenteForm').addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const sinonimo = document.getElementById('sinonimo').value.trim();
|
||||||
|
const fraccion = document.getElementById('fraccion').value.trim();
|
||||||
|
const nico = document.getElementById('nico').value.trim();
|
||||||
|
const numero_parte = document.getElementById('numero_parte').value.trim();
|
||||||
|
const pais_o_d = document.getElementById('pais_origen_destino').value;
|
||||||
|
const pais_c_v = document.getElementById('pais_comprador_vendedor').value;
|
||||||
|
const unidad_medida = document.getElementById('umc_id').value;
|
||||||
|
|
||||||
|
const soloNumRegex = /^[0-9]+$/;
|
||||||
|
|
||||||
|
if (!sinonimo) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa el sinónimo.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('sinonimo').focus();
|
||||||
|
}
|
||||||
|
if (!fraccion) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa la fracción.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('fraccion').focus();
|
||||||
|
}
|
||||||
|
if (!soloNumRegex.test(fraccion)) {
|
||||||
|
Swal.fire({ icon: 'error', title: 'Fracción inválida', text: 'La fracción solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||||
|
document.getElementById('fraccion').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!nico) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa el NICO.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('nico').focus();
|
||||||
|
}
|
||||||
|
if (!soloNumRegex.test(nico)) {
|
||||||
|
Swal.fire({ icon: 'error', title: 'NICO inválido', text: 'El NICO solo puede contener números', confirmButtonColor: '#dc3545' });
|
||||||
|
document.getElementById('nico').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!numero_parte) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor ingresa el número de parte.', confirmButtonColor: '#dc3545' });
|
||||||
|
return document.getElementById('numero_parte').focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Función helper para hacer focus en elementos con Choices.js
|
||||||
|
function focusChoicesElement(selectId) {
|
||||||
|
const choicesContainer = document.querySelector(`#${selectId}`).parentElement.querySelector('.choices');
|
||||||
|
if (choicesContainer) {
|
||||||
|
choicesContainer.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// En tu validación del submit:
|
||||||
|
if (!pais_o_d) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor selecciona el país de origen.', confirmButtonColor: '#dc3545' });
|
||||||
|
focusChoicesElement('pais_origen_destino');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!pais_c_v) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor selecciona el país de destino.', confirmButtonColor: '#dc3545' });
|
||||||
|
focusChoicesElement('pais_comprador_vendedor');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!unidad_medida) {
|
||||||
|
Swal.fire({ icon: 'warning', title: 'Campo requerido', text: 'Por favor selecciona la unidad de medida.', confirmButtonColor: '#dc3545' });
|
||||||
|
focusChoicesElement('umc_id');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Obtener todos los inputs y selects para validación
|
||||||
|
const inputs = document.querySelectorAll('#altaProductoFrecuenteForm input[required], #altaProductoFrecuenteForm select[required]');
|
||||||
|
|
||||||
|
let isValid = true;
|
||||||
|
inputs.forEach(input => {
|
||||||
|
if (!input.checkValidity()) {
|
||||||
|
input.classList.add('shake');
|
||||||
|
isValid = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isValid) {
|
||||||
|
// Si pasa la validación, enviamos el formulario manualmente
|
||||||
|
this.submit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
// Helper para fetch + validación JSON
|
// Helper para fetch + validación JSON
|
||||||
function fetchJsonOrThrow(url) {
|
function fetchJsonOrThrow(url) {
|
||||||
|
|||||||
@@ -57,26 +57,19 @@
|
|||||||
|
|
||||||
<?php if (!empty($_SESSION['flash_error'])): ?>
|
<?php if (!empty($_SESSION['flash_error'])): ?>
|
||||||
<script>
|
<script>
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'error', title: 'Error', text: '<?= addslashes($_SESSION['flash_error']) ?>' });
|
||||||
icon: 'error',
|
|
||||||
title: 'Error',
|
|
||||||
text: '<?= addslashes($_SESSION['flash_error']) ?>'
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<?php unset($_SESSION['flash_error']); endif; ?>
|
<?php unset($_SESSION['flash_error']); endif; ?>
|
||||||
|
|
||||||
<?php if (!empty($_SESSION['flash_success'])): ?>
|
<?php if (!empty($_SESSION['flash_success'])): ?>
|
||||||
<script>
|
<script>
|
||||||
Swal.fire({
|
Swal.fire({ icon: 'success', title: '¡Listo!', text: '<?= addslashes($_SESSION['flash_success']) ?>' });
|
||||||
icon: 'success',
|
|
||||||
title: '¡Listo!',
|
|
||||||
text: '<?= addslashes($_SESSION['flash_success']) ?>'
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<?php unset($_SESSION['flash_success']); endif; ?>
|
<?php unset($_SESSION['flash_success']); endif; ?>
|
||||||
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">📋 Productos Frecuentes</h4>
|
<h4 class="mb-4 animate__animated animate__fadeInDown title_glow">📋 Productos Frecuentes</h4>
|
||||||
|
<a href="/IMPORTADORES/productos_frecuentes/alta" class="btn btn-success mb-3 mt-auto w-auto btn-animated">➕ Nuevo Producto</a>
|
||||||
<div class="card p-4 shadow-sm card-hover position-relative h-auto">
|
<div class="card p-4 shadow-sm card-hover position-relative h-auto">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table id="tablaProductosFrecuentes" class="table table-striped table-bordered">
|
<table id="tablaProductosFrecuentes" class="table table-striped table-bordered">
|
||||||
@@ -99,50 +92,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<?php foreach ($productos as $row): ?>
|
||||||
$conn = getConnection();
|
|
||||||
$sql = "
|
|
||||||
SELECT
|
|
||||||
pf.id_producto_frecuente,
|
|
||||||
pf.sinonimo,
|
|
||||||
pf.fraccion,
|
|
||||||
pf.nico,
|
|
||||||
pf.numero_parte,
|
|
||||||
pf.proveedor AS proveedor_guardado,
|
|
||||||
u.descripcion AS unidad_de_medida,
|
|
||||||
por.nombre AS pais_origen_destino,
|
|
||||||
pc.nombre AS pais_comprador_vendedor,
|
|
||||||
pf.uso_mercancia,
|
|
||||||
pf.estado_mercancia,
|
|
||||||
pf.preferencia,
|
|
||||||
pf.frecuencia_uso
|
|
||||||
FROM dbo.productos_frecuentes pf
|
|
||||||
LEFT JOIN dbo.unidades_medida_apendice7 u
|
|
||||||
ON pf.umc_id = u.id
|
|
||||||
LEFT JOIN dbo.paises por
|
|
||||||
ON pf.pais_origen_destino = por.id_pais
|
|
||||||
LEFT JOIN dbo.paises pc
|
|
||||||
ON pf.pais_comprador_vendedor = pc.id_pais
|
|
||||||
WHERE pf.id_importador = ?
|
|
||||||
ORDER BY pf.fecha_alta DESC
|
|
||||||
";
|
|
||||||
$stmt = sqlsrv_query($conn, $sql, [$_SESSION['usuario_id']]);
|
|
||||||
|
|
||||||
if ($stmt === false) {
|
|
||||||
echo '<pre>', print_r(sqlsrv_errors(), true), '</pre>';
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)):
|
|
||||||
?>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><?= htmlspecialchars($row['id_producto_frecuente']) ?></td>
|
<td><?= htmlspecialchars($row['id_producto_frecuente']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['sinonimo']) ?></td>
|
<td><?= htmlspecialchars($row['sinonimo']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['fraccion']) ?></td>
|
<td><?= htmlspecialchars($row['fraccion']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['nico']) ?></td>
|
<td><?= htmlspecialchars($row['nico']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['numero_parte']) ?></td>
|
<td><?= htmlspecialchars($row['numero_parte']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['proveedor_guardado']) ?></td>
|
<td><?= htmlspecialchars($row['nombre_proveedor']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['unidad_de_medida']) ?></td>
|
<td><?= htmlspecialchars($row['unidad_de_medida']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['pais_origen_destino']) ?></td>
|
<td><?= htmlspecialchars($row['pais_origen_destino']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['pais_comprador_vendedor']) ?></td>
|
<td><?= htmlspecialchars($row['pais_comprador_vendedor']) ?></td>
|
||||||
@@ -151,15 +108,11 @@
|
|||||||
<td><?= htmlspecialchars($row['preferencia']) ?></td>
|
<td><?= htmlspecialchars($row['preferencia']) ?></td>
|
||||||
<td><?= htmlspecialchars($row['frecuencia_uso']) ?></td>
|
<td><?= htmlspecialchars($row['frecuencia_uso']) ?></td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
<a href="/IMPORTADORES/productos_frecuentes/editar?id=<?= $row['id_producto_frecuente'] ?>"
|
<a href="/IMPORTADORES/productos_frecuentes/editar?id=<?= $row['id_producto_frecuente'] ?>" class="btn btn-sm btn-primary mt-auto w-auto btn-animated">✏️</a>
|
||||||
class="btn btn-sm btn-primary mt-auto w-auto btn-animated">✏️</a>
|
<button class="btn btn-sm btn-danger mt-auto w-auto btn-animated" onclick="confirmDelete(<?= $row['id_producto_frecuente'] ?>)">🗑️</button>
|
||||||
<button class="btn btn-sm btn-danger mt-auto w-auto btn-animated"
|
|
||||||
onclick="confirmDelete(<?= $row['id_producto_frecuente'] ?>)">
|
|
||||||
🗑️
|
|
||||||
</button>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endwhile; ?>
|
<?php endforeach; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -193,6 +146,11 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<?php if (isset($_GET['deleted']) && $_GET['deleted']==='ok'): ?>
|
||||||
|
Swal.fire({ icon: 'success', title: 'Producto eliminado', text: 'Ya no aparecerá en tu lista.', confirmButtonColor: '#198754' });
|
||||||
|
<?php endif; ?>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -8,13 +8,13 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Bootstrap CSS -->
|
<!-- Bootstrap CSS -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<!-- Choices.js CSS -->
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css"/>
|
||||||
<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/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">
|
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
||||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
||||||
|
<!-- Sweet Alert 2 -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
<!-- Font Awesome -->
|
<!-- Font Awesome -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||||
<!-- Animate.css para animaciones adicionales -->
|
<!-- Animate.css para animaciones adicionales -->
|
||||||
@@ -59,80 +59,6 @@
|
|||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
||||||
.btn-animated:hover::before { left: 100%; }
|
.btn-animated:hover::before { left: 100%; }
|
||||||
.hide { display: none !important; }
|
.hide { display: none !important; }
|
||||||
.btn-pulse { animation: pulse 2s infinite; }
|
|
||||||
@keyframes pulse {
|
|
||||||
0% { transform: scale(1); }
|
|
||||||
50% { transform: scale(1.05); }
|
|
||||||
100% { transform: scale(1); }
|
|
||||||
}
|
|
||||||
.fade-in-up { animation: fadeInUp 0.8s ease-out; }
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from { opacity: 0; transform: translateY(30px); }
|
|
||||||
to { opacity: 1; transform: translateY(0); }
|
|
||||||
}
|
|
||||||
/* Responsive animations */
|
|
||||||
@media (max-width: 768px) { .card-hover:hover { transform: translateY(-4px) scale(1.01); } }
|
|
||||||
/* Efecto de glow para elementos activos */
|
|
||||||
.btn.active { box-shadow: 0 0 20px rgba(var(--bs-primary-rgb), 0.5); }
|
|
||||||
/* Animación para el título */
|
|
||||||
.title-glow { text-shadow: 0 0 10px rgba(0, 123, 255, 0.3); }
|
|
||||||
/* Efecto para botones */
|
|
||||||
.btn-animated { transition: all 0.3s ease; position: relative; overflow: hidden; }
|
|
||||||
.btn-animated:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2); }
|
|
||||||
.btn-animated::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
|
||||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); transition: left 0.5s; }
|
|
||||||
.btn-animated:hover::before { left: 100%; }
|
|
||||||
.form-label { font-weight: 500; }
|
|
||||||
/* ========== ANIMACIONES PARA INPUTS TEXTO ========== */
|
|
||||||
.form-control:not(.no-animation) { transition: all 0.3s ease; border: 2px solid #dee2e6; position: relative; }
|
|
||||||
.form-control:not(.no-animation):focus { border-color: #0d6efd; box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25), 0 0 20px rgba(13, 110, 253, 0.3); transform: translateY(-2px); }
|
|
||||||
.form-control:not(.no-animation):not(:placeholder-shown) { /*border-color: #198754; background-color: #f8fff9;*/ }
|
|
||||||
.form-control:not(.no-animation).shake { animation: shake 0.5s ease-in-out; }
|
|
||||||
@keyframes shake {
|
|
||||||
0%, 100% { transform: translateX(0); }
|
|
||||||
25% { transform: translateX(-5px); }
|
|
||||||
75% { transform: translateX(5px); }
|
|
||||||
}
|
|
||||||
/* Floating labels para inputs texto */
|
|
||||||
.form-floating-custom { position: relative; margin-bottom: 1.5rem; }
|
|
||||||
.form-floating-custom .form-control { padding: 1rem 0.75rem 0.5rem 0.75rem; height: auto; }
|
|
||||||
.form-floating-custom .form-label { position: absolute; top: 0.75rem; left: 0.75rem; transition: all 0.3s ease; pointer-events: none; color: #6c757d; z-index: 2; }
|
|
||||||
.form-floating-custom .form-control:focus ~ .form-label,
|
|
||||||
.form-floating-custom .form-control:not(:placeholder-shown) ~ .form-label { top: 0.25rem; font-size: 0.75rem; color: #0d6efd; font-weight: 600; }
|
|
||||||
.input-pulse:hover:not(.no-animation) { animation: inputPulse 0.6s ease-in-out; }
|
|
||||||
@keyframes inputPulse {
|
|
||||||
0% { transform: scale(1); }
|
|
||||||
50% { transform: scale(1.02); }
|
|
||||||
100% { transform: scale(1); }
|
|
||||||
}
|
|
||||||
.input-gradient:not(.no-animation) { position: relative; overflow: hidden; }
|
|
||||||
.input-gradient:not(.no-animation)::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%;
|
|
||||||
background: linear-gradient(90deg, transparent, rgba(13, 110, 253, 0.3), transparent); transition: left 0.5s; pointer-events: none; z-index: 1; }
|
|
||||||
.input-gradient:not(.no-animation):focus::before { left: 100%; }
|
|
||||||
.form-control.valid:not(.no-animation) { /*border-color: #198754; background: linear-gradient(45deg, #fff, #f8fff9);*/ animation: successGlow 1s ease-in-out; }
|
|
||||||
@keyframes successGlow {
|
|
||||||
0% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
|
||||||
50% { box-shadow: 0 0 20px rgba(25, 135, 84, 0.8); }
|
|
||||||
100% { box-shadow: 0 0 5px rgba(25, 135, 84, 0.5); }
|
|
||||||
}
|
|
||||||
/* Animación para los campos del formulario */
|
|
||||||
.form-group-animated { opacity: 0; transform: translateY(20px); animation: slideUp 0.6s ease-out forwards; }
|
|
||||||
.form-group-animated:nth-child(1) { animation-delay: 0.1s; }
|
|
||||||
.form-group-animated:nth-child(2) { animation-delay: 0.2s; }
|
|
||||||
.form-group-animated:nth-child(3) { animation-delay: 0.3s; }
|
|
||||||
.form-group-animated:nth-child(4) { animation-delay: 0.4s; }
|
|
||||||
.form-group-animated:nth-child(5) { animation-delay: 0.5s; }
|
|
||||||
.form-group-animated:nth-child(6) { animation-delay: 0.6s; }
|
|
||||||
.form-group-animated:nth-child(7) { animation-delay: 0.7s; }
|
|
||||||
.form-group-animated:nth-child(8) { animation-delay: 0.8s; }
|
|
||||||
.form-group-animated:nth-child(9) { animation-delay: 0.9s; }
|
|
||||||
.form-group-animated:nth-child(10) { animation-delay: 1.0s; }
|
|
||||||
@keyframes slideUp { to { opacity: 1; transform: translateY(0); } }
|
|
||||||
/* ========== ESTILOS PARA CAMPO FOTO (SIN ANIMACIONES) ========== */
|
|
||||||
.no-animation, .no-border-style { transition: none !important; border: none; box-shadow: none !important; background: #fff !important; }
|
|
||||||
.no-animation:focus { transform: none !important; border: none; box-shadow: none !important; }
|
|
||||||
.no-animation:hover { animation: none !important; }
|
|
||||||
.no-animation::before, .no-animation::after { display: none !important; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -145,19 +71,19 @@
|
|||||||
|
|
||||||
<!-- Datos principales -->
|
<!-- Datos principales -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-3 mb-3 form-group-animated">
|
<div class="col-md-3 mb-3">
|
||||||
<label for="numero_factura" class="form-label">Número de Factura</label>
|
<label for="numero_factura" class="form-label">Número de Factura</label>
|
||||||
<input id="numero_factura" name="numero_factura" type="text" class="form-control" required
|
<input id="numero_factura" name="numero_factura" type="text" class="form-control" required
|
||||||
value="<?= htmlspecialchars($factura['numero_factura']) ?>">
|
value="<?= htmlspecialchars($factura['numero_factura']) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 mb-3 form-group-animated">
|
<div class="col-md-3 mb-3">
|
||||||
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
<label for="fecha_factura" class="form-label">Fecha de Factura</label>
|
||||||
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control" required
|
<input id="fecha_factura" name="fecha_factura" type="date" class="form-control" required
|
||||||
value="<?= htmlspecialchars($factura['fecha_factura']) ?>">
|
value="<?= htmlspecialchars($factura['fecha_factura']) ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-3 mb-3">
|
<div class="col-md-3 mb-3">
|
||||||
<label for="proveedor_clave" class="form-label">Proveedor</label>
|
<label for="proveedor_id" class="form-label">Proveedor</label>
|
||||||
<select id="proveedor_clave" name="proveedor_clave" class="form-select searchable">
|
<select id="proveedor_id" name="proveedor_clave" class="form-select searchable">
|
||||||
<option value="">Cargando proveedores...</option>
|
<option value="">Cargando proveedores...</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -224,7 +150,7 @@
|
|||||||
|
|
||||||
<!-- Valor y Vinculación -->
|
<!-- Valor y Vinculación -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-8 mb-3 form-group-animated">
|
<div class="col-md-8 mb-3">
|
||||||
<label for="valor_factura" class="form-label">Valor Factura</label>
|
<label for="valor_factura" class="form-label">Valor Factura</label>
|
||||||
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control valor-total" required
|
<input id="valor_factura" name="valor_factura" type="number" step="0.01" min="0" class="form-control valor-total" required
|
||||||
value="<?= htmlspecialchars($factura['valor_factura']) ?>">
|
value="<?= htmlspecialchars($factura['valor_factura']) ?>">
|
||||||
@@ -267,7 +193,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 mb-3">
|
<div class="col-md-4 mb-3">
|
||||||
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
<label for="foto_solicitud" class="form-label">Foto de la Carga (PIPA)</label>
|
||||||
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control no-animation no-border-style" accept="image/*">
|
<input id="foto_solicitud" name="foto_solicitud" type="file" class="form-control" accept="image/*">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -293,9 +219,9 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<?php if (!empty($partidas)): foreach($partidas as $i=>$p): ?>
|
<?php if (!empty($partidas)): foreach($partidas as $i=>$p): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input name="partidas[<?= $i ?>][descripcion]" class="form-control form-group-animated" value="<?= htmlspecialchars($p['descripcion']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][descripcion]" class="form-control" value="<?= htmlspecialchars($p['descripcion']) ?>"></td>
|
||||||
<td><input name="partidas[<?= $i ?>][cantidad_comercial]" type="number" step="0.0001" min="0" class="form-control form-group-animated" value="<?= htmlspecialchars($p['cantidad_comercial']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][cantidad_comercial]" type="number" step="0.0001" min="0" class="form-control" value="<?= htmlspecialchars($p['cantidad_comercial']) ?>"></td>
|
||||||
<td><input name="partidas[<?= $i ?>][cantidad_tarifa]" type="number" step="0.0001" min="0" class="form-control form-group-animated" value="<?= htmlspecialchars($p['cantidad_tarifa']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][cantidad_tarifa]" type="number" step="0.0001" min="0" class="form-control" value="<?= htmlspecialchars($p['cantidad_tarifa']) ?>"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[<?= $i ?>][unidad_comercial_id]" class="form-select searchable">
|
<select name="partidas[<?= $i ?>][unidad_comercial_id]" class="form-select searchable">
|
||||||
<option value="">-- Unidad --</option>
|
<option value="">-- Unidad --</option>
|
||||||
@@ -306,8 +232,8 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td><input name="partidas[<?= $i ?>][valor_factura]" type="number" step="0.01" min="0" class="form-control valor-partida form-group-animated" value="<?= htmlspecialchars($p['valor_factura']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][valor_factura]" type="number" step="0.01" min="0" class="form-control valor-partida" value="<?= htmlspecialchars($p['valor_factura']) ?>"></td>
|
||||||
<td><input name="partidas[<?= $i ?>][peso_bruto]" type="number" step="0.0001" min="0" class="form-control form-group-animated" value="<?= htmlspecialchars($p['peso_bruto']) ?>"></td>
|
<td><input name="partidas[<?= $i ?>][peso_bruto]" type="number" step="0.0001" min="0" class="form-control" value="<?= htmlspecialchars($p['peso_bruto']) ?>"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[<?= $i ?>][tasa_preferencial]" class="form-select searchable">
|
<select name="partidas[<?= $i ?>][tasa_preferencial]" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -316,15 +242,15 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td class="hide"><input name="partidas[<?= $i ?>][precio_unitario]" type="number" class="form-control form-group-animated" value="<?= htmlspecialchars($p['precio_unitario'] ?? '') ?>"></td>
|
<td class="hide"><input name="partidas[<?= $i ?>][precio_unitario]" type="number" class="form-control" value="<?= htmlspecialchars($p['precio_unitario'] ?? '') ?>"></td>
|
||||||
<td class="hide"><input name="partidas[<?= $i ?>][oma_factura]" class="form-control form-group-animated" value="<?= htmlspecialchars($p['oma_factura'] ?? '') ?>"></td>
|
<td class="hide"><input name="partidas[<?= $i ?>][oma_factura]" class="form-control" value="<?= htmlspecialchars($p['oma_factura'] ?? '') ?>"></td>
|
||||||
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
<td><button type="button" class="btn btn-danger btn-sm remove-row">✖️</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; else: ?>
|
<?php endforeach; else: ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td><input name="partidas[0][descripcion]" class="form-control form-group-animated"></td>
|
<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 form-group-animated" min="0"></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 form-group-animated" min="0"></td>
|
<td><input name="partidas[0][cantidad_tarifa]" type="number" step="0.0001" class="form-control" min="0"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
|
<select name="partidas[0][unidad_comercial_id]" class="form-select searchable">
|
||||||
<option value="">-- Unidad --</option>
|
<option value="">-- Unidad --</option>
|
||||||
@@ -333,8 +259,8 @@
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td><input name="partidas[0][valor_factura]" type="number" step="0.01" class="form-control valor-partida form-group-animated" min="0"></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 form-group-animated" min="0"></td>
|
<td><input name="partidas[0][peso_bruto]" type="number" step="0.0001" class="form-control" min="0"></td>
|
||||||
<td>
|
<td>
|
||||||
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
|
<select name="partidas[0][tasa_preferencial]" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
@@ -350,79 +276,75 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group-animated">
|
|
||||||
<button type="button" class="btn btn-secondary btn-sm mb-3 mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
<button type="button" class="btn btn-secondary btn-sm mb-3 mt-auto w-auto btn-animated" id="add-partida">➕ Agregar partida</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Activo -->
|
<!-- Activo -->
|
||||||
<div class="form-check mb-4 form-group-animated">
|
<div class="form-check mb-4">
|
||||||
<input id="status" value=1 name="status" type="hidden" <?= $factura['status']==1?'checked':'' ?>>
|
<input id="status" value=1 name="status" type="hidden" <?= $factura['status']==1?'checked':'' ?>>
|
||||||
<label for="status" class="hide form-check-label">Activo</label>
|
<label for="status" class="hide form-check-label">Activo</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Botones finales -->
|
|
||||||
<div class="col-12 text-end mt-4 form-group-animated"></div>
|
|
||||||
<button type="submit" class="btn btn-success mt-auto w-auto btn-animated">Actualizar</button>
|
<button type="submit" class="btn btn-success mt-auto w-auto btn-animated">Actualizar</button>
|
||||||
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
<a href="/IMPORTADORES/solicitud_importacion/lista" class="btn btn-secondary ms-2 mt-auto w-auto btn-animated">Cancelar</a>
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Choices.js JS -->
|
<!-- Choices.js JS -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js"></script>
|
<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/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 src="https://cdn.jsdelivr.net/npm/select2@4.1.0/dist/js/select2.min.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// ✅ 1. INICIALIZACIÓN PRINCIPAL
|
// ✅ 1. INICIALIZACIÓN PRINCIPAL
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Primero cargar proveedores, después inicializar otros selects
|
const proveedorActual = '<?= htmlspecialchars($proveedor_clave_actual ?? '') ?>';
|
||||||
cargarProveedores().then(() => {
|
console.log('📦 Proveedor actual:', proveedorActual);
|
||||||
// Inicializar Choices.js en todos los selects searchable DESPUÉS de cargar proveedores
|
|
||||||
|
cargarProveedores(proveedorActual).then(() => {
|
||||||
document.querySelectorAll('.searchable').forEach(el => {
|
document.querySelectorAll('.searchable').forEach(el => {
|
||||||
new Choices(el, {
|
// Destruir instancia previa si existe
|
||||||
|
if (el.choicesInstance) el.choicesInstance.destroy();
|
||||||
|
|
||||||
|
const instance = new Choices(el, {
|
||||||
searchEnabled: true,
|
searchEnabled: true,
|
||||||
itemSelectText: '',
|
itemSelectText: '',
|
||||||
shouldSort: false
|
shouldSort: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Guardar instancia
|
||||||
|
el.choicesInstance = instance;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ✅ 2. FUNCIÓN PARA CARGAR PROVEEDORES (CON PROMESA)
|
// ✅ 2. FUNCIÓN PARA CARGAR PROVEEDORES (CON PROMESA)
|
||||||
function cargarProveedores() {
|
function cargarProveedores(proveedorActual) {
|
||||||
const proveedorEl = document.getElementById('proveedor_clave');
|
const proveedorEl = document.getElementById('proveedor_id');
|
||||||
// Obtenemos la cadena con la ID del proveedor guardado
|
|
||||||
const proveedorActual = '<?= htmlspecialchars($proveedor_clave_actual ?? '') ?>';
|
|
||||||
|
|
||||||
return fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
return fetch('/IMPORTADORES/solicitud_importacion/ajax_proveedores')
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then(json => {
|
.then(json => {
|
||||||
// Limpiar el select
|
|
||||||
proveedorEl.innerHTML = '<option value="">-- Selecciona Proveedor --</option>';
|
proveedorEl.innerHTML = '<option value="">-- Selecciona Proveedor --</option>';
|
||||||
|
|
||||||
// Agregar todas las opciones
|
|
||||||
if (json.results && json.results.length > 0) {
|
|
||||||
json.results.forEach(item => {
|
json.results.forEach(item => {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
opt.value = item.id;
|
opt.value = item.id;
|
||||||
opt.textContent = item.text;
|
opt.textContent = item.text;
|
||||||
|
|
||||||
// Comparar forzando a cadena para que coincida con proveedorActual
|
if (String(item.id) === proveedorActual) {
|
||||||
if (String(item.id) === proveedorActual && proveedorActual !== '') {
|
|
||||||
opt.selected = true;
|
opt.selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
proveedorEl.appendChild(opt);
|
proveedorEl.appendChild(opt);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
// Forzar manualmente el value
|
||||||
|
proveedorEl.value = proveedorActual;
|
||||||
console.log('✅ Proveedores cargados. Proveedor actual:', proveedorActual);
|
console.log('✅ Proveedores cargados. Proveedor actual:', proveedorActual);
|
||||||
|
console.log('🧪 Select value actual (después de asignar):', proveedorEl.value);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error('❌ Error cargando proveedores:', err);
|
console.error('❌ Error cargando proveedores:', err);
|
||||||
@@ -453,7 +375,11 @@
|
|||||||
<td>
|
<td>
|
||||||
<select name="partidas[${idx}][tasa_preferencial]" class="form-select searchable">
|
<select name="partidas[${idx}][tasa_preferencial]" class="form-select searchable">
|
||||||
<option value="">-- Selecciona --</option>
|
<option value="">-- Selecciona --</option>
|
||||||
<option>General</option><option>TLC</option><option>PROSEC</option><option>ALADI</option><option>COMERCIALIZADORA</option>
|
<option>General</option>
|
||||||
|
<option>TLC</option>
|
||||||
|
<option>PROSEC</option>
|
||||||
|
<option>ALADI</option>
|
||||||
|
<option>COMERCIALIZADORA</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
<td class="hide"><input name="partidas[${idx}][precio_unitario]" type="number" class="form-control"></td>
|
<td class="hide"><input name="partidas[${idx}][precio_unitario]" type="number" class="form-control"></td>
|
||||||
@@ -716,67 +642,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Script para manejar las animaciones de validación
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const inputs = document.querySelectorAll('input.form-control, select.form_select');
|
|
||||||
const selects = document.querySelectorAll('select.form_select');
|
|
||||||
|
|
||||||
inputs.forEach(input => {
|
|
||||||
// Validación en tiempo real
|
|
||||||
input.addEventListener('input', function() {
|
|
||||||
if (this.checkValidity()) {
|
|
||||||
this.classList.remove('shake');
|
|
||||||
this.classList.add('valid');
|
|
||||||
} else {
|
|
||||||
this.classList.remove('valid');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Efecto shake en campos inválidos
|
|
||||||
input.addEventListener('invalid', function() {
|
|
||||||
this.classList.add('shake');
|
|
||||||
setTimeout(() => {
|
|
||||||
this.classList.remove('shake');
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Configurar selects
|
|
||||||
selects.forEach(select => {
|
|
||||||
select.addEventListener('change', function() {
|
|
||||||
updateSelectState(this);
|
|
||||||
});
|
|
||||||
updateSelectState(select);
|
|
||||||
});
|
|
||||||
|
|
||||||
function updateSelectState(select) {
|
|
||||||
select.setAttribute('value', select.value);
|
|
||||||
|
|
||||||
if (select.value && select.value !== '') {
|
|
||||||
select.classList.add('valid');
|
|
||||||
select.classList.remove('invalid');
|
|
||||||
} else {
|
|
||||||
select.classList.remove('valid');
|
|
||||||
if (select.hasAttribute('required') && select.closest('form')?.classList.contains('was-validated')) {
|
|
||||||
select.classList.add('invalid');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validación del formulario
|
|
||||||
document.getElementById('solicitudForm').addEventListener('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
let isValid = true;
|
|
||||||
inputs.forEach(input => {
|
|
||||||
if (!input.checkValidity()) {
|
|
||||||
input.classList.add('shake');
|
|
||||||
isValid = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -333,9 +333,6 @@
|
|||||||
|
|
||||||
// Aquí puedes enviar el formulario real
|
// Aquí puedes enviar el formulario real
|
||||||
form.submit();
|
form.submit();
|
||||||
} else {
|
|
||||||
// Mostrar mensaje de error
|
|
||||||
showNotification('Por favor, complete todos los campos obligatorios correctamente.', 'error');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user