Preparando proyecto para migración a repositorio MVE
This commit is contained in:
739
public/importar_pedimentos.php
Normal file
739
public/importar_pedimentos.php
Normal file
@@ -0,0 +1,739 @@
|
||||
<?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("POST recibido: " . print_r($_POST, true));
|
||||
error_log("FILES recibido: " . print_r($_FILES, true));
|
||||
error_log("Tiene archivo individual: " . (isset($_FILES['archivo']) ? 'SÍ' : 'NO'));
|
||||
error_log("Tiene archivos múltiples: " . (isset($_FILES['archivos']) ? 'SÍ' : 'NO'));
|
||||
|
||||
// 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 (individual o múltiple)
|
||||
if (!isset($_FILES['archivo']) && !isset($_FILES['archivos'])) {
|
||||
error_log("ERROR: No se encontraron archivos. FILES: " . print_r($_FILES, true));
|
||||
http_response_code(400);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'No se ha recibido ningún archivo válido',
|
||||
'debug' => $_FILES
|
||||
]);
|
||||
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) {
|
||||
// Reiniciar estadísticas y acumuladores por archivo para evitar sobreconteo entre múltiples archivos
|
||||
$this->estadisticas = [
|
||||
'total_lineas' => 0,
|
||||
'pedimentos_procesados' => 0,
|
||||
'facturas_procesadas' => 0,
|
||||
'partidas_procesadas' => 0,
|
||||
'errores' => 0,
|
||||
'duplicados' => 0
|
||||
];
|
||||
$this->errores_detalle = [];
|
||||
$this->pedimentos_creados = [];
|
||||
|
||||
$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, moneda, proveedor)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
$params = [
|
||||
$pedimento_id,
|
||||
$factura['numero_factura'],
|
||||
$factura['fecha_factura'],
|
||||
$factura['valor_dolares'],
|
||||
$factura['valor_factura'],
|
||||
isset($factura['cove']) ? $factura['cove'] : null,
|
||||
isset($factura['moneda']) ? $factura['moneda'] : 'USD',
|
||||
isset($factura['proveedor']) ? $factura['proveedor'] : 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
|
||||
}
|
||||
}
|
||||
|
||||
// Procesamiento de archivos (individual o múltiple)
|
||||
try {
|
||||
error_log("=== PROCESAMIENTO DE ARCHIVOS ===");
|
||||
error_log("POST: " . print_r($_POST, true));
|
||||
error_log("FILES: " . print_r($_FILES, true));
|
||||
|
||||
$validar_duplicados = isset($_POST['validar_duplicados']) && $_POST['validar_duplicados'] === 'on';
|
||||
error_log("Validar duplicados: " . ($validar_duplicados ? 'SÍ' : 'NO'));
|
||||
|
||||
// Validar variables de entorno requeridas ANTES de intentar conectar (evita die() dentro de getConnection)
|
||||
$requiredEnv = ['DB_HOST','DB_DATABASE','DB_USERNAME','DB_PASSWORD'];
|
||||
foreach ($requiredEnv as $envKey) {
|
||||
if (!isset($_ENV[$envKey]) || $_ENV[$envKey] === '') {
|
||||
throw new Exception("Falta configurar la variable de entorno $envKey en el archivo .env");
|
||||
}
|
||||
}
|
||||
|
||||
// Obtener conexión a SQL Server
|
||||
$conn = getConnection();
|
||||
$importador = new ImportadorPedimentos($conn);
|
||||
|
||||
$resultado_final = null;
|
||||
|
||||
// Verificar si es archivo individual
|
||||
if (isset($_FILES['archivo'])) {
|
||||
error_log("=== PROCESAMIENTO INDIVIDUAL ===");
|
||||
$archivo_temporal = $_FILES['archivo']['tmp_name'];
|
||||
$nombre_archivo = $_FILES['archivo']['name'];
|
||||
|
||||
$resultado_final = $importador->procesarArchivo($archivo_temporal, $validar_duplicados);
|
||||
|
||||
} else if (isset($_FILES['archivos']) && is_array($_FILES['archivos']['name'])) {
|
||||
error_log("=== PROCESAMIENTO MÚLTIPLE FORMATO NORMAL ===");
|
||||
|
||||
$archivos = $_FILES['archivos'];
|
||||
$estadisticas_globales = [
|
||||
'pedimentos_procesados' => 0,
|
||||
'facturas_procesadas' => 0,
|
||||
'partidas_procesadas' => 0,
|
||||
'duplicados' => 0,
|
||||
'errores' => 0,
|
||||
'total_lineas' => 0
|
||||
];
|
||||
|
||||
$archivos_procesados = 0;
|
||||
$archivos_con_errores = [];
|
||||
|
||||
// Procesar cada archivo individualmente
|
||||
for ($i = 0; $i < count($archivos['name']); $i++) {
|
||||
if ($archivos['error'][$i] !== UPLOAD_ERR_OK) {
|
||||
$archivos_con_errores[] = [
|
||||
'archivo' => $archivos['name'][$i],
|
||||
'error' => 'Error en la subida del archivo (código: ' . $archivos['error'][$i] . ')'
|
||||
];
|
||||
continue;
|
||||
}
|
||||
|
||||
$nombre_archivo = $archivos['name'][$i];
|
||||
$archivo_temporal = $archivos['tmp_name'][$i];
|
||||
|
||||
error_log("Procesando archivo: $nombre_archivo");
|
||||
|
||||
try {
|
||||
$resultado = $importador->procesarArchivo($archivo_temporal, $validar_duplicados);
|
||||
|
||||
if ($resultado['success']) {
|
||||
$estadisticas_globales['pedimentos_procesados'] += $resultado['estadisticas']['pedimentos_procesados'];
|
||||
$estadisticas_globales['facturas_procesadas'] += $resultado['estadisticas']['facturas_procesadas'];
|
||||
$estadisticas_globales['partidas_procesadas'] += $resultado['estadisticas']['partidas_procesadas'];
|
||||
$estadisticas_globales['duplicados'] += $resultado['estadisticas']['duplicados'];
|
||||
$estadisticas_globales['errores'] += $resultado['estadisticas']['errores'];
|
||||
$estadisticas_globales['total_lineas'] += $resultado['estadisticas']['total_lineas'];
|
||||
|
||||
$archivos_procesados++;
|
||||
error_log("Archivo procesado exitosamente: $nombre_archivo");
|
||||
} else {
|
||||
$archivos_con_errores[] = [
|
||||
'archivo' => $nombre_archivo,
|
||||
'error' => $resultado['message'] ?? 'Error desconocido'
|
||||
];
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$archivos_con_errores[] = [
|
||||
'archivo' => $nombre_archivo,
|
||||
'error' => $e->getMessage()
|
||||
];
|
||||
error_log("Excepción procesando archivo: $nombre_archivo - " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$resultado_final = [
|
||||
'success' => $archivos_procesados > 0,
|
||||
'estadisticas' => $estadisticas_globales,
|
||||
'archivos_procesados' => $archivos_procesados,
|
||||
'total_archivos' => count($archivos['name']),
|
||||
'archivos_con_errores' => $archivos_con_errores
|
||||
];
|
||||
|
||||
if ($archivos_procesados === 0) {
|
||||
$resultado_final['message'] = 'No se pudo procesar ningún archivo correctamente';
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Exception("No se recibieron archivos para procesar");
|
||||
}
|
||||
|
||||
// Cerrar conexión
|
||||
sqlsrv_close($conn);
|
||||
|
||||
// Enviar respuesta
|
||||
echo json_encode($resultado_final);
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("ERROR GENERAL: " . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Error del servidor: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user