From 2e35375a3a24d447a6947a19cc04e121a9897224 Mon Sep 17 00:00:00 2001 From: "Kevin A. Rosales Marquez" Date: Fri, 12 Sep 2025 15:59:13 -0600 Subject: [PATCH] Se modifico seccion de reportes --- src/data/datastageModels.json | 440 +++++++++++++++++++ src/data/pedimentosModels.json | 50 +++ src/pages/Reports.jsx | 745 ++++++++++++++++++++++++--------- 3 files changed, 1026 insertions(+), 209 deletions(-) create mode 100644 src/data/datastageModels.json create mode 100644 src/data/pedimentosModels.json diff --git a/src/data/datastageModels.json b/src/data/datastageModels.json new file mode 100644 index 0000000..b82d3f6 --- /dev/null +++ b/src/data/datastageModels.json @@ -0,0 +1,440 @@ +{ + "models": [ + + { + "model": "Registro501", + "name": "Datos generales", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "tipo_operacion", "clave_documento", + "seccion_aduanera_entrada", "curp_contribuyente", "rfc", "curp_agente_a", "tipo_cambio", + "total_fletes", "total_seguros", "total_embalajes", "total_incrementables", "total_deducibles", + "peso_bruto_mercancia", "medio_transporte_salida", "medio_transporte_arribo", + "medio_transporte_entrada_salida", "destino_mercancia", "nombre_contribuyente", + "calle_contribuyente", "num_interior_contribuyente", "num_exterior_contribuyente", + "cp_contribuyente", "municipio_contribuyente", "entidad_fed_contribuyente", "pais_contribuyente", + "tipo_pedimento", "fecha_recepcion_pedimento", "fecha_pago_real", "organizacion", "consulta", + "datastage" + ], + "filters": { + "patente": "", + "pedimento": "", + "seccion_aduanera": "", + "tipo_operacion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro502", + "name": "Transporte de las mercancías", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "pedimento", "seccion_aduanera", "rfc_transportista", "curp_transportista", + "nombre_transportista", "pais_transporte", "identificador_transporte", "fecha_pago_real", + "organizacion", "created_by", "consulta", "datastage", "patente" + ], + "filters": { + "patente": "", + "pedimento": "", + "fecha_pago_real": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro503", + "name": "Guías", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "numero_guia", "tipo_guia", + "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "pedimento": "", + "fecha_pago_real": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro504", + "name": "Contenedores", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "num_contenedor", "tipo_contenedor", + "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "pedimento": "", + "num_contenedor": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro505", + "name": "Facturas", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "pedimento", "seccion_aduanera", "fecha_facturacion", "numero_factura", + "termino_facturacion", "moneda_facturacion", "valor_dolares", "valor_moneda_extranjera", + "pais_facturacion", "entidad_fed_facturacion", "indent_fiscal_proveedor", + "proveedor_mercancia", "calle_proveedor", "num_interior_proveedor", "num_exterior_proveedor", + "cp_proveedor", "municipio_proveedor", "fecha_pago_real", "organizacion", "created_by", + "consulta", "datastage", "patente" + ], + "filters": { + "pedimento": "", + "numero_factura": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro506", + "name": "Fechas del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "tipo_fecha", "fecha_operacion", + "fecha_validacion_pago_r", "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "fecha_operacion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro507", + "name": "Casos del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "clave_caso", "identificador_caso", + "tipo_pedimento", "complemento_caso", "fecha_validacion_pago_r", "organizacion", + "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "clave_caso": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro508", + "name": "Cuentas aduaneras de garantía del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "institucion_emisora", "numero_cuenta", + "folio_constancia", "fecha_constancia", "tipo_cuenta", "clave_garantia", + "valor_unitario_titulo", "total_garantia", "cantidad_unidades", "titulos_asignados", + "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "institucion_emisora": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro509", + "name": "Tasas del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", + "tasa_contribucion", "tipo_tasa", "tipo_pedimento", "fecha_pago_real", + "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "clave_contribucion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro510", + "name": "Contribuciones del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", + "tasa_contribucion", "tipo_tasa", "tipo_pedimento", "fecha_pago_real", + "organizacion", "created_by", "datastage", "consulta", "forma_pago", "importe_pago" + ], + "filters": { + "patente": "", + "clave_contribucion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro511", + "name": "Observaciones del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "secuencia_observacion", + "observaciones", "tipo_pedimento", "fecha_validacion_pago_r", "organizacion", + "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "secuencia_observacion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro512", + "name": "Descargos de mercancías", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "patente_aduanal_orig", + "pedimento_original", "seccion_aduanera_desp_orig", "documento_original", + "fecha_operacion_orig", "fraccion_original", "unidad_medida", "mercancia_descargada", + "tipo_pedimento", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "patente_aduanal_orig": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro520", + "name": "Destinatarios de la mercancía", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "indent_fiscal_destinatario", + "nombre_destinatario_mercancia", "calle_destinatario", "num_interior_destinatario", + "num_exterior_destinatario", "cp_destinatario", "municpio_destinatario", + "pais_destinatario", "fecha_pago_real", "organizacion", "created_at", + "consulta", "datastage" + ], + "filters": { + "patente": "", + "indent_fiscal_destinatario": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro551", + "name": "Partidas", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "subdivision_fraccion", "descripcion_mercancia", "precio_unitario", "valor_aduana", + "valor_comercial", "valor_dolares", "cantidad_um_comercial", "unidad_medida_comercial", + "cantidad_um_tarifa", "unidad_medida_tarifa", "valor_agregado", "clave_vinculacion", + "metodo_valorizacion", "codigo_mercancia_producto", "marca_mercancia_producto", + "modelo_mercancia_producto", "pais_origen_destino", "pais_comprador_vendedor", + "entidad_fed_origen", "entidad_fed_comprador", "entidad_fed_vendedor", + "tipo_operacion", "clave_documento", "fecha_pago_real", "organizacion", + "created_by", "consulta", "datastage", "entidad_fed_destino" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro552", + "name": "Mercancías", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "vin_numero_serie", "kilometraje_vehiculo", "fecha_pago_real", "organizacion", + "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro553", + "name": "Permiso de la partida", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "clave_permiso", "firma_descargo", "numero_permiso", "valor_comercial_dolares", + "cantidad_mum_tarifa", "fecha_pago_real", "organizacion", "created_by", + "datastage", "consulta" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro554", + "name": "Casos de la partida", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "clave_caso", "identificador_caso", "complemento_caso", "fecha_pago_real", + "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro555", + "name": "Cuentas aduaneras de garantía de la partida", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "institucion_emisora", "numero_cuenta", "folio_constancia", "fecha_constancia", + "clave_garantia", "valor_unitario_titulo", "total_garantia", "cantidad_unidades_medida", + "titulos_asignados", "fecha_pago_real", "organizacion", "datastage", "created_by", + "consulta" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro556", + "name": "Tasas de las contribuciones de la partida", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", + "tasa_contribucion", "tipo_tasa", "fecha_pago_real", "organizacion", + "created_by", "consulta", "datastage", "fraccion", "secuencia_fraccion" + ], + "filters": { + "patente": "", + "clave_contribucion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro557", + "name": "Contribuciones de la partida", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "clave_contribucion", "forma_pago", "importe_pago", "fecha_pago_real", + "organizacion", "created_by", "datastage", "consulta" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro558", + "name": "Observaciones de la partida", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", + "secuencia_observacion", "observaciones", "fecha_pago_real", "organizacion", + "created_by", "datastage", "consulta" + ], + "filters": { + "patente": "", + "fraccion": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "RegistroSel", + "name": "Registros de selección", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "consecutivo_remesa", + "numero_seleccion", "fecha_seleccion", "hora_seleccion", "semaforo_fiscal", + "clave_documento", "tipo_operacion", "organizacion", "created_by", + "consulta", "datastage" + ], + "filters": { + "patente": "", + "consecutivo_remesa": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro701", + "name": "Rectificaciones", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "clave_documento", + "fecha_pago", "pedimento_anterior", "patente_anterior", "seccion_aduanera_anterior", + "documento_anterior", "fecha_operacion_anterior", "pedimento_original", + "patente_aduanal_orig", "seccion_aduanera_desp_orig", "fecha_pago_real", + "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "pedimento_anterior": "", + "organizacion": "", + "datastage": "" + } + }, + { + "model": "Registro702", + "name": "Diferencias de contribuciones del pedimento", + "module": "datastage", + "type": "excel", + "fields": [ + "id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", + "forma_pago", "importe_pago", "tipo_pedimento", "fecha_pago_real", + "organizacion", "created_by", "consulta", "datastage" + ], + "filters": { + "patente": "", + "clave_contribucion": "", + "organizacion": "", + "datastage": "" + } + } + ] +} diff --git a/src/data/pedimentosModels.json b/src/data/pedimentosModels.json new file mode 100644 index 0000000..522dabf --- /dev/null +++ b/src/data/pedimentosModels.json @@ -0,0 +1,50 @@ +{ + "models": [ + { + "model": "Pedimento", + "name": "Pedimentos cargados", + "module": "customs", + "type": "excel", + "fields": [ + "id", + "pedimento", + "pedimento_app", + "patente", + "aduana", + "regimen", + "tipo_operacion", + "clave_pedimento", + "fecha_inicio", + "fecha_fin", + "fecha_pago", + "alerta", + "contribuyente", + "agente_aduanal", + "curp_apoderado", + "importe_total", + "saldo_disponible", + "importe_pedimento", + "existe_expediente", + "remesas", + "numero_partidas", + "numero_operacion", + "created_at", + "updated_at" + ], + "filters": { + "pedimento": "", + "patente": "", + "aduana": "", + "fecha_inicio": "", + "fecha_fin": "", + "fecha_pago": "", + "tipo_operacion": "", + "clave_pedimento": "", + "contribuyente": "", + "alerta": "", + "existe_expediente": "", + "remesas": "" + } + } + ] +} diff --git a/src/pages/Reports.jsx b/src/pages/Reports.jsx index db10ff9..43fc0ce 100644 --- a/src/pages/Reports.jsx +++ b/src/pages/Reports.jsx @@ -1,80 +1,102 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from 'react'; import { fetchWithAuth } from '../fetchWithAuth'; +import datastageModelsData from '../data/datastageModels.json'; +import pedimentosModelsData from '../data/pedimentosModels.json'; const API_URL = import.meta.env.VITE_EFC_API_URL; -// Animación fade-in/slide-up para bloques -const fadeInSlideUp = `@keyframes fadein-slideup { - 0% { opacity: 0; transform: translateY(40px); } - 100% { opacity: 1; transform: translateY(0); } -}`; -if (typeof document !== 'undefined' && !document.getElementById('fadein-slideup-reports')) { +// Animaciones +const animations = ` + @keyframes fadein-slideup { + 0% { opacity: 0; transform: translateY(40px); } + 100% { opacity: 1; transform: translateY(0); } + } + @keyframes shimmer { + 0% { transform: translateX(-100%); } + 100% { transform: translateX(100%); } + } + @keyframes bounce-slow { + 0%, 100% { transform: translateY(0) scale(1); } + 50% { transform: translateY(-8px) scale(1.05); } + } + @keyframes pulse-soft { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.8; } + } +`; + +// Inyectar estilos de animación +if (typeof document !== 'undefined' && !document.getElementById('reports-animations')) { const style = document.createElement('style'); - style.id = 'fadein-slideup-reports'; - style.innerHTML = fadeInSlideUp; + style.id = 'reports-animations'; + style.innerHTML = animations; document.head.appendChild(style); } export default function Reports() { const [isExporting, setIsExporting] = useState(false); + const [exportFormat, setExportFormat] = useState('excel'); + const [showExportSuccess, setShowExportSuccess] = useState(false); + + // Estado para formato de exportación personalizado + const [showFormatSelector, setShowFormatSelector] = useState(false); // Estado para pestañas const [activeTab, setActiveTab] = useState('pedimentos'); - // JSON de modelos para Datastage - const datastageModels = [ - { model: "Registro500", name: "Validación y reconocimiento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "consecutivo_remesa", "numero_seleccion", "fecha_inicio_reconocimiento", "hora_inicio_reconocimiento", "fecha_fin_reconocimiento", "hora_fin_reconocimiento", "fraccion", "secuencia_fraccion", "clave_documento", "tipo_operacion", "grado_incidencia", "fecha_seleccion", "organizacion", "consulta", "datastage", "created_at", "updated_at"], filters: {patente: "", pedimento: "", seccion_aduanera: "", fecha_seleccion: "", organizacion: "", datastage: ""}}, - { model: "Registro501", name: "Datos generales", fields: ["id", "patente", "pedimento", "seccion_aduanera", "tipo_operacion", "clave_documento", "seccion_aduanera_entrada", "curp_contribuyente", "rfc", "curp_agente_a", "tipo_cambio", "total_fletes", "total_seguros", "total_embalajes", "total_incrementables", "total_deducibles", "peso_bruto_mercancia", "medio_transporte_salida", "medio_transporte_arribo", "medio_transporte_entrada_salida", "destino_mercancia", "nombre_contribuyente", "calle_contribuyente", "num_interior_contribuyente", "num_exterior_contribuyente", "cp_contribuyente", "municipio_contribuyente", "entidad_fed_contribuyente", "pais_contribuyente", "tipo_pedimento", "fecha_recepcion_pedimento", "fecha_pago_real", "organizacion", "consulta", "datastage"], filters: {patente: "", pedimento: "", seccion_aduanera: "", tipo_operacion: "", organizacion: "", datastage: ""}}, - { model: "Registro502", name: "Transporte de las mercancías", fields: ["id", "pedimento", "seccion_aduanera", "rfc_transportista", "curp_transportista", "nombre_transportista", "pais_transporte", "identificador_transporte", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage", "patente"], filters: {patente: "", pedimento: "", fecha_pago_real: "", organizacion: "", datastage: ""}}, - { model: "Registro503", name: "Guías", fields: ["id", "patente", "pedimento", "seccion_aduanera", "numero_guia", "tipo_guia", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", pedimento: "", fecha_pago_real: "", organizacion: "", datastage: ""}}, - { model: "Registro504", name: "Contenedores", fields: ["id", "patente", "pedimento", "seccion_aduanera", "num_contenedor", "tipo_contenedor", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", pedimento: "", num_contenedor: "", organizacion: "", datastage: ""}}, - { model: "Registro505", name: "Facturas", fields: ["id", "pedimento", "seccion_aduanera", "fecha_facturacion", "numero_factura", "termino_facturacion", "moneda_facturacion", "valor_dolares", "valor_moneda_extranjera", "pais_facturacion", "entidad_fed_facturacion", "indent_fiscal_proveedor", "proveedor_mercancia", "calle_proveedor", "num_interior_proveedor", "num_exterior_proveedor", "cp_proveedor", "municipio_proveedor", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage", "patente"], filters: {pedimento: "", numero_factura: "", organizacion: "", datastage: ""}}, - { model: "Registro506", name: "Fechas del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "tipo_fecha", "fecha_operacion", "fecha_validacion_pago_r", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", fecha_operacion: "", organizacion: "", datastage: ""}}, - { model: "Registro507", name: "Casos del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "clave_caso", "identificador_caso", "tipo_pedimento", "complemento_caso", "fecha_validacion_pago_r", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", clave_caso: "", organizacion: "", datastage: ""}}, - { model: "Registro508", name: "Cuentas aduaneras de garantía del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "institucion_emisora", "numero_cuenta", "folio_constancia", "fecha_constancia", "tipo_cuenta", "clave_garantia", "valor_unitario_titulo", "total_garantia", "cantidad_unidades", "titulos_asignados", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", institucion_emisora: "", organizacion: "", datastage: ""}}, - { model: "Registro509", name: "Tasas del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", "tasa_contribucion", "tipo_tasa", "tipo_pedimento", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", clave_contribucion: "", organizacion: "", datastage: ""}}, - { model: "Registro510", name: "Contribuciones del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", "tasa_contribucion", "tipo_tasa", "tipo_pedimento", "fecha_pago_real", "organizacion", "created_by", "datastage", "consulta", "forma_pago", "importe_pago"], filters: {patente: "", clave_contribucion: "", organizacion: "", datastage: ""}}, - { model: "Registro511", name: "Observaciones del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "secuencia_observacion", "observaciones", "tipo_pedimento", "fecha_validacion_pago_r", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", secuencia_observacion: "", organizacion: "", datastage: ""}}, - { model: "Registro512", name: "Descargos de mercancías", fields: ["id", "patente", "pedimento", "seccion_aduanera", "patente_aduanal_orig", "pedimento_original", "seccion_aduanera_desp_orig", "documento_original", "fecha_operacion_orig", "fraccion_original", "unidad_medida", "mercancia_descargada", "tipo_pedimento", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", patente_aduanal_orig: "", organizacion: "", datastage: ""}}, - { model: "Registro520", name: "Destinatarios de la mercancía", fields: ["id", "patente", "pedimento", "seccion_aduanera", "indent_fiscal_destinatario", "nombre_destinatario_mercancia", "calle_destinatario", "num_interior_destinatario", "num_exterior_destinatario", "cp_destinatario", "municpio_destinatario", "pais_destinatario", "fecha_pago_real", "organizacion", "created_at", "consulta", "datastage"], filters: {patente: "", indent_fiscal_destinatario: "", organizacion: "", datastage: ""}}, - { model: "Registro551", name: "Partidas", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "subdivision_fraccion", "descripcion_mercancia", "precio_unitario", "valor_aduana", "valor_comercial", "valor_dolares", "cantidad_um_comercial", "unidad_medida_comercial", "cantidad_um_tarifa", "unidad_medida_tarifa", "valor_agregado", "clave_vinculacion", "metodo_valorizacion", "codigo_mercancia_producto", "marca_mercancia_producto", "modelo_mercancia_producto", "pais_origen_destino", "pais_comprador_vendedor", "entidad_fed_origen", "entidad_fed_comprador", "entidad_fed_vendedor", "tipo_operacion", "clave_documento", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage", "entidad_fed_destino"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "Registro552", name: "Mercancías", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "vin_numero_serie", "kilometraje_vehiculo", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "Registro553", name: "Permiso de la partida", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "clave_permiso", "firma_descargo", "numero_permiso", "valor_comercial_dolares", "cantidad_mum_tarifa", "fecha_pago_real", "organizacion", "created_by", "datastage", "consulta"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "Registro554", name: "Casos de la partida", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "clave_caso", "identificador_caso", "complemento_caso", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "Registro555", name: "Cuentas aduaneras de garantía de la partida", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "institucion_emisora", "numero_cuenta", "folio_constancia", "fecha_constancia", "clave_garantia", "valor_unitario_titulo", "total_garantia", "cantidad_unidades_medida", "titulos_asignados", "fecha_pago_real", "organizacion", "datastage", "created_by", "consulta"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "Registro556", name: "Tasas de las contribuciones de la partida", fields: ["id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", "tasa_contribucion", "tipo_tasa", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage", "fraccion", "secuencia_fraccion"], filters: {patente: "", clave_contribucion: "", organizacion: "", datastage: ""}}, - { model: "Registro557", name: "Contribuciones de la partida", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "clave_contribucion", "forma_pago", "importe_pago", "fecha_pago_real", "organizacion", "created_by", "datastage", "consulta"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "Registro558", name: "Observaciones de la partida", fields: ["id", "patente", "pedimento", "seccion_aduanera", "fraccion", "secuencia_fraccion", "secuencia_observacion", "observaciones", "fecha_pago_real", "organizacion", "created_by", "datastage", "consulta"], filters: {patente: "", fraccion: "", organizacion: "", datastage: ""}}, - { model: "RegistroSel", fields: ["id", "patente", "pedimento", "seccion_aduanera", "consecutivo_remesa", "numero_seleccion", "fecha_seleccion", "hora_seleccion", "semaforo_fiscal", "clave_documento", "tipo_operacion", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", consecutivo_remesa: "", organizacion: "", datastage: ""}}, - { model: "Registro701", name: "Rectificaciones", fields: ["id", "patente", "pedimento", "seccion_aduanera", "clave_documento", "fecha_pago", "pedimento_anterior", "patente_anterior", "seccion_aduanera_anterior", "documento_anterior", "fecha_operacion_anterior", "pedimento_original", "patente_aduanal_orig", "seccion_aduanera_desp_orig", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", pedimento_anterior: "", organizacion: "", datastage: ""}}, - { model: "Registro702", name: "Diferencias de contribuciones del pedimento", fields: ["id", "patente", "pedimento", "seccion_aduanera", "clave_contribucion", "forma_pago", "importe_pago", "tipo_pedimento", "fecha_pago_real", "organizacion", "created_by", "consulta", "datastage"], filters: {patente: "", clave_contribucion: "", organizacion: "", datastage: ""}}, - ]; + // Importar modelos + const datastageModels = datastageModelsData?.models || []; + const pedimentosModels = pedimentosModelsData?.models || []; + // Obtener el modelo inicial según la pestaña activa + const initialModels = activeTab === 'pedimentos' ? pedimentosModels : datastageModels; + const defaultModel = initialModels[0] || { model: '', fields: [], filters: {} }; - // Estado para modelo seleccionado en Datastage - const [selectedModel, setSelectedModel] = useState(datastageModels[0].model); + // Estado para modelo seleccionado + const [selectedModel, setSelectedModel] = useState(defaultModel.model); // Estado para campos seleccionados - const [selectedFields, setSelectedFields] = useState(datastageModels[0].fields); + const [selectedFields, setSelectedFields] = useState(defaultModel.fields); // Estado para campo seleccionado en lista disponible const [availableSelected, setAvailableSelected] = useState(null); // Estado para los filtros - const [filters, setFilters] = useState(datastageModels[0].filters); + const [filters, setFilters] = useState(defaultModel.filters); - // Actualizar campos seleccionados al cambiar de modelo + // Actualizar campos seleccionados al cambiar de modelo o pestaña React.useEffect(() => { - const modelObj = datastageModels.find(m => m.model === selectedModel); - setSelectedFields(modelObj.fields); - setAvailableSelected(null); - setFilters(modelObj.filters); + const models = activeTab === 'pedimentos' ? pedimentosModels : datastageModels; + // Al cambiar de pestaña, seleccionar el primer modelo de la pestaña actual + const newModel = models[0]?.model || ''; + setSelectedModel(newModel); + + const modelObj = models.find(m => m.model === newModel); + if (modelObj) { + setSelectedFields(modelObj.fields); + setAvailableSelected(null); + setFilters(modelObj.filters); + } + }, [activeTab]); + + // Efecto separado para cambios de modelo dentro de la misma pestaña + React.useEffect(() => { + const models = activeTab === 'pedimentos' ? pedimentosModels : datastageModels; + const modelObj = models.find(m => m.model === selectedModel); + if (modelObj) { + setSelectedFields(modelObj.fields); + setAvailableSelected(null); + setFilters(modelObj.filters); + } }, [selectedModel]); - // Encontrar el modelo actual - const currentModel = datastageModels.find(m => m.model === selectedModel); + // Obtener los modelos según la pestaña activa + const models = activeTab === 'pedimentos' ? pedimentosModels : datastageModels; + + // Encontrar el modelo actual dentro de los modelos de la pestaña activa + const currentModel = models.find(m => m.model === selectedModel) || defaultModel; - // Campos disponibles (no seleccionados) + // Campos disponibles (no seleccionados) del modelo actual const availableFields = currentModel.fields.filter(f => !selectedFields.includes(f)); // Mover campo de disponible a seleccionado @@ -112,32 +134,63 @@ export default function Reports() { // Función para manejar la exportación del modelo const handleExportModel = async () => { + if (selectedFields.length === 0) { + // Mostrar mensaje de error con estilo + const errorDiv = document.createElement('div'); + errorDiv.className = 'fixed top-4 right-4 bg-red-50 border-l-4 border-red-500 p-4 rounded shadow-lg'; + errorDiv.innerHTML = ` +
+
+ + + +
+
+

Por favor selecciona al menos un campo para exportar

+
+
+ `; + document.body.appendChild(errorDiv); + setTimeout(() => { + errorDiv.style.opacity = '0'; + errorDiv.style.transform = 'translateX(100%)'; + setTimeout(() => errorDiv.remove(), 300); + }, 3000); + return; + } + setIsExporting(true); try { - // Construir el objeto de filtros con los valores no vacíos - const nonEmptyFilters = {}; - for (const [key, value] of Object.entries(filters)) { - if (value && value.trim() !== '') { - nonEmptyFilters[key] = value.trim(); - } - } + // Mostrar indicador de progreso + const progressDiv = document.createElement('div'); + progressDiv.className = 'fixed bottom-4 right-4 bg-white p-4 rounded-lg shadow-xl border border-blue-100'; + progressDiv.innerHTML = ` +
+
+

Preparando exportación...

+
+ `; + document.body.appendChild(progressDiv); - // Construir el payload + // Construir filtros no vacíos + const nonEmptyFilters = Object.entries(filters) + .reduce((acc, [key, value]) => { + if (value?.trim()) { + acc[key] = value.trim(); + } + return acc; + }, {}); + + // Construir payload const payload = { model: currentModel.model, + module: currentModel.module, fields: selectedFields, - type: 'csv', // Usamos CSV como formato por defecto + type: exportFormat, + ...(Object.keys(nonEmptyFilters).length > 0 && { filters: nonEmptyFilters }), }; - // Solo agregar filtros si hay alguno con valor - if (Object.keys(nonEmptyFilters).length > 0) { - payload.filters = nonEmptyFilters; - } - - // Log para debug - console.log('Sending payload:', payload); - - // Realizar la petición POST + // Realizar la petición const response = await fetchWithAuth(`${API_URL}/reports/exportmodel/`, { method: 'POST', headers: { @@ -147,45 +200,51 @@ export default function Reports() { }); if (!response.ok) { - // Intentar obtener el mensaje de error del backend const errorData = await response.json().catch(() => ({})); - console.error('Error response:', { - status: response.status, - statusText: response.statusText, - errorData - }); throw new Error(errorData.error || errorData.message || 'Error al exportar el modelo'); } - // Obtener el blob del archivo según el tipo + // Actualizar mensaje de progreso + progressDiv.innerHTML = ` +
+
+

Preparando archivo...

+
+ `; + const blob = await response.blob(); - const contentType = payload.type === 'excel' + const contentType = exportFormat === 'excel' ? 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' : 'text/csv'; - // Crear URL del blob - const url = window.URL.createObjectURL( - new Blob([blob], { type: contentType }) - ); - - // Crear elemento temporal para la descarga + const url = window.URL.createObjectURL(new Blob([blob], { type: contentType })); const link = document.createElement('a'); + const extension = exportFormat === 'excel' ? 'xlsx' : 'csv'; + const fileName = `${currentModel.model}_${new Date().toISOString().split('T')[0]}.${extension}`; + link.href = url; - - // Obtener el nombre del archivo del header Content-Disposition o usar uno por defecto - const contentDisposition = response.headers.get('Content-Disposition'); - const extension = payload.type === 'csv' ? 'csv' : 'xlsx'; - const fileName = contentDisposition - ? contentDisposition.match(/filename="(.+?)"/)?.pop() || `${currentModel.model}.${extension}` - : `${currentModel.model}.${extension}`; - link.setAttribute('download', fileName); document.body.appendChild(link); link.click(); - - // Limpiar recursos document.body.removeChild(link); window.URL.revokeObjectURL(url); + + // Mostrar mensaje de éxito + progressDiv.innerHTML = ` +
+ + + +

¡Exportación completada!

+
+ `; + setTimeout(() => { + progressDiv.style.opacity = '0'; + progressDiv.style.transform = 'translateY(100%)'; + setTimeout(() => progressDiv.remove(), 300); + }, 2000); + + setShowExportSuccess(true); } catch (error) { console.error('Error al exportar:', error); alert(error.message || 'Error al exportar el modelo. Por favor intente nuevamente.'); @@ -194,115 +253,334 @@ export default function Reports() { } }; - const renderFields = () => ( -
- {/* Lista de campos disponibles */} -
-
- Campos disponibles -
- - + const renderFields = () => { + const formatFieldName = (field) => { + return field.split('_') + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + }; + + return ( +
+
+ {/* Header con búsqueda y contador */} +
+
+
+
+ + + +
+
+

Campos del reporte

+

Selecciona los campos a incluir

+
+
+ + {selectedFields.length} seleccionados + +
+ + {/* Panel de campos */} +
+ {/* Panel izquierdo - Campos disponibles */} +
+
+

Campos disponibles

+ +
+
+ {availableFields.length === 0 ? ( +
+ + + +

Todos los campos están incluidos

+
+ ) : ( +
+ {availableFields.map(field => ( +
setAvailableSelected(field)} + onDoubleClick={() => addField(field)} + className={`group flex items-center justify-between p-2 rounded-md cursor-pointer transition-all duration-200 ${ + availableSelected === field + ? 'bg-blue-50 text-blue-700' + : 'hover:bg-gray-100' + }`} + > + {formatFieldName(field)} + +
+ ))} +
+ )} +
+
+ + {/* Panel derecho - Campos seleccionados */} +
+
+

Campos incluidos

+ +
+
+ {selectedFields.length === 0 ? ( +
+ + + +

No hay campos seleccionados

+
+ ) : ( +
+ {selectedFields.map(field => ( +
setIncludedSelected(field)} + onDoubleClick={() => removeField(field)} + > + {formatFieldName(field)} + +
+ ))} +
+ )} +
+
-
-
    - {availableFields.length === 0 && ( -
  • Todos los campos incluidos
  • - )} - {availableFields.map(field => ( -
  • setAvailableSelected(field)} - onDoubleClick={() => addField(field)} - tabIndex={0} - > - {field} -
  • - ))} -
-
- {/* Lista de campos seleccionados */} -
-
- Campos incluidos -
- -
-
    - {selectedFields.length === 0 && ( -
  • No hay campos seleccionados
  • - )} - {selectedFields.map(field => ( -
  • setIncludedSelected(field)} - onDoubleClick={() => removeField(field)} - tabIndex={0} - title="Doble click para quitar" - > - {field} -
  • - ))} -
+ +
-
- ); + ); + }; const renderFilters = () => ( -
- {Object.entries(currentModel.filters).map(([key, value]) => ( -
- - setFilters(prev => ({ - ...prev, - [key]: e.target.value - }))} - className="w-full border border-blue-200 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-blue-400 bg-white/90 shadow-md transition-all duration-200 hover:shadow-lg" - /> +
+
+
+
+
+ + + +
+
+

Filtros de búsqueda

+

Refina los resultados del reporte

+
+
- ))} +
+
+ {Object.entries(currentModel.filters).map(([key, value]) => { + const label = key.split('_').map(word => + word.charAt(0).toUpperCase() + word.slice(1) + ).join(' '); + + const isDate = key.toLowerCase().includes('fecha'); + + return ( +
+ +
+ setFilters(prev => ({ + ...prev, + [key]: e.target.value + }))} + className="block w-full rounded-lg border-gray-300 pl-3 pr-10 py-2.5 text-gray-900 placeholder-gray-500 + focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 sm:text-sm + transition-all duration-200 bg-white" + placeholder={`Buscar por ${label.toLowerCase()}`} + /> +
+ {isDate ? ( + + + + ) : ( + + + + )} +
+
+
+ ); + })} +
+
+
); // Contenido de cada pestaña const tabContents = { pedimentos: ( -
-

Generar reporte de pedimentos cargados

-

Aquí puedes generar y descargar el reporte de pedimentos cargados.

- {/* Aquí va la lógica y UI específica para pedimentos */} +
+
+
+ + + +
+
+

Generar reporte de pedimentos

+

Selecciona los campos y ajusta los filtros para generar el reporte.

+
+
+ +
+ +
+ + + +
+
+ +
+

Campos

+ {renderFields()} +
+
+

Filtros

+ {renderFilters()} +
+ +
), datastage: ( @@ -318,24 +596,65 @@ export default function Reports() {

Selecciona el modelo, revisa los campos y ajusta los filtros para generar el reporte.

-
- -
- -
- - - +
+
+ +
+ +
+ + + +
+
+
+ +
+ +
+ + +
@@ -353,13 +672,21 @@ export default function Reports() { className={`group relative w-full py-3 text-lg font-semibold ${ isExporting ? 'bg-gray-400 cursor-not-allowed' - : 'bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700' - } text-white rounded-xl transition-all duration-300 transform hover:scale-[1.02] shadow-lg hover:shadow-xl shadow-green-500/20 hover:shadow-green-500/30 overflow-hidden`} + : exportFormat === 'excel' + ? 'bg-gradient-to-r from-green-500 to-green-600 hover:from-green-600 hover:to-green-700' + : 'bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700' + } text-white rounded-xl transition-all duration-300 transform hover:scale-[1.02] shadow-lg hover:shadow-xl ${ + exportFormat === 'excel' + ? 'shadow-green-500/20 hover:shadow-green-500/30' + : 'shadow-blue-500/20 hover:shadow-blue-500/30' + } overflow-hidden`} >
{isExporting ? ( @@ -372,7 +699,7 @@ export default function Reports() { )} - {isExporting ? 'Generando archivo...' : 'Generar y descargar CSV'} + {isExporting ? 'Generando archivo...' : `Generar y descargar ${exportFormat.toUpperCase()}`}