Preparando proyecto para migración a repositorio MVE

This commit is contained in:
2025-10-23 08:48:00 -06:00
parent b1b9e4a77c
commit d0af739ce2
75 changed files with 15875 additions and 4022 deletions

View File

@@ -0,0 +1,303 @@
<?php
class ImportadorPedimentos {
private $conn;
private $estadisticas = [
'total_lineas' => 0,
'pedimentos_procesados' => 0,
'facturas_procesadas' => 0,
'partidas_procesadas' => 0,
'errores' => 0,
'duplicados' => 0
];
private $errores_detalle = [];
private $pedimentos_creados = [];
public function __construct($connection) {
$this->conn = $connection;
}
public function procesarArchivo($archivo_path, $validar_duplicados = true, $timestamp_importacion = null) {
$inicio_tiempo = time();
$nombre_archivo = basename($archivo_path);
if ($timestamp_importacion === null) {
$timestamp_importacion = date('Y-m-d H:i:s');
}
try {
$contenido = file_get_contents($archivo_path);
if ($contenido === false) {
throw new Exception("No se pudo leer el archivo");
}
// Convertir encoding si es necesario
if (!mb_check_encoding($contenido, 'UTF-8')) {
$contenido = mb_convert_encoding($contenido, 'UTF-8', 'ISO-8859-1');
}
$lineas = explode("\n", $contenido);
$this->estadisticas['total_lineas'] = count($lineas);
$pedimento_actual = null;
$facturas_pedimento = [];
$partidas_pedimento = [];
foreach ($lineas as $numero_linea => $linea) {
$linea = trim($linea);
if (empty($linea)) continue;
try {
$codigo = substr($linea, 0, 3);
switch ($codigo) {
case '500':
// Header - ignorar
break;
case '501':
// Si hay un pedimento anterior, procesarlo
if ($pedimento_actual) {
$this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
$facturas_pedimento = [];
$partidas_pedimento = [];
}
$pedimento_actual = $this->parsearLinea501Real($linea, $timestamp_importacion);
break;
case '505':
if ($pedimento_actual) {
$factura = $this->parsearLinea505Real($linea);
$facturas_pedimento[] = $factura;
}
break;
case '551':
if ($pedimento_actual) {
$partida = $this->parsearLinea551Real($linea);
$partidas_pedimento[] = $partida;
}
break;
}
} catch (Exception $e) {
$this->errores_detalle[] = "Línea " . ($numero_linea + 1) . ": " . $e->getMessage();
$this->estadisticas['errores']++;
}
}
// Procesar el último pedimento
if ($pedimento_actual) {
$this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
}
return [
'success' => true,
'estadisticas' => $this->estadisticas,
'errores' => $this->errores_detalle,
'pedimentos_creados' => $this->pedimentos_creados
];
} catch (Exception $e) {
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
private function parsearLinea501Real($linea, $timestamp_importacion) {
$campos = explode('|', $linea);
if (count($campos) < 10) {
throw new Exception("Formato inválido en línea 501");
}
return [
'numero_pedimento' => trim($campos[2]),
'patente' => trim($campos[1]),
'aduana' => trim($campos[3]),
'anio' => date('Y'),
'clave_documento' => trim($campos[5]),
'rfc_importador' => trim($campos[8]),
'fecha_creacion' => $timestamp_importacion,
'usuario_id' => $_SESSION['usuario_id']
];
}
private function parsearLinea505Real($linea) {
$campos = explode('|', $linea);
if (count($campos) < 12) {
throw new Exception("Formato inválido en línea 505");
}
return [
'numero_factura' => trim($campos[3]),
'fecha_factura' => $this->convertirFechaReal(trim($campos[2])),
'valor_dolares' => floatval(trim($campos[6])),
'valor_factura' => floatval(trim($campos[7])),
'cove' => trim($campos[3]),
'moneda' => trim($campos[5]),
'proveedor' => trim($campos[11])
];
}
private function parsearLinea551Real($linea) {
$campos = explode('|', $linea);
if (count($campos) < 12) {
throw new Exception("Formato inválido en línea 551");
}
static $contador = 1;
return [
'secuencia' => $contador++,
'fraccion_arancelaria' => trim($campos[2]) ?: 'PENDIENTE',
'descripcion' => trim($campos[5]) ?: 'DESCRIPCIÓN PENDIENTE',
'cantidad' => floatval(trim($campos[10])) ?: 1.0,
'unidad' => trim($campos[11]) ?: 'PZ',
'valor_unitario' => floatval(trim($campos[6])),
'peso_neto' => null,
'peso_bruto' => null
];
}
private function procesarPedimento($pedimento, $facturas, $partidas, $validar_duplicados) {
try {
if ($validar_duplicados && $this->existePedimento($pedimento['numero_pedimento'])) {
$this->estadisticas['duplicados']++;
return;
}
sqlsrv_begin_transaction($this->conn);
// Insertar pedimento
$sql = "INSERT INTO pedimentos (numero_pedimento, patente, aduana, anio, clave_documento,
rfc_importador, fecha_creacion, usuario_id, estado)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'activo'); SELECT SCOPE_IDENTITY() AS id;";
$params = [
$pedimento['numero_pedimento'],
$pedimento['patente'],
$pedimento['aduana'],
$pedimento['anio'],
$pedimento['clave_documento'],
$pedimento['rfc_importador'],
$pedimento['fecha_creacion'],
$pedimento['usuario_id']
];
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt === false) {
throw new Exception("Error al insertar pedimento");
}
sqlsrv_next_result($stmt);
sqlsrv_fetch($stmt);
$pedimento_id = sqlsrv_get_field($stmt, 0);
sqlsrv_free_stmt($stmt);
// Insertar facturas
foreach ($facturas as $factura) {
$sql = "INSERT INTO pedimento_facturas (pedimento_id, numero_factura, fecha_factura,
valor_dolares, valor_factura, cove, moneda, proveedor)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
$params = [
$pedimento_id,
$factura['numero_factura'],
$factura['fecha_factura'],
$factura['valor_dolares'],
$factura['valor_factura'],
$factura['cove'],
$factura['moneda'],
$factura['proveedor']
];
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt === false) {
throw new Exception("Error al insertar factura");
}
sqlsrv_free_stmt($stmt);
$this->estadisticas['facturas_procesadas']++;
}
// Insertar partidas
foreach ($partidas as $partida) {
$sql = "INSERT INTO pedimento_partidas (pedimento_id, secuencia, fraccion_arancelaria,
descripcion, cantidad, unidad, valor_unitario,
peso_neto, peso_bruto)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
$params = [
$pedimento_id,
$partida['secuencia'],
$partida['fraccion_arancelaria'],
$partida['descripcion'],
$partida['cantidad'],
$partida['unidad'],
$partida['valor_unitario'],
$partida['peso_neto'],
$partida['peso_bruto']
];
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt === false) {
throw new Exception("Error al insertar partida");
}
sqlsrv_free_stmt($stmt);
$this->estadisticas['partidas_procesadas']++;
}
sqlsrv_commit($this->conn);
$this->estadisticas['pedimentos_procesados']++;
$this->pedimentos_creados[] = $pedimento['numero_pedimento'];
} catch (Exception $e) {
sqlsrv_rollback($this->conn);
$this->errores_detalle[] = "Error procesando pedimento {$pedimento['numero_pedimento']}: " . $e->getMessage();
$this->estadisticas['errores']++;
}
}
private function existePedimento($numero_pedimento) {
$sql = "SELECT id FROM pedimentos WHERE numero_pedimento = ?";
$stmt = sqlsrv_query($this->conn, $sql, [$numero_pedimento]);
if ($stmt === false) {
return false;
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
sqlsrv_free_stmt($stmt);
return $row !== false;
}
private function convertirFechaReal($fecha_str) {
if (empty($fecha_str) || strlen($fecha_str) !== 8) {
return date('Y-m-d');
}
if (substr($fecha_str, 0, 2) === '20') {
$anio = substr($fecha_str, 0, 4);
$mes = substr($fecha_str, 4, 2);
$dia = substr($fecha_str, 6, 2);
} else {
$dia = substr($fecha_str, 0, 2);
$mes = substr($fecha_str, 2, 2);
$anio = substr($fecha_str, 4, 4);
}
if (checkdate($mes, $dia, $anio)) {
return "$anio-$mes-$dia";
}
return date('Y-m-d');
}
}
?>

View File

@@ -359,44 +359,16 @@ function ajax_lista()
$id_usuario = $_SESSION['usuario_id'];
$conn = getConnection();
// Obtener RFC del importador para filtrar solo sus pedimentos
$sqlImportador = "SELECT rfc FROM informacion_general WHERE id_usuario = ?";
$stmtImportador = sqlsrv_query($conn, $sqlImportador, [$id_usuario]);
if ($stmtImportador === false) {
echo json_encode([
"draw" => intval($_GET['draw'] ?? 0),
"recordsTotal" => 0,
"recordsFiltered" => 0,
"data" => [],
"error" => "Error al consultar información del importador"
]);
exit;
}
$importador = sqlsrv_fetch_array($stmtImportador, SQLSRV_FETCH_ASSOC);
if (!$importador) {
echo json_encode([
"draw" => intval($_GET['draw'] ?? 0),
"recordsTotal" => 0,
"recordsFiltered" => 0,
"data" => []
]);
exit;
}
// Parámetros de DataTables
$draw = intval($_GET['draw'] ?? 0);
$start = intval($_GET['start'] ?? 0);
$length = intval($_GET['length'] ?? 10);
$search = $_GET['search']['value'] ?? '';
// Total registros sin filtro
$sqlTotal = "SELECT COUNT(*) AS total FROM PREVIOS_COMPARTIDOS_WS WHERE ClienteRFC = ?";
$stmt = sqlsrv_query($conn, $sqlTotal, [$importador['rfc']]);
if ($stmt === false) {
// Total registros sin filtro en nuevas tablas
$sqlTotal = "SELECT COUNT(*) AS total FROM pedimentos WHERE usuario_id = ?";
$stmtTotal = sqlsrv_query($conn, $sqlTotal, [$id_usuario]);
if ($stmtTotal === false) {
echo json_encode([
"draw" => $draw,
"recordsTotal" => 0,
@@ -406,24 +378,21 @@ function ajax_lista()
]);
exit;
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
$recordsTotal = (int)($row['total'] ?? 0);
// Construir condiciones de filtro
$where = "ClienteRFC = ?";
$params = [$importador['rfc']];
$rowT = sqlsrv_fetch_array($stmtTotal, SQLSRV_FETCH_ASSOC);
$recordsTotal = (int)($rowT['total'] ?? 0);
// Filtro y búsqueda
$where = "p.usuario_id = ?";
$params = [$id_usuario];
if ($search !== '') {
$where .= " AND (Pedimento LIKE ? OR ClienteNombre LIKE ? OR ClavePed LIKE ?)";
$where .= " AND (p.numero_pedimento LIKE ? OR p.rfc_importador LIKE ? OR p.clave_documento LIKE ? OR p.patente LIKE ? OR p.aduana LIKE ?)";
$like = "%{$search}%";
$params = array_merge($params, [$like, $like, $like]);
$params = array_merge($params, [$like, $like, $like, $like, $like]);
}
// Total registros filtrados
$sqlFiltered = "SELECT COUNT(*) AS total FROM PREVIOS_COMPARTIDOS_WS WHERE $where";
// Total filtrado
$sqlFiltered = "SELECT COUNT(*) AS total FROM pedimentos p WHERE $where";
$stmtF = sqlsrv_query($conn, $sqlFiltered, $params);
if ($stmtF === false) {
echo json_encode([
"draw" => $draw,
@@ -434,34 +403,41 @@ function ajax_lista()
]);
exit;
}
$rowF = sqlsrv_fetch_array($stmtF, SQLSRV_FETCH_ASSOC);
$recordsFiltered = (int)($rowF['total'] ?? 0);
// Datos de la página
$sqlData = "SELECT IdPrevio, Pedimento, ClienteRFC, ClienteNombre, Timestamp, Status
FROM PREVIOS_COMPARTIDOS_WS
WHERE $where
ORDER BY Timestamp DESC
// Datos paginados
$sqlData = "SELECT p.id, p.numero_pedimento, p.rfc_importador, p.fecha_creacion, p.estado,
ig.nombre AS nombre_importador
FROM pedimentos p
LEFT JOIN informacion_general ig ON ig.id_usuario = p.usuario_id
WHERE $where
ORDER BY p.fecha_creacion DESC
OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
$params[] = $start;
$params[] = $length;
$stmtD = sqlsrv_query($conn, $sqlData, $params);
$paramsData = array_merge($params, [$start, $length]);
$stmtD = sqlsrv_query($conn, $sqlData, $paramsData);
$data = [];
if ($stmtD !== false) {
while ($r = sqlsrv_fetch_array($stmtD, SQLSRV_FETCH_ASSOC)) {
$timestamp = $r['Timestamp'] instanceof DateTime ? $r['Timestamp']->format('Y-m-d H:i:s') : '';
$status_text = $r['Status'] == 1 ? 'Activo' : 'Inactivo';
$fecha = '';
if (isset($r['fecha_creacion'])) {
if ($r['fecha_creacion'] instanceof DateTime) {
$fecha = $r['fecha_creacion']->format('Y-m-d H:i:s');
} elseif (is_array($r['fecha_creacion']) && isset($r['fecha_creacion']['date'])) {
// Por si viene como array (SQLSRV con print_r)
$fecha = substr($r['fecha_creacion']['date'], 0, 19);
}
}
$estado = strtolower((string)$r['estado']) === 'activo' || $r['estado'] === 1 ? 'Activo' : 'Inactivo';
$data[] = [
$r['IdPrevio'],
$r['Pedimento'],
$r['ClienteRFC'],
$r['ClienteNombre'],
$timestamp,
$status_text
$r['id'],
$r['numero_pedimento'],
$r['rfc_importador'],
$r['nombre_importador'] ?? '',
$fecha,
$estado
];
}
}
@@ -555,4 +531,157 @@ function buscar_pedimentos()
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($pedimentos, JSON_UNESCAPED_UNICODE);
exit;
}
/**
* Devuelve información general del pedimento (cabecera)
* GET /IMPORTADORES/catalogo_pedimentos/ajax_pedimento?id=123
*/
function ajax_pedimento()
{
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
$id_usuario = $_SESSION['usuario_id'];
$pedimento_id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($pedimento_id <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'ID inválido']);
exit;
}
$conn = getConnection();
$sql = "SELECT p.id, p.numero_pedimento, p.patente, p.aduana, p.anio, p.clave_documento,
p.rfc_importador, p.fecha_creacion, p.estado
FROM pedimentos p
WHERE p.id = ? AND p.usuario_id = ?";
$stmt = sqlsrv_query($conn, $sql, [$pedimento_id, $id_usuario]);
if ($stmt === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
exit;
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
sqlsrv_free_stmt($stmt);
if (!$row) {
echo json_encode(['success' => false, 'message' => 'No encontrado']);
exit;
}
// Formatear fecha si es DateTime
if (isset($row['fecha_creacion']) && $row['fecha_creacion'] instanceof DateTime) {
$row['fecha_creacion'] = $row['fecha_creacion']->format('Y-m-d H:i:s');
}
echo json_encode(['success' => true, 'data' => $row]);
exit;
}
/**
* Devuelve las facturas del pedimento
* GET /IMPORTADORES/catalogo_pedimentos/ajax_facturas?pedimento_id=123
*/
function ajax_facturas()
{
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
$id_usuario = $_SESSION['usuario_id'];
$pedimento_id = isset($_GET['pedimento_id']) ? (int)$_GET['pedimento_id'] : 0;
if ($pedimento_id <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'ID inválido']);
exit;
}
$conn = getConnection();
// Verificar propiedad
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_usuario]);
$own = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$own) {
http_response_code(404);
echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
exit;
}
$sql = "SELECT id, numero_factura, fecha_factura, valor_dolares, valor_factura, cove, moneda, proveedor
FROM pedimento_facturas
WHERE pedimento_id = ?
ORDER BY fecha_factura ASC, id ASC";
$stmt = sqlsrv_query($conn, $sql, [$pedimento_id]);
if ($stmt === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
exit;
}
$items = [];
while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
if ($r['fecha_factura'] instanceof DateTime) {
$r['fecha_factura'] = $r['fecha_factura']->format('Y-m-d');
}
$items[] = $r;
}
sqlsrv_free_stmt($stmt);
echo json_encode(['success' => true, 'data' => $items]);
exit;
}
/**
* Devuelve las partidas del pedimento
* GET /IMPORTADORES/catalogo_pedimentos/ajax_partidas?pedimento_id=123
*/
function ajax_partidas()
{
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
$id_usuario = $_SESSION['usuario_id'];
$pedimento_id = isset($_GET['pedimento_id']) ? (int)$_GET['pedimento_id'] : 0;
if ($pedimento_id <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'ID inválido']);
exit;
}
$conn = getConnection();
// Verificar propiedad
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_usuario]);
$own = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$own) {
http_response_code(404);
echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
exit;
}
$sql = "SELECT id, secuencia, fraccion_arancelaria, descripcion, cantidad, unidad, valor_unitario, peso_neto, peso_bruto
FROM pedimento_partidas
WHERE pedimento_id = ?
ORDER BY secuencia ASC, id ASC";
$stmt = sqlsrv_query($conn, $sql, [$pedimento_id]);
if ($stmt === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
exit;
}
$items = [];
while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$items[] = $r;
}
sqlsrv_free_stmt($stmt);
echo json_encode(['success' => true, 'data' => $items]);
exit;
}

170
app/controllers/cove.php Normal file
View File

@@ -0,0 +1,170 @@
<?php
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/session.php';
/**
* GET /IMPORTADORES/cove/ajax_estado_facturas?pedimento_id=123
* Devuelve estado de COVE por factura del pedimento actual del usuario.
*/
function ajax_estado_facturas()
{
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
$usuario_id = (int)$_SESSION['usuario_id'];
$pedimento_id = isset($_GET['pedimento_id']) ? (int)$_GET['pedimento_id'] : 0;
if ($pedimento_id <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'ID inválido']);
exit;
}
$conn = getConnection();
// Verificar propiedad del pedimento
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $usuario_id]);
$own = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$own) {
http_response_code(404);
echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
exit;
}
$sql = "SELECT f.id AS factura_id,
CASE WHEN cr.id IS NULL THEN 0 ELSE 1 END AS respondido,
cr.estado AS estado,
cr.fecha_actualizacion AS fecha
FROM pedimento_facturas f
LEFT JOIN cove_respuestas cr
ON cr.factura_id = f.id AND cr.usuario_id = ?
WHERE f.pedimento_id = ?
ORDER BY f.id";
$stmt = sqlsrv_query($conn, $sql, [$usuario_id, $pedimento_id]);
if ($stmt === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
exit;
}
$data = [];
while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
if (isset($r['fecha']) && $r['fecha'] instanceof DateTime) {
$r['fecha'] = $r['fecha']->format('Y-m-d H:i:s');
}
$data[] = $r;
}
sqlsrv_free_stmt($stmt);
echo json_encode(['success' => true, 'data' => $data]);
exit;
}
/**
* POST /IMPORTADORES/cove/ajax_guardar_respuestas
* Guarda/actualiza respuestas de COVE para una factura concreta.
* Body: pedimento_id, factura_id, respuestas (JSON string), estado (opcional)
*/
function ajax_guardar_respuestas()
{
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
$usuario_id = (int)$_SESSION['usuario_id'];
$pedimento_id = isset($_POST['pedimento_id']) ? (int)$_POST['pedimento_id'] : 0;
$factura_id = isset($_POST['factura_id']) ? (int)$_POST['factura_id'] : 0;
$respuestas = $_POST['respuestas'] ?? '{}';
$estado = $_POST['estado'] ?? 'respondido';
if ($pedimento_id <= 0 || $factura_id <= 0) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
exit;
}
$conn = getConnection();
// Verificar propiedad del pedimento
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $usuario_id]);
$own = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$own) {
http_response_code(404);
echo json_encode(['success' => false, 'message' => 'Pedimento no encontrado']);
exit;
}
// Upsert manual: si existe update, si no insert
$sel = sqlsrv_query($conn, "SELECT id FROM cove_respuestas WHERE factura_id = ? AND usuario_id = ?", [$factura_id, $usuario_id]);
$row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null;
if ($sel) sqlsrv_free_stmt($sel);
if ($row) {
$sql = "UPDATE cove_respuestas
SET respuestas = ?, estado = ?, fecha_actualizacion = SYSDATETIME()
WHERE id = ?";
$stmt = sqlsrv_query($conn, $sql, [$respuestas, $estado, $row['id']]);
} else {
$sql = "INSERT INTO cove_respuestas (pedimento_id, factura_id, usuario_id, respuestas, estado, fecha_creacion)
VALUES (?, ?, ?, ?, ?, SYSDATETIME())";
$stmt = sqlsrv_query($conn, $sql, [$pedimento_id, $factura_id, $usuario_id, $respuestas, $estado]);
}
if ($stmt === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'No se pudieron guardar las respuestas']);
exit;
}
echo json_encode(['success' => true]);
exit;
}
// Estado agregado por pedimento: total de facturas vs respondidas/solicitadas
function ajax_estado_pedimentos()
{
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
exit;
}
$usuario_id = (int)$_SESSION['usuario_id'];
$conn = getConnection();
$sql = "
SELECT p.id AS pedimento_id,
COUNT(f.id) AS total_facturas,
SUM(CASE WHEN cr.estado IN ('respondido','solicitado') THEN 1 ELSE 0 END) AS respondidas
FROM pedimentos p
LEFT JOIN pedimento_facturas f ON f.pedimento_id = p.id
LEFT JOIN cove_respuestas cr ON cr.factura_id = f.id AND cr.usuario_id = p.usuario_id
WHERE p.usuario_id = ?
GROUP BY p.id
";
$stmt = sqlsrv_query($conn, $sql, [$usuario_id]);
if ($stmt === false) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Error de base de datos']);
exit;
}
$data = [];
while ($r = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$total = (int)($r['total_facturas'] ?? 0);
$resp = (int)($r['respondidas'] ?? 0);
$completo = ($total > 0 && $resp >= $total) ? 1 : 0;
$data[] = [
'pedimento_id' => (int)$r['pedimento_id'],
'total_facturas' => $total,
'respondidas' => $resp,
'completo' => $completo
];
}
sqlsrv_free_stmt($stmt);
echo json_encode(['success' => true, 'data' => $data]);
exit;
}

View File

@@ -0,0 +1,22 @@
<?php
// Debug para ver rutas
echo "<h3>Información de rutas del servidor:</h3>";
echo "<p><strong>DOCUMENT_ROOT:</strong> " . $_SERVER['DOCUMENT_ROOT'] . "</p>";
echo "<p><strong>SCRIPT_NAME:</strong> " . $_SERVER['SCRIPT_NAME'] . "</p>";
echo "<p><strong>REQUEST_URI:</strong> " . $_SERVER['REQUEST_URI'] . "</p>";
echo "<p><strong>HTTP_HOST:</strong> " . $_SERVER['HTTP_HOST'] . "</p>";
echo "<p><strong>__FILE__:</strong> " . __FILE__ . "</p>";
echo "<p><strong>__DIR__:</strong> " . __DIR__ . "</p>";
// Verificar si los archivos existen
$test_file = __DIR__ . '/test_connection.php';
$import_file = __DIR__ . '/importar_pedimentos.php';
echo "<h3>Verificación de archivos:</h3>";
echo "<p><strong>test_connection.php:</strong> " . (file_exists($test_file) ? '✅ Existe' : '❌ No existe') . "</p>";
echo "<p><strong>importar_pedimentos.php:</strong> " . (file_exists($import_file) ? '✅ Existe' : '❌ No existe') . "</p>";
echo "<h3>URLs sugeridas:</h3>";
$base_url = "http" . (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] === "on" ? "s" : "") . "://" . $_SERVER["HTTP_HOST"];
echo "<p><strong>Test URL:</strong> <a href='{$base_url}/IMPORTADORES/app/controllers/test_connection.php' target='_blank'>{$base_url}/IMPORTADORES/app/controllers/test_connection.php</a></p>";
?>

View File

@@ -3,6 +3,29 @@ require_once __DIR__ . '/../helpers/session.php';
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/env.php';
// Formatea el pedimento como: YY-AA-PPPP-PPPPPPP
function format_pedimento_display($anio, $aduana, $patente, $numero)
{
$yy = substr((string)$anio, -2);
$ad = substr(preg_replace('/\D/', '', (string)$aduana), 0, 2);
$pat = str_pad(preg_replace('/\D/', '', (string)$patente), 4, '0', STR_PAD_LEFT);
$num = str_pad(preg_replace('/\D/', '', (string)$numero), 7, '0', STR_PAD_LEFT);
$yy = $yy !== '' ? $yy : '00';
$ad = str_pad($ad, 2, '0', STR_PAD_LEFT);
return "$yy-$ad-$pat-$num";
}
function ensure_expediente_schema($conn) {
// Agregar columna pedimento_id si no existe (compatibilidad con esquema nuevo)
$chk = sqlsrv_query($conn, "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'expediente_archivos' AND COLUMN_NAME = 'pedimento_id'");
$exists = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$exists) {
@sqlsrv_query($conn, "ALTER TABLE expediente_archivos ADD pedimento_id INT NULL");
@sqlsrv_query($conn, "CREATE INDEX IX_expediente_archivos_pedimento ON expediente_archivos(pedimento_id)");
}
}
// Mostrar tabla de expedientes
function index()
{
@@ -12,29 +35,50 @@ function index()
}
$conn = getConnection();
ensure_expediente_schema($conn);
$id_importador = $_SESSION['usuario_id'];
$sql = "SELECT
sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave,
COUNT(ea.id) AS total_archivos,
ISNULL(SUM(ea.tamano_archivo), 0) AS total_tamano
FROM solicitud_importacion_factura sif
LEFT JOIN expediente_archivos ea
ON ea.id_solicitud = sif.id_solicitud
WHERE sif.numero_pedimento IS NOT NULL
AND sif.id_importador = ?
AND sif.status > 0
GROUP BY sif.id_solicitud, sif.numero_pedimento, sif.fecha_factura, sif.aduana, sif.proveedor_clave
ORDER BY sif.fecha_factura DESC
";
// Nuevo origen: pedimentos (cabecera) + facturas para fecha/proveedor + archivos por pedimento
$sql = "
WITH fact AS (
SELECT
f.pedimento_id,
MAX(f.fecha_factura) AS fecha_factura,
MIN(COALESCE(NULLIF(LTRIM(RTRIM(f.proveedor)), ''), '-')) AS proveedor
FROM pedimento_facturas f
GROUP BY f.pedimento_id
), arch AS (
SELECT pedimento_id, COUNT(*) AS total_archivos, ISNULL(SUM(tamano_archivo), 0) AS total_tamano
FROM expediente_archivos
WHERE pedimento_id IS NOT NULL
GROUP BY pedimento_id
)
SELECT
p.id AS pedimento_id,
p.numero_pedimento,
p.patente,
p.aduana,
p.anio,
f.fecha_factura,
f.proveedor,
ISNULL(a.total_archivos, 0) AS total_archivos,
ISNULL(a.total_tamano, 0) AS total_tamano
FROM pedimentos p
LEFT JOIN fact f ON f.pedimento_id = p.id
LEFT JOIN arch a ON a.pedimento_id = p.id
WHERE p.usuario_id = ?
ORDER BY COALESCE(f.fecha_factura, p.fecha_creacion) DESC, p.id DESC
";
$stmt = sqlsrv_query($conn, $sql, [$id_importador]);
$expedientes = [];
if ($stmt) {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$row['pedimento_display'] = format_pedimento_display($row['anio'] ?? '', $row['aduana'] ?? '', $row['patente'] ?? '', $row['numero_pedimento'] ?? '');
$expedientes[] = $row;
}
sqlsrv_free_stmt($stmt);
}
include __DIR__ . '/../../views/expediente/index.php';
@@ -45,27 +89,50 @@ function subir($id_solicitud)
include __DIR__ . '/../../views/expediente/subir.php';
}
// Vista subir para pedimento nuevo
function subir_pedimento($pedimento_id)
{
if (!isset($_SESSION['usuario_id'])) { header('Location: /IMPORTADORES/login'); exit; }
$conn = getConnection();
// Validar propiedad del pedimento
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $_SESSION['usuario_id']]);
if (!$chk || !sqlsrv_fetch($chk)) { http_response_code(403); echo "No autorizado"; exit; }
if ($chk) sqlsrv_free_stmt($chk);
$GLOBALS['pedimento_id'] = (int)$pedimento_id;
include __DIR__ . '/../../views/expediente/subir.php';
}
function subir_handler()
{
if (!isset($_POST['id_solicitud']) || !isset($_FILES['archivos']) || !isset($_SESSION['usuario_id'])) {
die("❌ Solicitud inválida.");
}
if (!isset($_FILES['archivos']) || !isset($_SESSION['usuario_id'])) { die("❌ Solicitud inválida."); }
$conn = getConnection();
ensure_expediente_schema($conn);
$id_solicitud = (int) $_POST['id_solicitud'];
$id_importador = $_SESSION['usuario_id'];
// Validar propiedad de la solicitud
$validStmt = sqlsrv_query($conn, "SELECT 1 FROM solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ?", [$id_solicitud, $id_importador]);
if (!sqlsrv_fetch($validStmt)) {
die("❌ No tienes permisos para esta solicitud.");
$id_solicitud = isset($_POST['id_solicitud']) ? (int) $_POST['id_solicitud'] : null;
$pedimento_id = isset($_POST['pedimento_id']) ? (int) $_POST['pedimento_id'] : null;
if ($pedimento_id) {
// Validar propiedad del pedimento
$validStmt = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_importador]);
if (!$validStmt || !sqlsrv_fetch($validStmt)) { die("❌ No tienes permisos para este pedimento."); }
if ($validStmt) sqlsrv_free_stmt($validStmt);
} elseif ($id_solicitud) {
// Validar propiedad de la solicitud (legacy)
$validStmt = sqlsrv_query($conn, "SELECT 1 FROM solicitud_importacion_factura WHERE id_solicitud = ? AND id_importador = ?", [$id_solicitud, $id_importador]);
if (!$validStmt || !sqlsrv_fetch($validStmt)) { die("❌ No tienes permisos para esta solicitud."); }
if ($validStmt) sqlsrv_free_stmt($validStmt);
} else {
die("❌ Falta identificador de pedimento.");
}
$archivos = $_FILES['archivos'];
$usuario = $_SESSION['usuario_nombre'] ?? 'sistema';
$uploadDir = __DIR__ . '/../../uploads/expedientes/' . $id_solicitud;
$folderKey = $pedimento_id ? ('pedimento_' . $pedimento_id) : ('solicitud_' . $id_solicitud);
$uploadDir = __DIR__ . '/../../uploads/expedientes/' . $folderKey;
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0775, true);
}
@@ -79,19 +146,29 @@ function subir_handler()
move_uploaded_file($archivos['tmp_name'][$i], $rutaFinal);
$rutaDb = "uploads/expedientes/$id_solicitud/$nombreSeguro";
$rutaDb = "uploads/expedientes/$folderKey/$nombreSeguro";
$tamanoKb = round(filesize($rutaFinal) / 1024, 2);
$tipoArchivo = mime_content_type($rutaFinal);
$sql = "INSERT INTO expediente_archivos
(id_solicitud, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por)
VALUES (?, ?, ?, ?, ?, ?)
";
$params = [$id_solicitud, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario];
if ($pedimento_id) {
$sql = "INSERT INTO expediente_archivos
(pedimento_id, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por)
VALUES (?, ?, ?, ?, ?, ?)";
$params = [$pedimento_id, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario];
} else {
$sql = "INSERT INTO expediente_archivos
(id_solicitud, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por)
VALUES (?, ?, ?, ?, ?, ?)";
$params = [$id_solicitud, $nombreOriginal, $rutaDb, $tipoArchivo, $tamanoKb, $usuario];
}
sqlsrv_query($conn, $sql, $params);
}
header("Location: /IMPORTADORES/expediente/ver/$id_solicitud");
if ($pedimento_id) {
header("Location: /IMPORTADORES/expediente/ver_pedimento/$pedimento_id");
} else {
header("Location: /IMPORTADORES/expediente/ver/$id_solicitud");
}
exit;
}
@@ -119,6 +196,51 @@ function ver($id_solicitud)
}
}
$GLOBALS['pedimento'] = null; // vista usa variable opcional
include __DIR__ . '/../../views/expediente/ver.php';
}
function ver_pedimento($pedimento_id)
{
if (!isset($_SESSION['usuario_id'])) {
header('Location: /IMPORTADORES/login');
exit;
}
$conn = getConnection();
ensure_expediente_schema($conn);
$id_importador = $_SESSION['usuario_id'];
// Validar propiedad
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_importador]);
if (!$chk || !sqlsrv_fetch($chk)) { http_response_code(404); echo "No autorizado o no encontrado"; exit; }
if ($chk) sqlsrv_free_stmt($chk);
// Datos del pedimento para cabecera
$stmtPed = sqlsrv_query($conn, "SELECT id, numero_pedimento, patente, aduana, anio, clave_documento, rfc_importador, fecha_creacion FROM pedimentos WHERE id = ?", [$pedimento_id]);
$pedimento = $stmtPed ? sqlsrv_fetch_array($stmtPed, SQLSRV_FETCH_ASSOC) : null;
if ($stmtPed) sqlsrv_free_stmt($stmtPed);
if ($pedimento) {
$pedimento['pedimento_display'] = format_pedimento_display($pedimento['anio'] ?? '', $pedimento['aduana'] ?? '', $pedimento['patente'] ?? '', $pedimento['numero_pedimento'] ?? '');
}
$sql = "SELECT * FROM expediente_archivos WHERE pedimento_id = ? ORDER BY creado_en DESC";
$stmt = sqlsrv_query($conn, $sql, [$pedimento_id]);
$archivos = [];
if ($stmt) {
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
if (isset($row['creado_en']) && is_string($row['creado_en'])) {
$row['creado_en'] = new DateTime($row['creado_en']);
}
$archivos[] = $row;
}
sqlsrv_free_stmt($stmt);
}
$GLOBALS['pedimento_id'] = (int)$pedimento_id;
$GLOBALS['pedimento'] = $pedimento;
include __DIR__ . '/../../views/expediente/ver.php';
}
@@ -131,9 +253,24 @@ function ver_archivo($id_archivo)
$conn = getConnection();
$sql = "SELECT ea.*, sif.id_importador FROM expediente_archivos ea JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud WHERE ea.id = ?";
$stmt = sqlsrv_query($conn, $sql, [$id_archivo]);
$archivo = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
ensure_expediente_schema($conn);
// Intentar resolver por pedimento (nuevo) y si no, por solicitud (legacy)
$sql = "SELECT ea.*, p.usuario_id AS id_importador
FROM expediente_archivos ea
JOIN pedimentos p ON p.id = ea.pedimento_id
WHERE ea.id = ? AND ea.pedimento_id IS NOT NULL";
$stmt = sqlsrv_query($conn, $sql, [$id_archivo]);
$archivo = $stmt ? sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) : null;
if ($stmt) sqlsrv_free_stmt($stmt);
if (!$archivo) {
$sqlL = "SELECT ea.*, sif.id_importador
FROM expediente_archivos ea
JOIN solicitud_importacion_factura sif ON sif.id_solicitud = ea.id_solicitud
WHERE ea.id = ?";
$stmtL = sqlsrv_query($conn, $sqlL, [$id_archivo]);
$archivo = $stmtL ? sqlsrv_fetch_array($stmtL, SQLSRV_FETCH_ASSOC) : null;
if ($stmtL) sqlsrv_free_stmt($stmtL);
}
if (!$archivo || $archivo['id_importador'] != $_SESSION['usuario_id']) {
http_response_code(403);
@@ -224,4 +361,50 @@ function descargar_zip($id_solicitud)
readfile($zip_file);
unlink($zip_file);
exit;
}
function descargar_zip_pedimento($pedimento_id)
{
if (!isset($_SESSION['usuario_id'])) {
http_response_code(403);
echo "No autorizado.";
exit;
}
$conn = getConnection();
ensure_expediente_schema($conn);
$id_importador = $_SESSION['usuario_id'];
// Validar propiedad
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos WHERE id = ? AND usuario_id = ?", [$pedimento_id, $id_importador]);
if (!$chk || !sqlsrv_fetch($chk)) { http_response_code(404); echo "No autorizado"; exit; }
if ($chk) sqlsrv_free_stmt($chk);
$stmt = sqlsrv_query($conn, "SELECT nombre_archivo, ruta_archivo FROM expediente_archivos WHERE pedimento_id = ?", [$pedimento_id]);
if (!$stmt) { http_response_code(500); echo "Error al consultar archivos."; exit; }
$archivos = [];
while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC)) {
$ruta_absoluta = __DIR__ . '/../../' . $row['ruta_archivo'];
if (file_exists($ruta_absoluta)) {
$archivos[] = [ 'ruta' => $ruta_absoluta, 'nombre' => $row['nombre_archivo'] ];
}
}
sqlsrv_free_stmt($stmt);
if (empty($archivos)) { http_response_code(404); echo "No hay archivos válidos para comprimir."; exit; }
$zip_file = tempnam(sys_get_temp_dir(), 'expediente_') . '.zip';
$zip = new ZipArchive();
if ($zip->open($zip_file, ZipArchive::CREATE) !== true) { http_response_code(500); echo "No se pudo crear el archivo ZIP."; exit; }
foreach ($archivos as $a) { $zip->addFile($a['ruta'], $a['nombre']); }
$zip->close();
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="expediente_pedimento_' . $pedimento_id . '.zip"');
header('Content-Length: ' . filesize($zip_file));
readfile($zip_file);
unlink($zip_file);
exit;
}

View File

@@ -142,20 +142,22 @@ function obtenerCatalogosVisibles($idUsuario)
function obtenerIconoCatalogo($nombre)
{
$iconos = [
'Locaciones' => '📍',
'Vinculación' => '🔗',
'Transportistas' => '🚚',
'Transportes' => '🚛',
'Choferes' => '👨‍✈️',
'Proveedores' => '🏭',
'Productos frecuentes' => '',
'Solicitudes importación' => '📄',
'Expediente electrónico' => '📁',
'Configuración' => '⚙️',
'Cerrar sesión' => '🚪'
'Locaciones' => 'fas fa-map-marker-alt',
'Vinculación' => 'fas fa-link',
'Transportistas' => 'fas fa-truck',
'Transportes' => 'fas fa-shipping-fast',
'Choferes' => 'fas fa-user-tie',
'Proveedores' => 'fas fa-industry',
'Productos frecuentes' => 'fas fa-star',
'Solicitudes importación' => 'fas fa-file-alt',
'Expediente electrónico' => 'fas fa-folder',
'Configuración' => 'fas fa-cog',
'Cerrar sesión' => 'fas fa-sign-out-alt',
'Agencias' => 'fas fa-building',
'Importadores' => 'fas fa-boxes'
];
return $iconos[$nombre] ?? '📁';
return $iconos[$nombre] ?? 'fas fa-folder';
}
// Función para el dashboard del importador

View File

@@ -0,0 +1,636 @@
<?php
session_start();
require_once __DIR__ . '/../config/database.php';
// Headers para AJAX
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
// Log para debugging
error_log("=== INICIO IMPORTACIÓN ===");
error_log("Usuario ID en sesión: " . (isset($_SESSION['usuario_id']) ? $_SESSION['usuario_id'] : 'NO_USUARIO'));
error_log("Tipo usuario: " . (isset($_SESSION['tipo_usuario']) ? $_SESSION['tipo_usuario'] : 'NO_TIPO'));
error_log("Método: " . $_SERVER['REQUEST_METHOD']);
error_log("Archivos recibidos: " . print_r($_FILES, true));
// Verificar que el usuario esté logueado
if (!isset($_SESSION['usuario_id'])) {
error_log("ERROR: Usuario no autenticado - no hay usuario_id en sesión");
http_response_code(401);
echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
exit;
}
// Verificar que sea una petición POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['success' => false, 'message' => 'Método no permitido']);
exit;
}
// Verificar que se haya subido un archivo
if (!isset($_FILES['archivo']) || $_FILES['archivo']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => 'No se ha recibido ningún archivo válido']);
exit;
}
class ImportadorPedimentos {
private $conn;
private $estadisticas = [
'total_lineas' => 0,
'pedimentos_procesados' => 0,
'facturas_procesadas' => 0,
'partidas_procesadas' => 0,
'errores' => 0,
'duplicados' => 0
];
private $errores_detalle = [];
private $pedimentos_creados = [];
public function __construct($connection) {
$this->conn = $connection;
}
public function procesarArchivo($archivo_path, $validar_duplicados = true) {
$inicio_tiempo = time();
$nombre_archivo = basename($archivo_path);
try {
$contenido = file_get_contents($archivo_path);
if ($contenido === false) {
throw new Exception("No se pudo leer el archivo");
}
// Convertir encoding si es necesario (muchos archivos julianos usan Latin1)
if (!mb_check_encoding($contenido, 'UTF-8')) {
$contenido = mb_convert_encoding($contenido, 'UTF-8', 'ISO-8859-1');
}
$lineas = explode("\n", $contenido);
$this->estadisticas['total_lineas'] = count($lineas);
$pedimento_actual = null;
$facturas_pedimento = [];
$partidas_pedimento = [];
foreach ($lineas as $numero_linea => $linea) {
$linea = trim($linea);
if (empty($linea)) continue;
try {
$codigo = substr($linea, 0, 3);
switch ($codigo) {
case '500':
// Línea de header - ignorar por ahora
break;
case '501':
// Si hay un pedimento anterior, procesarlo
if ($pedimento_actual) {
$this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
$facturas_pedimento = [];
$partidas_pedimento = [];
}
$pedimento_actual = $this->parsearLinea501Real($linea);
break;
case '505':
if ($pedimento_actual) {
try {
$factura = $this->parsearLinea505Real($linea);
$facturas_pedimento[] = $factura;
error_log("Factura 505 procesada exitosamente: " . $factura['numero_factura']);
} catch (Exception $e) {
error_log("ERROR procesando línea 505: " . $e->getMessage());
error_log("Línea problemática: " . $linea);
$this->estadisticas['errores']++;
// Continuar con la siguiente línea
}
}
break;
case '551':
if ($pedimento_actual) {
try {
$partida = $this->parsearLinea551Real($linea);
$partidas_pedimento[] = $partida;
error_log("Partida 551 procesada exitosamente: secuencia " . $partida['secuencia']);
} catch (Exception $e) {
error_log("ERROR procesando línea 551: " . $e->getMessage());
error_log("Línea problemática: " . $linea);
$this->estadisticas['errores']++;
// Continuar con la siguiente línea en lugar de fallar completamente
}
}
break;
case '506':
case '509':
case '510':
case '511':
case '553':
case '554':
case '556':
case '557':
case '558':
case '800':
case '801':
// Otros códigos del formato real - ignorar por ahora
break;
}
} catch (Exception $e) {
$this->errores_detalle[] = "Línea " . ($numero_linea + 1) . ": " . $e->getMessage();
$this->estadisticas['errores']++;
}
}
// Procesar el último pedimento
if ($pedimento_actual) {
$this->procesarPedimento($pedimento_actual, $facturas_pedimento, $partidas_pedimento, $validar_duplicados);
}
// Registrar log de importación
$tiempo_procesamiento = time() - $inicio_tiempo;
$this->registrarLog($nombre_archivo, $tiempo_procesamiento,
count($this->errores_detalle) > 0 ? 'con_errores' : 'exitoso');
return [
'success' => true,
'estadisticas' => $this->estadisticas,
'errores' => $this->errores_detalle,
'pedimentos_creados' => $this->pedimentos_creados
];
} catch (Exception $e) {
// Registrar log de error
$tiempo_procesamiento = time() - $inicio_tiempo;
$this->registrarLog($nombre_archivo, $tiempo_procesamiento, 'fallido', $e->getMessage());
return [
'success' => false,
'message' => $e->getMessage()
];
}
}
private function registrarLog($archivo_nombre, $tiempo_procesamiento, $estado, $error_mensaje = null) {
try {
$sql = "INSERT INTO importacion_logs (
usuario_id, archivo_nombre, total_lineas, pedimentos_procesados,
facturas_procesadas, partidas_procesadas, errores, duplicados,
tiempo_procesamiento, estado, detalles_errores
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$detalles_errores = null;
if (!empty($this->errores_detalle)) {
$detalles_errores = implode("\n", $this->errores_detalle);
} else if ($error_mensaje) {
$detalles_errores = $error_mensaje;
}
$params = [
isset($_SESSION['usuario_id']) ? $_SESSION['usuario_id'] : null,
$archivo_nombre,
$this->estadisticas['total_lineas'],
$this->estadisticas['pedimentos_procesados'],
$this->estadisticas['facturas_procesadas'],
$this->estadisticas['partidas_procesadas'],
$this->estadisticas['errores'],
$this->estadisticas['duplicados'],
$tiempo_procesamiento,
$estado,
$detalles_errores
];
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt) {
sqlsrv_free_stmt($stmt);
}
} catch (Exception $e) {
// No hacer nada si falla el log, no queremos interrumpir el proceso principal
}
}
private function parsearLinea501($linea) {
// Formato: 501|numero_pedimento|patente|aduana|anio|clave_documento|rfc_importador|...
$campos = explode('|', $linea);
if (count($campos) < 7) {
throw new Exception("Formato inválido en línea 501");
}
return [
'numero_pedimento' => trim($campos[1]),
'patente' => trim($campos[2]),
'aduana' => trim($campos[3]),
'anio' => trim($campos[4]),
'clave_documento' => trim($campos[5]),
'rfc_importador' => trim($campos[6]),
'fecha_creacion' => date('Y-m-d H:i:s'),
'usuario_id' => $_SESSION['usuario_id']
];
}
private function parsearLinea501Real($linea) {
// Formato real: 501|patente|numero_pedimento|aduana|tipo|clave_documento|aduana2||rfc_importador|nombre_importador|...
$campos = explode('|', $linea);
if (count($campos) < 10) {
throw new Exception("Formato inválido en línea 501 real - campos insuficientes: " . count($campos));
}
error_log("Parseando 501 real: " . $linea);
error_log("Campos: " . print_r(array_slice($campos, 0, 10), true));
return [
'numero_pedimento' => trim($campos[2]), // Campo 2: numero de pedimento
'patente' => trim($campos[1]), // Campo 1: patente
'aduana' => trim($campos[3]), // Campo 3: aduana
'anio' => date('Y'), // Usar año actual
'clave_documento' => trim($campos[5]), // Campo 5: clave documento
'rfc_importador' => trim($campos[8]), // Campo 8: RFC importador
'fecha_creacion' => date('Y-m-d H:i:s'),
'usuario_id' => $_SESSION['usuario_id']
];
}
private function parsearLinea505($linea) {
// Formato: 505|numero_factura|fecha_factura|valor_dolares|valor_factura|...
$campos = explode('|', $linea);
if (count($campos) < 5) {
throw new Exception("Formato inválido en línea 505");
}
return [
'numero_factura' => trim($campos[1]),
'fecha_factura' => $this->convertirFecha(trim($campos[2])),
'valor_dolares' => floatval(trim($campos[3])),
'valor_factura' => floatval(trim($campos[4]))
];
}
private function parsearLinea505Real($linea) {
// Formato oficial 505: 505|numero_pedimento|fecha_cfdi|numero_cfdi_cove|termino_facturacion|moneda|valor_dolares|valor_total|pais|entidad_federativa|rfc_proveedor|nombre_proveedor|calle|num_int|num_ext|cp|municipio|...
$campos = explode('|', $linea);
if (count($campos) < 12) {
throw new Exception("Formato inválido en línea 505 - campos insuficientes: " . count($campos) . " (mínimo: 12)");
}
error_log("DEBUG 505 - Total campos: " . count($campos));
error_log("DEBUG 505 - Primeros 12 campos: " . implode(' | ', array_slice($campos, 0, 12)));
// Extraer datos según documentación oficial SAT
$numero_pedimento = trim($campos[1]); // Campo 1: Número de Pedimento
$fecha_cfdi = trim($campos[2]); // Campo 2: Fecha de CFDI
$numero_cfdi_cove = trim($campos[3]); // Campo 3: Número de CFDI (COVE) - 40 caracteres max
$termino_facturacion = trim($campos[4]); // Campo 4: Término de Facturación - 3 caracteres
$moneda = trim($campos[5]); // Campo 5: Moneda - 3 caracteres
$valor_dolares = floatval(trim($campos[6])); // Campo 6: Valor Total en Dólares USD
$valor_total = floatval(trim($campos[7])); // Campo 7: Valor Total en moneda del CFDI
$pais = trim($campos[8]); // Campo 8: País del CFDI - 3 caracteres
$entidad_federativa = trim($campos[9]); // Campo 9: Entidad Federativa - 3 caracteres
$rfc_proveedor = trim($campos[10]); // Campo 10: RFC Proveedor - 30 caracteres max
$nombre_proveedor = trim($campos[11]); // Campo 11: Nombre Proveedor - 120 caracteres max
error_log("DEBUG 505 - Datos oficiales extraídos:");
error_log(" - Número CFDI/COVE: '$numero_cfdi_cove'");
error_log(" - Fecha CFDI: '$fecha_cfdi'");
error_log(" - Término facturación: '$termino_facturacion'");
error_log(" - Moneda: '$moneda'");
error_log(" - Valor USD: $valor_dolares");
error_log(" - Valor total: $valor_total");
error_log(" - RFC Proveedor: '$rfc_proveedor'");
error_log(" - Nombre Proveedor: '$nombre_proveedor'");
return [
'numero_factura' => $numero_cfdi_cove, // Campo 3: Número de CFDI/COVE
'fecha_factura' => $this->convertirFechaReal($fecha_cfdi), // Campo 2: Fecha CFDI
'valor_dolares' => $valor_dolares, // Campo 6: Valor en USD
'valor_factura' => $valor_total, // Campo 7: Valor total en moneda CFDI
'cove' => $numero_cfdi_cove, // Campo 3: COVE (mismo que número factura)
'moneda' => $moneda, // Campo 5: Moneda
'proveedor' => $nombre_proveedor // Campo 11: Nombre del proveedor
];
}
private function parsearLinea551($linea) {
// Formato: 551|secuencia|fraccion_arancelaria|descripcion|cantidad|unidad|valor_unitario|...
$campos = explode('|', $linea);
if (count($campos) < 7) {
throw new Exception("Formato inválido en línea 551");
}
return [
'secuencia' => intval(trim($campos[1])),
'fraccion_arancelaria' => trim($campos[2]),
'descripcion' => trim($campos[3]),
'cantidad' => floatval(trim($campos[4])),
'unidad' => trim($campos[5]),
'valor_unitario' => floatval(trim($campos[6]))
];
}
private function parsearLinea551Real($linea) {
// Formato oficial 551: 551|numero_pedimento|fraccion_arancelaria|numero_partida|subdivision|descripcion|precio_unitario|valor_aduana|valor_comercial|valor_dolares|cantidad_umc|unidad_comercial|...
$campos = explode('|', $linea);
if (count($campos) < 12) {
throw new Exception("Formato inválido en línea 551 - campos insuficientes: " . count($campos) . " (mínimo: 12)");
}
error_log("DEBUG 551 - Total campos: " . count($campos));
error_log("DEBUG 551 - Primeros 12 campos: " . implode(' | ', array_slice($campos, 0, 12)));
// Extraer datos según documentación oficial
$numero_pedimento = isset($campos[1]) ? trim($campos[1]) : '';
$fraccion_arancelaria = isset($campos[2]) ? trim($campos[2]) : '';
$numero_partida = isset($campos[3]) ? intval(trim($campos[3])) : 0;
$subdivision = isset($campos[4]) ? trim($campos[4]) : '';
$descripcion = isset($campos[5]) ? trim($campos[5]) : '';
$precio_unitario = isset($campos[6]) ? floatval(trim($campos[6])) : 0;
$valor_aduana = isset($campos[7]) ? floatval(trim($campos[7])) : 0;
$valor_comercial = isset($campos[8]) ? floatval(trim($campos[8])) : 0;
$valor_dolares = isset($campos[9]) ? floatval(trim($campos[9])) : 0;
$cantidad_umc = isset($campos[10]) ? floatval(trim($campos[10])) : 0;
$unidad_comercial = isset($campos[11]) ? trim($campos[11]) : '';
// Aplicar valores por defecto según documentación oficial
if (empty($fraccion_arancelaria)) {
error_log("WARNING 551: Fracción arancelaria vacía, usando valor por defecto");
$fraccion_arancelaria = 'PENDIENTE';
}
if ($numero_partida <= 0) {
error_log("WARNING 551: Número de partida inválido, generando secuencial");
static $contador_partida = 1;
$numero_partida = $contador_partida++;
}
if (empty($descripcion)) {
error_log("WARNING 551: Descripción vacía, usando valor por defecto");
$descripcion = 'DESCRIPCIÓN PENDIENTE';
}
if ($cantidad_umc <= 0) {
error_log("WARNING 551: Cantidad UMC inválida ($cantidad_umc), usando 1.0000");
$cantidad_umc = 1.0000;
}
if (empty($unidad_comercial)) {
error_log("WARNING 551: Unidad comercial vacía, usando 'PZ'");
$unidad_comercial = 'PZ'; // Pieza como unidad por defecto
}
// Calcular precio unitario si no existe pero hay valores
if ($precio_unitario == 0) {
if ($valor_dolares > 0 && $cantidad_umc > 0) {
$precio_unitario = $valor_dolares / $cantidad_umc;
error_log("DEBUG 551: Precio unitario calculado: $precio_unitario");
} elseif ($valor_comercial > 0 && $cantidad_umc > 0) {
$precio_unitario = $valor_comercial / $cantidad_umc;
error_log("DEBUG 551: Precio unitario calculado desde valor comercial: $precio_unitario");
}
}
error_log("DEBUG 551 - Datos procesados:");
error_log(" - Partida: $numero_partida");
error_log(" - Fracción: '$fraccion_arancelaria'");
error_log(" - Descripción: '" . substr($descripcion, 0, 50) . "...'");
error_log(" - Cantidad: $cantidad_umc");
error_log(" - Unidad: '$unidad_comercial'");
error_log(" - Precio unitario: $precio_unitario");
error_log(" - Valor dólares: $valor_dolares");
return [
'secuencia' => $numero_partida,
'fraccion_arancelaria' => $fraccion_arancelaria,
'descripcion' => $descripcion,
'cantidad' => $cantidad_umc,
'unidad' => $unidad_comercial,
'valor_unitario' => $precio_unitario,
'peso_neto' => null,
'peso_bruto' => null
];
}
private function procesarPedimento($pedimento, $facturas, $partidas, $validar_duplicados) {
try {
error_log("Procesando pedimento: " . $pedimento['numero_pedimento']);
error_log("Validar duplicados: " . ($validar_duplicados ? 'SÍ' : 'NO'));
// Validar duplicados si está habilitado
if ($validar_duplicados && $this->existePedimento($pedimento['numero_pedimento'])) {
error_log("Pedimento {$pedimento['numero_pedimento']} marcado como duplicado, omitiendo...");
$this->estadisticas['duplicados']++;
return;
}
error_log("Insertando pedimento nuevo: " . $pedimento['numero_pedimento']);
// Iniciar transacción
sqlsrv_begin_transaction($this->conn);
// Insertar pedimento
$sql = "INSERT INTO pedimentos (numero_pedimento, patente, aduana, anio, clave_documento,
rfc_importador, fecha_creacion, usuario_id, estado)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'activo'); SELECT SCOPE_IDENTITY() AS id;";
$params = [
$pedimento['numero_pedimento'],
$pedimento['patente'],
$pedimento['aduana'],
$pedimento['anio'],
$pedimento['clave_documento'],
$pedimento['rfc_importador'],
$pedimento['fecha_creacion'],
$pedimento['usuario_id']
];
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt === false) {
throw new Exception("Error al insertar pedimento: " . print_r(sqlsrv_errors(), true));
}
// Obtener el ID del pedimento insertado
sqlsrv_next_result($stmt);
sqlsrv_fetch($stmt);
$pedimento_id = sqlsrv_get_field($stmt, 0);
sqlsrv_free_stmt($stmt);
// Insertar facturas
foreach ($facturas as $factura) {
$sql = "INSERT INTO pedimento_facturas (pedimento_id, numero_factura, fecha_factura,
valor_dolares, valor_factura, cove)
VALUES (?, ?, ?, ?, ?, ?)";
$params = [
$pedimento_id,
$factura['numero_factura'],
$factura['fecha_factura'],
$factura['valor_dolares'],
$factura['valor_factura'],
isset($factura['cove']) ? $factura['cove'] : null
];
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt === false) {
throw new Exception("Error al insertar factura: " . print_r(sqlsrv_errors(), true));
}
sqlsrv_free_stmt($stmt);
$this->estadisticas['facturas_procesadas']++;
}
// Insertar partidas
foreach ($partidas as $partida) {
error_log("INSERTANDO PARTIDA: " . print_r($partida, true));
$sql = "INSERT INTO pedimento_partidas (pedimento_id, secuencia, fraccion_arancelaria,
descripcion, cantidad, unidad, valor_unitario,
peso_neto, peso_bruto)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
$params = [
$pedimento_id,
$partida['secuencia'],
$partida['fraccion_arancelaria'],
$partida['descripcion'],
$partida['cantidad'],
$partida['unidad'],
$partida['valor_unitario'],
isset($partida['peso_neto']) ? $partida['peso_neto'] : null,
isset($partida['peso_bruto']) ? $partida['peso_bruto'] : null
];
error_log("PARÁMETROS SQL: " . print_r($params, true));
$stmt = sqlsrv_query($this->conn, $sql, $params);
if ($stmt === false) {
$error = print_r(sqlsrv_errors(), true);
error_log("ERROR AL INSERTAR PARTIDA: " . $error);
throw new Exception("Error al insertar partida: " . $error);
}
sqlsrv_free_stmt($stmt);
$this->estadisticas['partidas_procesadas']++;
error_log("Partida insertada exitosamente - Total procesadas: " . $this->estadisticas['partidas_procesadas']);
}
// Confirmar transacción
sqlsrv_commit($this->conn);
$this->estadisticas['pedimentos_procesados']++;
$this->pedimentos_creados[] = $pedimento['numero_pedimento'];
} catch (Exception $e) {
sqlsrv_rollback($this->conn);
$this->errores_detalle[] = "Error procesando pedimento {$pedimento['numero_pedimento']}: " . $e->getMessage();
$this->estadisticas['errores']++;
}
}
private function existePedimento($numero_pedimento) {
$sql = "SELECT id, fecha_creacion FROM pedimentos WHERE numero_pedimento = ?";
$stmt = sqlsrv_query($this->conn, $sql, [$numero_pedimento]);
if ($stmt === false) {
error_log("Error al verificar duplicado: " . print_r(sqlsrv_errors(), true));
return false;
}
$row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
sqlsrv_free_stmt($stmt);
if ($row) {
error_log("Pedimento duplicado encontrado: {$numero_pedimento} (ID: {$row['id']})");
return true;
}
return false;
}
private function convertirFecha($fecha_str) {
// Convertir formato DDMMYYYY a YYYY-MM-DD
if (strlen($fecha_str) === 8) {
$dia = substr($fecha_str, 0, 2);
$mes = substr($fecha_str, 2, 2);
$anio = substr($fecha_str, 4, 4);
return "$anio-$mes-$dia";
}
return date('Y-m-d'); // Fecha por defecto
}
private function convertirFechaReal($fecha_str) {
// Convertir fecha del archivo real - puede venir en formato YYYYMMDD o DDMMYYYY
if (empty($fecha_str) || strlen($fecha_str) !== 8) {
return date('Y-m-d'); // Fecha por defecto
}
// Intentar formato YYYYMMDD primero
if (substr($fecha_str, 0, 2) === '20') {
$anio = substr($fecha_str, 0, 4);
$mes = substr($fecha_str, 4, 2);
$dia = substr($fecha_str, 6, 2);
} else {
// Formato DDMMYYYY
$dia = substr($fecha_str, 0, 2);
$mes = substr($fecha_str, 2, 2);
$anio = substr($fecha_str, 4, 4);
}
// Validar fecha
if (checkdate($mes, $dia, $anio)) {
return "$anio-$mes-$dia";
}
return date('Y-m-d'); // Fecha por defecto si no es válida
}
}
// Procesar la importación
try {
$archivo = $_FILES['archivo'];
$validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
// Crear directorio temporal si no existe
$upload_dir = __DIR__ . '/../storage/temp/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
// Mover archivo a directorio temporal
$archivo_temporal = $upload_dir . 'import_' . time() . '_' . $archivo['name'];
if (!move_uploaded_file($archivo['tmp_name'], $archivo_temporal)) {
throw new Exception("Error al procesar el archivo subido");
}
// Obtener conexión a SQL Server
$conn = getConnection();
// Procesar archivo
$importador = new ImportadorPedimentos($conn);
$resultado = $importador->procesarArchivo($archivo_temporal, $validar_duplicados);
// Cerrar conexión
sqlsrv_close($conn);
// Limpiar archivo temporal
unlink($archivo_temporal);
// Enviar respuesta
echo json_encode($resultado);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'message' => 'Error del servidor: ' . $e->getMessage()
]);
}
?>

View File

@@ -2,44 +2,163 @@
require_once __DIR__ . '/../../config/database.php';
require_once __DIR__ . '/../helpers/session.php';
function index() {
// Formatea el pedimento como: YY-AA-PPPP-PPPPPPP
function mve_format_pedimento_display($anio, $aduana, $patente, $numero)
{
$yy = substr((string)$anio, -2);
$ad = substr(preg_replace('/\D/', '', (string)$aduana), 0, 2);
$pat = str_pad(preg_replace('/\D/', '', (string)$patente), 4, '0', STR_PAD_LEFT);
$num = str_pad(preg_replace('/\D/', '', (string)$numero), 7, '0', STR_PAD_LEFT);
$yy = $yy !== '' ? $yy : '00';
$ad = str_pad($ad, 2, '0', STR_PAD_LEFT);
return "$yy-$ad-$pat-$num";
}
// Garantiza que expediente_archivos tenga la columna pedimento_id
function mve_ensure_expediente_schema($conn)
{
$chk = sqlsrv_query($conn, "SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'expediente_archivos' AND COLUMN_NAME = 'pedimento_id'");
$exists = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$exists) {
@sqlsrv_query($conn, "ALTER TABLE expediente_archivos ADD pedimento_id INT NULL");
@sqlsrv_query($conn, "CREATE INDEX IX_expediente_archivos_pedimento ON expediente_archivos(pedimento_id)");
}
}
// Genera documentos de prueba (Acuse y Detalle) en el expediente del pedimento
function mve_generar_documentos_expediente($conn, $pedimento_id, $usuario_nombre = 'sistema')
{
mve_ensure_expediente_schema($conn);
// Obtener datos del pedimento para el encabezado
$stmt = sqlsrv_query($conn, "SELECT numero_pedimento, patente, aduana, anio, rfc_importador, clave_documento, fecha_creacion FROM pedimentos WHERE id = ?", [$pedimento_id]);
$ped = $stmt ? sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC) : null;
if ($stmt) sqlsrv_free_stmt($stmt);
if (!$ped) return; // nada que hacer
$display = mve_format_pedimento_display($ped['anio'] ?? '', $ped['aduana'] ?? '', $ped['patente'] ?? '', $ped['numero_pedimento'] ?? '');
// Directorio destino
$folderKey = 'pedimento_' . (int)$pedimento_id;
$uploadDir = __DIR__ . '/../../uploads/expedientes/' . $folderKey;
if (!is_dir($uploadDir)) { @mkdir($uploadDir, 0775, true); }
// Contenidos HTML simples
$now = date('Y-m-d H:i');
$htmlAcuse = "<html><head><meta charset='utf-8'><style>body{font-family:sans-serif} h1{font-size:18px} .m{font-family:monospace}</style></head><body>"
."<h1>Acuse de Manifestación de Valor</h1>"
."<p><strong>Pedimento:</strong> <span class='m'>{$display}</span></p>"
."<p><strong>RFC:</strong> ".htmlspecialchars($ped['rfc_importador'] ?? '-', ENT_QUOTES, 'UTF-8')."</p>"
."<p><strong>Clave:</strong> ".htmlspecialchars($ped['clave_documento'] ?? '-', ENT_QUOTES, 'UTF-8')."</p>"
."<p><strong>Generado:</strong> {$now}</p>"
."<p>Documento de prueba generado automáticamente.</p>"
."</body></html>";
$htmlDetalle = "<html><head><meta charset='utf-8'><style>body{font-family:sans-serif} h1{font-size:18px} .m{font-family:monospace}</style></head><body>"
."<h1>Detalle de Manifestación de Valor</h1>"
."<p><strong>Pedimento:</strong> <span class='m'>{$display}</span></p>"
."<p>Este es un detalle de ejemplo para pruebas.</p>"
."<ul><li>Sección 65/66 capturada (mock)</li><li>Precios pagados y por pagar (mock)</li><li>Compensaciones (mock)</li></ul>"
."<p><strong>Generado:</strong> {$now}</p>"
."</body></html>";
// Intentar generar PDF con Dompdf; fallback a .txt si no está disponible
$docs = [
[ 'nombre' => 'Acuse Manifestacion de Valor', 'html' => $htmlAcuse ],
[ 'nombre' => 'Detalle Manifestacion de Valor', 'html' => $htmlDetalle ],
];
$dompdfOk = false;
try {
@require_once __DIR__ . '/../../vendor/autoload.php';
if (class_exists('Dompdf\\Dompdf')) { $dompdfOk = true; }
} catch (\Throwable $e) { $dompdfOk = false; }
foreach ($docs as $d) {
$safeBase = preg_replace('/[^A-Za-z0-9._\- ]/', '_', $d['nombre']);
$filename = $safeBase . '_' . time() . ($dompdfOk ? '.pdf' : '.txt');
$fullPath = $uploadDir . '/' . $filename;
$rutaDb = 'uploads/expedientes/' . $folderKey . '/' . $filename;
if ($dompdfOk) {
try {
$dompdf = new Dompdf\Dompdf([ 'isRemoteEnabled' => false ]);
$dompdf->loadHtml($d['html']);
$dompdf->setPaper('letter', 'portrait');
$dompdf->render();
file_put_contents($fullPath, $dompdf->output());
$tipo = 'application/pdf';
} catch (\Throwable $e) {
// Fallback a texto
file_put_contents($fullPath, strip_tags($d['html']));
$tipo = 'text/plain';
}
} else {
file_put_contents($fullPath, strip_tags($d['html']));
$tipo = 'text/plain';
}
$tamanoKb = file_exists($fullPath) ? round(filesize($fullPath) / 1024, 2) : 0;
// Insertar en expediente_archivos
sqlsrv_query($conn,
"INSERT INTO expediente_archivos (pedimento_id, nombre_archivo, ruta_archivo, tipo_archivo, tamano_archivo, creado_por) VALUES (?,?,?,?,?,?)",
[$pedimento_id, $d['nombre'] . ($dompdfOk ? '.pdf' : '.txt'), $rutaDb, $tipo, $tamanoKb, $usuario_nombre]
);
}
}
function index()
{
include __DIR__ . '/../../views/mve/lista.php';
}
function ajax_guardar_datos_factura() {
try {
// Validar que el usuario esté autenticado
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'message' => 'Usuario no autenticado']);
return;
}
// Guarda en bloque los datos enviados (se usa por el botón Guardar)
function ajax_guardar_datos_factura()
{
if (!($_SESSION['usuario_id'] ?? false)) {
echo json_encode(['success' => false, 'message' => 'No autorizado']);
return;
}
$id_factura = $_POST['id_factura'] ?? null;
$id_pedimento = $_POST['id_pedimento'] ?? null;
$datos_art65 = json_decode($_POST['datos_art65'] ?? '{}', true);
$datos_art66 = json_decode($_POST['datos_art66'] ?? '{}', true);
$usuario_id = (int)$_SESSION['usuario_id'];
$id_factura = isset($_POST['id_factura']) ? (int)$_POST['id_factura'] : 0;
$id_pedimento = isset($_POST['id_pedimento']) ? (int)$_POST['id_pedimento'] : 0;
$datos_art65 = json_decode($_POST['datos_art65'] ?? '{}', true);
$datos_art66 = json_decode($_POST['datos_art66'] ?? '{}', true);
$datos_precio_pagado = json_decode($_POST['datos_precio_pagado'] ?? '{}', true);
$datos_precio_pagar = json_decode($_POST['datos_precio_pagar'] ?? '{}', true);
$datos_compenso = json_decode($_POST['datos_compenso'] ?? '{}', true);
if (!$id_factura || !$id_pedimento) {
echo json_encode(['success' => false, 'message' => 'Faltan datos requeridos']);
return;
}
if ($id_factura <= 0 || $id_pedimento <= 0) {
echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
return;
}
$db = getDB();
// Verificar si ya existen datos para esta factura
$stmt = $db->prepare("SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?");
$stmt->execute([$id_pedimento, $id_factura]);
$existe = $stmt->fetch();
$conn = getConnection();
if ($existe) {
// Actualizar registro existente
$sql = "UPDATE mve_facturas_datos SET
// Verificar propiedad del pedimento y que la factura le pertenezca
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos p JOIN pedimento_facturas f ON f.pedimento_id = p.id WHERE p.id = ? AND f.id = ? AND p.usuario_id = ?", [$id_pedimento, $id_factura, $usuario_id]);
$own = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$own) {
echo json_encode(['success' => false, 'message' => 'No autorizado o no encontrado']);
return;
}
// ¿Existe registro para esta factura?
$sel = sqlsrv_query($conn, "SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?", [$id_pedimento, $id_factura]);
$row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null;
if ($sel) sqlsrv_free_stmt($sel);
if ($row) {
// UPDATE
$sql = "UPDATE mve_facturas_datos SET
art65_fecha_transporte = ?, art65_importe_transporte = ?,
art65_fecha_descuentos = ?, art65_importe_descuentos = ?,
art65_fecha_posteriores = ?, art65_importe_posteriores = ?,
art65_fecha_contribuciones = ?, art65_importe_contribuciones = ?,
art65_fecha_pagos_vendedor = ?, art65_importe_pagos_vendedor = ?,
art66_fecha_comisiones = ?, art66_importe_comisiones = ?, art66_cargo_comisiones = ?,
art66_fecha_envases = ?, art66_importe_envases = ?, art66_cargo_envases = ?,
art66_fecha_embalaje = ?, art66_importe_embalaje = ?, art66_cargo_embalaje = ?,
@@ -47,37 +166,64 @@ function ajax_guardar_datos_factura() {
art66_fecha_ingenieria = ?, art66_importe_ingenieria = ?, art66_cargo_ingenieria = ?,
art66_fecha_regalias = ?, art66_importe_regalias = ?, art66_cargo_regalias = ?,
art66_fecha_producto = ?, art66_importe_producto = ?, art66_cargo_producto = ?,
fecha_actualizacion = NOW()
WHERE id_pedimento = ? AND id_factura = ?";
$params = [
$datos_art65['fecha_transporte'] ?: null, $datos_art65['importe_transporte'] ?: null,
$datos_art65['fecha_descuentos'] ?: null, $datos_art65['importe_descuentos'] ?: null,
$datos_art65['fecha_posteriores'] ?: null, $datos_art65['importe_posteriores'] ?: null,
$datos_art65['fecha_contribuciones'] ?: null, $datos_art65['importe_contribuciones'] ?: null,
$datos_art65['fecha_pagos_vendedor'] ?: null, $datos_art65['importe_pagos_vendedor'] ?: null,
$datos_art66['fecha_comisiones'] ?: null, $datos_art66['importe_comisiones'] ?: null, $datos_art66['cargo_comisiones'] ?: null,
$datos_art66['fecha_envases'] ?: null, $datos_art66['importe_envases'] ?: null, $datos_art66['cargo_envases'] ?: null,
$datos_art66['fecha_embalaje'] ?: null, $datos_art66['importe_embalaje'] ?: null, $datos_art66['cargo_embalaje'] ?: null,
$datos_art66['fecha_transporte_dec'] ?: null, $datos_art66['importe_transporte_dec'] ?: null, $datos_art66['cargo_transporte_dec'] ?: null,
$datos_art66['fecha_ingenieria'] ?: null, $datos_art66['importe_ingenieria'] ?: null, $datos_art66['cargo_ingenieria'] ?: null,
$datos_art66['fecha_regalias'] ?: null, $datos_art66['importe_regalias'] ?: null, $datos_art66['cargo_regalias'] ?: null,
$datos_art66['fecha_producto'] ?: null, $datos_art66['importe_producto'] ?: null, $datos_art66['cargo_producto'] ?: null,
$id_pedimento, $id_factura
];
} else {
// Crear nuevo registro
$sql = "INSERT INTO mve_facturas_datos (
precio_pagado_fecha_pago = ?, precio_pagado_importe = ?, precio_pagado_moneda = ?,
precio_pagado_forma_pago = ?, precio_pagado_referencia = ?,
precio_pagar_fecha_limite = ?, precio_pagar_importe = ?, precio_pagar_moneda = ?,
precio_pagar_terminos = ?, precio_pagar_observaciones = ?,
compenso_fecha = ?, compenso_importe = ?, compenso_tipo = ?,
compenso_motivo = ?, compenso_documentos = ?, compenso_descripcion = ?
WHERE id = ?";
$params = [
$datos_art65['fecha_transporte'] ?? null, $datos_art65['importe_transporte'] ?? null,
$datos_art65['fecha_descuentos'] ?? null, $datos_art65['importe_descuentos'] ?? null,
$datos_art65['fecha_posteriores'] ?? null, $datos_art65['importe_posteriores'] ?? null,
$datos_art65['fecha_contribuciones'] ?? null, $datos_art65['importe_contribuciones'] ?? null,
$datos_art65['fecha_pagos_vendedor'] ?? null, $datos_art65['importe_pagos_vendedor'] ?? null,
$datos_art66['fecha_comisiones'] ?? null, $datos_art66['importe_comisiones'] ?? null, $datos_art66['cargo_comisiones'] ?? null,
$datos_art66['fecha_envases'] ?? null, $datos_art66['importe_envases'] ?? null, $datos_art66['cargo_envases'] ?? null,
$datos_art66['fecha_embalaje'] ?? null, $datos_art66['importe_embalaje'] ?? null, $datos_art66['cargo_embalaje'] ?? null,
$datos_art66['fecha_transporte_dec'] ?? null, $datos_art66['importe_transporte_dec'] ?? null, $datos_art66['cargo_transporte_dec'] ?? null,
$datos_art66['fecha_ingenieria'] ?? null, $datos_art66['importe_ingenieria'] ?? null, $datos_art66['cargo_ingenieria'] ?? null,
$datos_art66['fecha_regalias'] ?? null, $datos_art66['importe_regalias'] ?? null, $datos_art66['cargo_regalias'] ?? null,
$datos_art66['fecha_producto'] ?? null, $datos_art66['importe_producto'] ?? null, $datos_art66['cargo_producto'] ?? null,
$datos_precio_pagado['fecha_precio_pagado'] ?? null,
$datos_precio_pagado['importe_precio_pagado'] ?? null,
$datos_precio_pagado['moneda_precio_pagado'] ?? null,
$datos_precio_pagado['forma_pago_precio_pagado'] ?? null,
$datos_precio_pagado['referencia_precio_pagado'] ?? null,
$datos_precio_pagar['fecha_limite_pago'] ?? null,
$datos_precio_pagar['importe_precio_pagar'] ?? null,
$datos_precio_pagar['moneda_precio_pagar'] ?? null,
$datos_precio_pagar['terminos_precio_pagar'] ?? null,
$datos_precio_pagar['observaciones_precio_pagar'] ?? null,
$datos_compenso['fecha_compenso'] ?? null,
$datos_compenso['importe_compenso'] ?? null,
$datos_compenso['tipo_compenso'] ?? null,
$datos_compenso['motivo_compenso'] ?? null,
$datos_compenso['documentos_compenso'] ?? null,
$datos_compenso['descripcion_compenso'] ?? null,
$row['id']
];
$stmt = sqlsrv_query($conn, $sql, $params);
} else {
// INSERT
$sql = "INSERT INTO mve_facturas_datos (
id_pedimento, id_factura, numero_factura,
art65_fecha_transporte, art65_importe_transporte,
art65_fecha_descuentos, art65_importe_descuentos,
art65_fecha_posteriores, art65_importe_posteriores,
art65_fecha_contribuciones, art65_importe_contribuciones,
art65_fecha_pagos_vendedor, art65_importe_pagos_vendedor,
art66_fecha_comisiones, art66_importe_comisiones, art66_cargo_comisiones,
art66_fecha_envases, art66_importe_envases, art66_cargo_envases,
art66_fecha_embalaje, art66_importe_embalaje, art66_cargo_embalaje,
@@ -85,106 +231,447 @@ function ajax_guardar_datos_factura() {
art66_fecha_ingenieria, art66_importe_ingenieria, art66_cargo_ingenieria,
art66_fecha_regalias, art66_importe_regalias, art66_cargo_regalias,
art66_fecha_producto, art66_importe_producto, art66_cargo_producto,
precio_pagado_fecha_pago, precio_pagado_importe, precio_pagado_moneda,
precio_pagado_forma_pago, precio_pagado_referencia,
precio_pagar_fecha_limite, precio_pagar_importe, precio_pagar_moneda,
precio_pagar_terminos, precio_pagar_observaciones,
compenso_fecha, compenso_importe, compenso_tipo,
compenso_motivo, compenso_documentos, compenso_descripcion,
usuario_creacion
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
// Obtener número de factura opcional
$num = null;
$nf = sqlsrv_query($conn, "SELECT numero_factura FROM pedimento_facturas WHERE id = ?", [$id_factura]);
if ($nf && ($r = sqlsrv_fetch_array($nf, SQLSRV_FETCH_ASSOC))) { $num = $r['numero_factura']; }
if ($nf) sqlsrv_free_stmt($nf);
$params = [
$id_pedimento, $id_factura, $num,
$datos_art65['fecha_transporte'] ?? null, $datos_art65['importe_transporte'] ?? null,
$datos_art65['fecha_descuentos'] ?? null, $datos_art65['importe_descuentos'] ?? null,
$datos_art65['fecha_posteriores'] ?? null, $datos_art65['importe_posteriores'] ?? null,
$datos_art65['fecha_contribuciones'] ?? null, $datos_art65['importe_contribuciones'] ?? null,
$datos_art65['fecha_pagos_vendedor'] ?? null, $datos_art65['importe_pagos_vendedor'] ?? null,
$datos_art66['fecha_comisiones'] ?? null, $datos_art66['importe_comisiones'] ?? null, $datos_art66['cargo_comisiones'] ?? null,
$datos_art66['fecha_envases'] ?? null, $datos_art66['importe_envases'] ?? null, $datos_art66['cargo_envases'] ?? null,
$datos_art66['fecha_embalaje'] ?? null, $datos_art66['importe_embalaje'] ?? null, $datos_art66['cargo_embalaje'] ?? null,
$datos_art66['fecha_transporte_dec'] ?? null, $datos_art66['importe_transporte_dec'] ?? null, $datos_art66['cargo_transporte_dec'] ?? null,
$datos_art66['fecha_ingenieria'] ?? null, $datos_art66['importe_ingenieria'] ?? null, $datos_art66['cargo_ingenieria'] ?? null,
$datos_art66['fecha_regalias'] ?? null, $datos_art66['importe_regalias'] ?? null, $datos_art66['cargo_regalias'] ?? null,
$datos_art66['fecha_producto'] ?? null, $datos_art66['importe_producto'] ?? null, $datos_art66['cargo_producto'] ?? null,
$datos_precio_pagado['fecha_precio_pagado'] ?? null,
$datos_precio_pagado['importe_precio_pagado'] ?? null,
$datos_precio_pagado['moneda_precio_pagado'] ?? null,
$datos_precio_pagado['forma_pago_precio_pagado'] ?? null,
$datos_precio_pagado['referencia_precio_pagado'] ?? null,
$datos_precio_pagar['fecha_limite_pago'] ?? null,
$datos_precio_pagar['importe_precio_pagar'] ?? null,
$datos_precio_pagar['moneda_precio_pagar'] ?? null,
$datos_precio_pagar['terminos_precio_pagar'] ?? null,
$datos_precio_pagar['observaciones_precio_pagar'] ?? null,
$datos_compenso['fecha_compenso'] ?? null,
$datos_compenso['importe_compenso'] ?? null,
$datos_compenso['tipo_compenso'] ?? null,
$datos_compenso['motivo_compenso'] ?? null,
$datos_compenso['documentos_compenso'] ?? null,
$datos_compenso['descripcion_compenso'] ?? null,
(string)$usuario_id
];
$stmt = sqlsrv_query($conn, $sql, $params);
}
if ($stmt === false) {
echo json_encode(['success' => false, 'message' => 'Error al guardar']);
return;
}
// Marcar estado de MVE/COVE como respondido (para el badge)
upsert_cove_respuesta_min($conn, $id_pedimento, $id_factura, $usuario_id);
echo json_encode(['success' => true]);
}
// Autosave por sección: seccion in ['65','66','precio_pagado','precio_pagar','compenso']
function ajax_guardar_seccion()
{
if (!($_SESSION['usuario_id'] ?? false)) {
echo json_encode(['success' => false, 'message' => 'No autorizado']);
return;
}
$usuario_id = (int)$_SESSION['usuario_id'];
$id_factura = isset($_POST['id_factura']) ? (int)$_POST['id_factura'] : 0;
$id_pedimento = isset($_POST['id_pedimento']) ? (int)$_POST['id_pedimento'] : 0;
$seccion = $_POST['seccion'] ?? '';
$datos = json_decode($_POST['datos'] ?? '{}', true);
if ($id_factura <= 0 || $id_pedimento <= 0 || !$seccion) {
echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']);
return;
}
$conn = getConnection();
// Verificar propiedad
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos p JOIN pedimento_facturas f ON f.pedimento_id = p.id WHERE p.id = ? AND f.id = ? AND p.usuario_id = ?", [$id_pedimento, $id_factura, $usuario_id]);
$own = $chk && sqlsrv_fetch_array($chk) ? true : false;
if ($chk) sqlsrv_free_stmt($chk);
if (!$own) { echo json_encode(['success' => false, 'message' => 'No autorizado']); return; }
// Garantizar que exista el registro base
$sel = sqlsrv_query($conn, "SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?", [$id_pedimento, $id_factura]);
$row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null; if ($sel) sqlsrv_free_stmt($sel);
if (!$row) {
// Crear registro vacío
$num = null; $nf = sqlsrv_query($conn, "SELECT numero_factura FROM pedimento_facturas WHERE id = ?", [$id_factura]);
if ($nf && ($r = sqlsrv_fetch_array($nf, SQLSRV_FETCH_ASSOC))) { $num = $r['numero_factura']; }
if ($nf) sqlsrv_free_stmt($nf);
$ins = sqlsrv_query($conn, "INSERT INTO mve_facturas_datos (id_pedimento, id_factura, numero_factura, usuario_creacion) VALUES (?,?,?,?)", [$id_pedimento, $id_factura, $num, (string)$usuario_id]);
if ($ins === false) { echo json_encode(['success' => false, 'message' => 'Error al iniciar registro']); return; }
$sel2 = sqlsrv_query($conn, "SELECT id FROM mve_facturas_datos WHERE id_pedimento = ? AND id_factura = ?", [$id_pedimento, $id_factura]);
$row = $sel2 ? sqlsrv_fetch_array($sel2, SQLSRV_FETCH_ASSOC) : null; if ($sel2) sqlsrv_free_stmt($sel2);
}
if (!$row) { echo json_encode(['success' => false, 'message' => 'No se pudo crear el registro']); return; }
$id = (int)$row['id'];
$sql = '';
$params = [];
switch ($seccion) {
case '65':
$sql = "UPDATE mve_facturas_datos SET
art65_fecha_transporte = ?, art65_importe_transporte = ?,
art65_fecha_descuentos = ?, art65_importe_descuentos = ?,
art65_fecha_posteriores = ?, art65_importe_posteriores = ?,
art65_fecha_contribuciones = ?, art65_importe_contribuciones = ?,
art65_fecha_pagos_vendedor = ?, art65_importe_pagos_vendedor = ?
WHERE id = ?";
$params = [
$id_pedimento, $id_factura, "FACTURA-$id_factura",
$datos_art65['fecha_transporte'] ?: null, $datos_art65['importe_transporte'] ?: null,
$datos_art65['fecha_descuentos'] ?: null, $datos_art65['importe_descuentos'] ?: null,
$datos_art65['fecha_posteriores'] ?: null, $datos_art65['importe_posteriores'] ?: null,
$datos_art65['fecha_contribuciones'] ?: null, $datos_art65['importe_contribuciones'] ?: null,
$datos_art65['fecha_pagos_vendedor'] ?: null, $datos_art65['importe_pagos_vendedor'] ?: null,
$datos_art66['fecha_comisiones'] ?: null, $datos_art66['importe_comisiones'] ?: null, $datos_art66['cargo_comisiones'] ?: null,
$datos_art66['fecha_envases'] ?: null, $datos_art66['importe_envases'] ?: null, $datos_art66['cargo_envases'] ?: null,
$datos_art66['fecha_embalaje'] ?: null, $datos_art66['importe_embalaje'] ?: null, $datos_art66['cargo_embalaje'] ?: null,
$datos_art66['fecha_transporte_dec'] ?: null, $datos_art66['importe_transporte_dec'] ?: null, $datos_art66['cargo_transporte_dec'] ?: null,
$datos_art66['fecha_ingenieria'] ?: null, $datos_art66['importe_ingenieria'] ?: null, $datos_art66['cargo_ingenieria'] ?: null,
$datos_art66['fecha_regalias'] ?: null, $datos_art66['importe_regalias'] ?: null, $datos_art66['cargo_regalias'] ?: null,
$datos_art66['fecha_producto'] ?: null, $datos_art66['importe_producto'] ?: null, $datos_art66['cargo_producto'] ?: null,
$_SESSION['user_id']
$datos['fecha_transporte'] ?? null, $datos['importe_transporte'] ?? null,
$datos['fecha_descuentos'] ?? null, $datos['importe_descuentos'] ?? null,
$datos['fecha_posteriores'] ?? null, $datos['importe_posteriores'] ?? null,
$datos['fecha_contribuciones'] ?? null, $datos['importe_contribuciones'] ?? null,
$datos['fecha_pagos_vendedor'] ?? null, $datos['importe_pagos_vendedor'] ?? null,
$id
];
break;
case '66':
$sql = "UPDATE mve_facturas_datos SET
art66_fecha_comisiones = ?, art66_importe_comisiones = ?, art66_cargo_comisiones = ?,
art66_fecha_envases = ?, art66_importe_envases = ?, art66_cargo_envases = ?,
art66_fecha_embalaje = ?, art66_importe_embalaje = ?, art66_cargo_embalaje = ?,
art66_fecha_transporte_dec = ?, art66_importe_transporte_dec = ?, art66_cargo_transporte_dec = ?,
art66_fecha_ingenieria = ?, art66_importe_ingenieria = ?, art66_cargo_ingenieria = ?,
art66_fecha_regalias = ?, art66_importe_regalias = ?, art66_cargo_regalias = ?,
art66_fecha_producto = ?, art66_importe_producto = ?, art66_cargo_producto = ?
WHERE id = ?";
$params = [
$datos['fecha_comisiones'] ?? null, $datos['importe_comisiones'] ?? null, $datos['cargo_comisiones'] ?? null,
$datos['fecha_envases'] ?? null, $datos['importe_envases'] ?? null, $datos['cargo_envases'] ?? null,
$datos['fecha_embalaje'] ?? null, $datos['importe_embalaje'] ?? null, $datos['cargo_embalaje'] ?? null,
$datos['fecha_transporte_dec'] ?? null, $datos['importe_transporte_dec'] ?? null, $datos['cargo_transporte_dec'] ?? null,
$datos['fecha_ingenieria'] ?? null, $datos['importe_ingenieria'] ?? null, $datos['cargo_ingenieria'] ?? null,
$datos['fecha_regalias'] ?? null, $datos['importe_regalias'] ?? null, $datos['cargo_regalias'] ?? null,
$datos['fecha_producto'] ?? null, $datos['importe_producto'] ?? null, $datos['cargo_producto'] ?? null,
$id
];
break;
case 'precio_pagado':
$sql = "UPDATE mve_facturas_datos SET
precio_pagado_fecha_pago = ?, precio_pagado_importe = ?, precio_pagado_moneda = ?,
precio_pagado_forma_pago = ?, precio_pagado_referencia = ?
WHERE id = ?";
$params = [
$datos['fecha_precio_pagado'] ?? null,
$datos['importe_precio_pagado'] ?? null,
$datos['moneda_precio_pagado'] ?? null,
$datos['forma_pago_precio_pagado'] ?? null,
$datos['referencia_precio_pagado'] ?? null,
$id
];
break;
case 'precio_pagar':
$sql = "UPDATE mve_facturas_datos SET
precio_pagar_fecha_limite = ?, precio_pagar_importe = ?, precio_pagar_moneda = ?,
precio_pagar_terminos = ?, precio_pagar_observaciones = ?
WHERE id = ?";
$params = [
$datos['fecha_limite_pago'] ?? null,
$datos['importe_precio_pagar'] ?? null,
$datos['moneda_precio_pagar'] ?? null,
$datos['terminos_precio_pagar'] ?? null,
$datos['observaciones_precio_pagar'] ?? null,
$id
];
break;
case 'compenso':
$sql = "UPDATE mve_facturas_datos SET
compenso_fecha = ?, compenso_importe = ?, compenso_tipo = ?,
compenso_motivo = ?, compenso_documentos = ?, compenso_descripcion = ?
WHERE id = ?";
$params = [
$datos['fecha_compenso'] ?? null,
$datos['importe_compenso'] ?? null,
$datos['tipo_compenso'] ?? null,
$datos['motivo_compenso'] ?? null,
$datos['documentos_compenso'] ?? null,
$datos['descripcion_compenso'] ?? null,
$id
];
break;
default:
echo json_encode(['success' => false, 'message' => 'Sección inválida']);
return;
}
$stmt = sqlsrv_query($conn, $sql, $params);
if ($stmt === false) {
echo json_encode(['success' => false, 'message' => 'Error al guardar sección']);
return;
}
// Marcar estado para badge
upsert_cove_respuesta_min($conn, $id_pedimento, $id_factura, $usuario_id);
echo json_encode(['success' => true]);
}
function ajax_obtener_datos_factura()
{
$id_factura = isset($_GET['id_factura']) ? (int)$_GET['id_factura'] : 0;
if ($id_factura <= 0) { echo json_encode(['success' => false, 'message' => 'ID inválido']); return; }
$conn = getConnection();
$stmt = sqlsrv_query($conn, "SELECT * FROM mve_facturas_datos WHERE id_factura = ?", [$id_factura]);
if ($stmt === false) { echo json_encode(['success' => false, 'message' => 'Error DB']); return; }
$datos = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC);
if ($stmt) sqlsrv_free_stmt($stmt);
if ($datos) {
// Formateador de fechas seguro para JSON
$fmtDate = function($v) {
if ($v instanceof DateTime) return $v->format('Y-m-d');
if (is_string($v)) return substr($v, 0, 10);
return $v ?: null;
};
if (isset($datos['fecha_actualizacion']) && $datos['fecha_actualizacion'] instanceof DateTime) {
$datos['fecha_actualizacion'] = $datos['fecha_actualizacion']->format('Y-m-d H:i:s');
}
$datosEstructurados = [
'art65' => [
'fecha_transporte' => $fmtDate($datos['art65_fecha_transporte'] ?? null),
'importe_transporte' => $datos['art65_importe_transporte'] ?? null,
'fecha_descuentos' => $fmtDate($datos['art65_fecha_descuentos'] ?? null),
'importe_descuentos' => $datos['art65_importe_descuentos'] ?? null,
'fecha_posteriores' => $fmtDate($datos['art65_fecha_posteriores'] ?? null),
'importe_posteriores' => $datos['art65_importe_posteriores'] ?? null,
'fecha_contribuciones' => $fmtDate($datos['art65_fecha_contribuciones'] ?? null),
'importe_contribuciones' => $datos['art65_importe_contribuciones'] ?? null,
'fecha_pagos_vendedor' => $fmtDate($datos['art65_fecha_pagos_vendedor'] ?? null),
'importe_pagos_vendedor' => $datos['art65_importe_pagos_vendedor'] ?? null,
],
'art66' => [
'fecha_comisiones' => $fmtDate($datos['art66_fecha_comisiones'] ?? null),
'importe_comisiones' => $datos['art66_importe_comisiones'] ?? null,
'cargo_comisiones' => $datos['art66_cargo_comisiones'] ?? null,
'fecha_envases' => $fmtDate($datos['art66_fecha_envases'] ?? null),
'importe_envases' => $datos['art66_importe_envases'] ?? null,
'cargo_envases' => $datos['art66_cargo_envases'] ?? null,
'fecha_embalaje' => $fmtDate($datos['art66_fecha_embalaje'] ?? null),
'importe_embalaje' => $datos['art66_importe_embalaje'] ?? null,
'cargo_embalaje' => $datos['art66_cargo_embalaje'] ?? null,
'fecha_transporte_dec' => $fmtDate($datos['art66_fecha_transporte_dec'] ?? null),
'importe_transporte_dec' => $datos['art66_importe_transporte_dec'] ?? null,
'cargo_transporte_dec' => $datos['art66_cargo_transporte_dec'] ?? null,
'fecha_ingenieria' => $fmtDate($datos['art66_fecha_ingenieria'] ?? null),
'importe_ingenieria' => $datos['art66_importe_ingenieria'] ?? null,
'cargo_ingenieria' => $datos['art66_cargo_ingenieria'] ?? null,
'fecha_regalias' => $fmtDate($datos['art66_fecha_regalias'] ?? null),
'importe_regalias' => $datos['art66_importe_regalias'] ?? null,
'cargo_regalias' => $datos['art66_cargo_regalias'] ?? null,
'fecha_producto' => $fmtDate($datos['art66_fecha_producto'] ?? null),
'importe_producto' => $datos['art66_importe_producto'] ?? null,
'cargo_producto' => $datos['art66_cargo_producto'] ?? null,
],
'precio_pagado' => [
'fecha_precio_pagado' => $fmtDate($datos['precio_pagado_fecha_pago'] ?? null),
'importe_precio_pagado' => $datos['precio_pagado_importe'] ?? null,
'moneda_precio_pagado' => $datos['precio_pagado_moneda'] ?? null,
'forma_pago_precio_pagado' => $datos['precio_pagado_forma_pago'] ?? null,
'referencia_precio_pagado' => $datos['precio_pagado_referencia'] ?? null,
],
'precio_pagar' => [
'fecha_limite_pago' => $fmtDate($datos['precio_pagar_fecha_limite'] ?? null),
'importe_precio_pagar' => $datos['precio_pagar_importe'] ?? null,
'moneda_precio_pagar' => $datos['precio_pagar_moneda'] ?? null,
'terminos_precio_pagar' => $datos['precio_pagar_terminos'] ?? null,
'observaciones_precio_pagar' => $datos['precio_pagar_observaciones'] ?? null,
],
'compenso' => [
'fecha_compenso' => $fmtDate($datos['compenso_fecha'] ?? null),
'importe_compenso' => $datos['compenso_importe'] ?? null,
'tipo_compenso' => $datos['compenso_tipo'] ?? null,
'motivo_compenso' => $datos['compenso_motivo'] ?? null,
'documentos_compenso' => $datos['compenso_documentos'] ?? null,
'descripcion_compenso' => $datos['compenso_descripcion'] ?? null,
]
];
$stmt = $db->prepare($sql);
$resultado = $stmt->execute($params);
if ($resultado) {
echo json_encode(['success' => true, 'message' => 'Datos guardados correctamente']);
} else {
echo json_encode(['success' => false, 'message' => 'Error al guardar los datos']);
}
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => 'Error interno: ' . $e->getMessage()]);
echo json_encode(['success' => true, 'datos' => $datosEstructurados]);
} else {
echo json_encode(['success' => true, 'datos' => null]);
}
}
function ajax_obtener_datos_factura() {
try {
$id_factura = $_GET['id_factura'] ?? null;
// Utilidad: marca/crea un registro mínimo en cove_respuestas para encender el badge
function upsert_cove_respuesta_min($conn, $pedimento_id, $factura_id, $usuario_id)
{
$sel = sqlsrv_query($conn, "SELECT id FROM cove_respuestas WHERE factura_id = ? AND usuario_id = ?", [$factura_id, $usuario_id]);
$row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null; if ($sel) sqlsrv_free_stmt($sel);
if ($row) {
sqlsrv_query($conn, "UPDATE cove_respuestas SET estado = 'respondido', fecha_actualizacion = SYSDATETIME() WHERE id = ?", [$row['id']]);
} else {
sqlsrv_query($conn, "INSERT INTO cove_respuestas (pedimento_id, factura_id, usuario_id, respuestas, estado, fecha_creacion) VALUES (?,?,?,?,?,SYSDATETIME())",
[$pedimento_id, $factura_id, $usuario_id, '{}', 'respondido']);
}
}
if (!$id_factura) {
echo json_encode(['success' => false, 'message' => 'ID de factura requerido']);
// Registra la solicitud de MVE con aceptación de declaración del importador
function ajax_registrar_solicitud()
{
header('Content-Type: application/json; charset=UTF-8');
if (!($_SESSION['usuario_id'] ?? false)) {
http_response_code(403);
echo json_encode(['success' => false, 'message' => 'No autorizado']);
return;
}
$usuario_id = (int)$_SESSION['usuario_id'];
$pedimento_id = isset($_POST['pedimento_id']) ? (int)$_POST['pedimento_id'] : 0;
$factura_id = isset($_POST['factura_id']) ? (int)$_POST['factura_id'] : 0;
$acepto = isset($_POST['acepto']) ? (int)$_POST['acepto'] : 0;
$rfc_importador = isset($_POST['rfc_importador']) ? trim($_POST['rfc_importador']) : null;
$firma_base64 = isset($_POST['firma_base64']) ? $_POST['firma_base64'] : null;
$firmante = isset($_POST['firmante']) ? trim($_POST['firmante']) : null;
$ip = $_SERVER['REMOTE_ADDR'] ?? null;
if ($pedimento_id <= 0 || $factura_id <= 0) { echo json_encode(['success' => false, 'message' => 'Parámetros inválidos']); return; }
if ($acepto !== 1) { echo json_encode(['success' => false, 'message' => 'Debes aceptar la declaración']); return; }
$conn = getConnection();
// Verificar propiedad y relación factura-pedimento
$chk = sqlsrv_query($conn, "SELECT 1 FROM pedimentos p JOIN pedimento_facturas f ON f.pedimento_id = p.id WHERE p.id = ? AND f.id = ? AND p.usuario_id = ?", [$pedimento_id, $factura_id, $usuario_id]);
$ok = $chk && sqlsrv_fetch_array($chk) ? true : false; if ($chk) sqlsrv_free_stmt($chk);
if (!$ok) { echo json_encode(['success' => false, 'message' => 'No autorizado o relación inválida']); return; }
// Asegurar tabla mve_solicitudes
$sqlEnsure = "
IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[mve_solicitudes]') AND type in (N'U'))
BEGIN
CREATE TABLE dbo.mve_solicitudes (
id INT IDENTITY(1,1) PRIMARY KEY,
pedimento_id INT NOT NULL,
factura_id INT NOT NULL,
usuario_id INT NOT NULL,
acepto_declaracion BIT NOT NULL,
rfc_importador NVARCHAR(20) NULL,
ip NVARCHAR(64) NULL,
fecha_solicitud DATETIME2 NOT NULL DEFAULT SYSDATETIME(),
comentario NVARCHAR(400) NULL,
firma_base64 NVARCHAR(MAX) NULL,
firmante NVARCHAR(200) NULL
);
CREATE INDEX IX_mve_solicitudes_factura ON dbo.mve_solicitudes(factura_id);
END;
-- Ensure all expected columns exist on legacy tables
IF COL_LENGTH('dbo.mve_solicitudes','pedimento_id') IS NULL ALTER TABLE dbo.mve_solicitudes ADD pedimento_id INT NULL;
IF COL_LENGTH('dbo.mve_solicitudes','factura_id') IS NULL ALTER TABLE dbo.mve_solicitudes ADD factura_id INT NULL;
IF COL_LENGTH('dbo.mve_solicitudes','usuario_id') IS NULL ALTER TABLE dbo.mve_solicitudes ADD usuario_id INT NULL;
IF COL_LENGTH('dbo.mve_solicitudes','acepto_declaracion') IS NULL ALTER TABLE dbo.mve_solicitudes ADD acepto_declaracion BIT NULL;
IF COL_LENGTH('dbo.mve_solicitudes','rfc_importador') IS NULL ALTER TABLE dbo.mve_solicitudes ADD rfc_importador NVARCHAR(20) NULL;
IF COL_LENGTH('dbo.mve_solicitudes','ip') IS NULL ALTER TABLE dbo.mve_solicitudes ADD ip NVARCHAR(64) NULL;
IF COL_LENGTH('dbo.mve_solicitudes','fecha_solicitud') IS NULL ALTER TABLE dbo.mve_solicitudes ADD fecha_solicitud DATETIME2 NULL;
IF COL_LENGTH('dbo.mve_solicitudes','comentario') IS NULL ALTER TABLE dbo.mve_solicitudes ADD comentario NVARCHAR(400) NULL;
IF COL_LENGTH('dbo.mve_solicitudes', 'firma_base64') IS NULL ALTER TABLE dbo.mve_solicitudes ADD firma_base64 NVARCHAR(MAX) NULL;
IF COL_LENGTH('dbo.mve_solicitudes', 'firmante') IS NULL ALTER TABLE dbo.mve_solicitudes ADD firmante NVARCHAR(200) NULL;
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_mve_solicitudes_factura' AND object_id = OBJECT_ID('dbo.mve_solicitudes'))
CREATE INDEX IX_mve_solicitudes_factura ON dbo.mve_solicitudes(factura_id);
";
$ensureOk = sqlsrv_query($conn, $sqlEnsure);
if ($ensureOk === false) {
$err = sqlsrv_errors();
echo json_encode(['success' => false, 'message' => 'Error al preparar tabla de solicitudes', 'detail' => $err]);
return;
}
// Determinar columnas legacy (id_*) y nuevas (*_id) disponibles
$has_id_ped = false; $has_id_fac = false; $has_id_usr = false;
$chkCols = sqlsrv_query($conn, "SELECT name FROM sys.columns WHERE object_id = OBJECT_ID('dbo.mve_solicitudes') AND name IN ('id_pedimento','id_factura','id_usuario','pedimento_id','factura_id','usuario_id')");
if ($chkCols) {
while ($c = sqlsrv_fetch_array($chkCols, SQLSRV_FETCH_ASSOC)) {
if ($c['name'] === 'id_pedimento') $has_id_ped = true;
if ($c['name'] === 'id_factura') $has_id_fac = true;
if ($c['name'] === 'id_usuario') $has_id_usr = true;
}
sqlsrv_free_stmt($chkCols);
}
// Validar firma obligatoria
if (!$firma_base64 || trim($firma_base64) === '') {
echo json_encode(['success' => false, 'message' => 'La firma es obligatoria']);
return;
}
$db = getDB();
$stmt = $db->prepare("SELECT * FROM mve_facturas_datos WHERE id_factura = ?");
$stmt->execute([$id_factura]);
$datos = $stmt->fetch(PDO::FETCH_ASSOC);
// Construir INSERT dinámico para soportar ambos esquemas
$cols = [];
$vals = [];
$paramsIns = [];
// IDs
$cols[] = 'pedimento_id'; $vals[] = '?'; $paramsIns[] = $pedimento_id;
if ($has_id_ped) { $cols[] = 'id_pedimento'; $vals[] = '?'; $paramsIns[] = $pedimento_id; }
$cols[] = 'factura_id'; $vals[] = '?'; $paramsIns[] = $factura_id;
if ($has_id_fac) { $cols[] = 'id_factura'; $vals[] = '?'; $paramsIns[] = $factura_id; }
$cols[] = 'usuario_id'; $vals[] = '?'; $paramsIns[] = $usuario_id;
if ($has_id_usr) { $cols[] = 'id_usuario'; $vals[] = '?'; $paramsIns[] = $usuario_id; }
// Resto de columnas
$cols = array_merge($cols, ['acepto_declaracion','rfc_importador','ip','firma_base64','firmante']);
$vals = array_merge($vals, array_fill(0, 5, '?'));
$paramsIns = array_merge($paramsIns, [1, $rfc_importador, $ip, $firma_base64, $firmante]);
if ($datos) {
// Estructurar datos para el frontend
$datosEstructurados = [
'art65' => [
'fecha_transporte' => $datos['art65_fecha_transporte'],
'importe_transporte' => $datos['art65_importe_transporte'],
'fecha_descuentos' => $datos['art65_fecha_descuentos'],
'importe_descuentos' => $datos['art65_importe_descuentos'],
'fecha_posteriores' => $datos['art65_fecha_posteriores'],
'importe_posteriores' => $datos['art65_importe_posteriores'],
'fecha_contribuciones' => $datos['art65_fecha_contribuciones'],
'importe_contribuciones' => $datos['art65_importe_contribuciones'],
'fecha_pagos_vendedor' => $datos['art65_fecha_pagos_vendedor'],
'importe_pagos_vendedor' => $datos['art65_importe_pagos_vendedor']
],
'art66' => [
'fecha_comisiones' => $datos['art66_fecha_comisiones'],
'importe_comisiones' => $datos['art66_importe_comisiones'],
'cargo_comisiones' => $datos['art66_cargo_comisiones'],
'fecha_envases' => $datos['art66_fecha_envases'],
'importe_envases' => $datos['art66_importe_envases'],
'cargo_envases' => $datos['art66_cargo_envases'],
'fecha_embalaje' => $datos['art66_fecha_embalaje'],
'importe_embalaje' => $datos['art66_importe_embalaje'],
'cargo_embalaje' => $datos['art66_cargo_embalaje'],
'fecha_transporte_dec' => $datos['art66_fecha_transporte_dec'],
'importe_transporte_dec' => $datos['art66_importe_transporte_dec'],
'cargo_transporte_dec' => $datos['art66_cargo_transporte_dec'],
'fecha_ingenieria' => $datos['art66_fecha_ingenieria'],
'importe_ingenieria' => $datos['art66_importe_ingenieria'],
'cargo_ingenieria' => $datos['art66_cargo_ingenieria'],
'fecha_regalias' => $datos['art66_fecha_regalias'],
'importe_regalias' => $datos['art66_importe_regalias'],
'cargo_regalias' => $datos['art66_cargo_regalias'],
'fecha_producto' => $datos['art66_fecha_producto'],
'importe_producto' => $datos['art66_importe_producto'],
'cargo_producto' => $datos['art66_cargo_producto']
]
];
echo json_encode(['success' => true, 'datos' => $datosEstructurados]);
} else {
echo json_encode(['success' => true, 'datos' => null]);
$sqlIns = 'INSERT INTO mve_solicitudes (' . implode(',', $cols) . ') VALUES (' . implode(',', $vals) . ')';
$ins = sqlsrv_query($conn, $sqlIns, $paramsIns);
if ($ins === false) {
$err = sqlsrv_errors();
$msg = 'No se pudo registrar la solicitud';
if ($err && isset($err[0]['message'])) { $msg .= ': ' . $err[0]['message']; }
echo json_encode(['success' => false, 'message' => $msg]);
return;
}
} catch (Exception $e) {
echo json_encode(['success' => false, 'message' => 'Error interno: ' . $e->getMessage()]);
}
// Actualizar estado en cove_respuestas a 'solicitado'
$sel = sqlsrv_query($conn, "SELECT id FROM cove_respuestas WHERE factura_id = ? AND usuario_id = ?", [$factura_id, $usuario_id]);
$row = $sel ? sqlsrv_fetch_array($sel, SQLSRV_FETCH_ASSOC) : null; if ($sel) sqlsrv_free_stmt($sel);
if ($row) {
sqlsrv_query($conn, "UPDATE cove_respuestas SET estado = 'solicitado', fecha_actualizacion = SYSDATETIME() WHERE id = ?", [$row['id']]);
} else {
sqlsrv_query($conn, "INSERT INTO cove_respuestas (usuario_id, pedimento_id, factura_id, estado, fecha_actualizacion) VALUES (?, ?, ?, 'solicitado', SYSDATETIME())", [$usuario_id, $pedimento_id, $factura_id]);
}
// Generar documentos de prueba (acuse y detalle) en el expediente del pedimento
$usuario_nombre = $_SESSION['usuario_nombre'] ?? 'sistema';
mve_generar_documentos_expediente($conn, $pedimento_id, $usuario_nombre);
echo json_encode(['success' => true]);
}

View File

@@ -0,0 +1,19 @@
<?php
session_start();
header('Content-Type: application/json; charset=utf-8');
// Simple test endpoint
echo json_encode([
'success' => true,
'message' => 'Conexión exitosa',
'timestamp' => date('Y-m-d H:i:s'),
'usuario' => isset($_SESSION['usuario']) ? $_SESSION['usuario']['nombre'] ?? 'Usuario logueado' : 'No hay usuario',
'post_data' => $_POST,
'files_data' => isset($_FILES['archivo']) ? [
'nombre' => $_FILES['archivo']['name'],
'tamaño' => $_FILES['archivo']['size'],
'tipo' => $_FILES['archivo']['type'],
'error' => $_FILES['archivo']['error']
] : 'No hay archivo'
]);
?>