diff --git a/apps/web/app/(dashboard)/cfdi/page.tsx b/apps/web/app/(dashboard)/cfdi/page.tsx index ebe04c5..67f883c 100644 --- a/apps/web/app/(dashboard)/cfdi/page.tsx +++ b/apps/web/app/(dashboard)/cfdi/page.tsx @@ -5,7 +5,7 @@ import { useDebounce } from '@horux/shared-ui'; import { Header } from '@/components/layouts/header'; import { Card, CardContent, CardHeader, CardTitle, CardDescription, Button, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, Popover, PopoverTrigger, PopoverContent } from '@horux/shared-ui'; import { useCfdis, useCfdiConceptos, useCreateCfdi, useDeleteCfdi } from '@/lib/hooks/use-cfdi'; -import { getCfdis, createManyCfdis, searchEmisores, searchReceptores, type EmisorReceptor } from '@/lib/api/cfdi'; +import { getCfdis, createManyCfdis, searchEmisores, searchReceptores, getAllCfdiConceptos, type EmisorReceptor } from '@/lib/api/cfdi'; import { cancelarFactura, downloadPdf, downloadXml } from '@/lib/api/facturacion'; import type { CfdiFilters, CfdiConceptoFilters, TipoCfdi, Cfdi } from '@horux/shared'; import type { CreateCfdiData } from '@/lib/api/cfdi'; @@ -502,6 +502,64 @@ export default function CfdiPage() { } }; + const exportConceptosToExcel = async () => { + if (!conceptosData?.data.length) return; + + setExporting(true); + try { + const allFilters: CfdiConceptoFilters = { ...conceptoFilters, page: 1, limit: 10000 }; + const allData = await getAllCfdiConceptos(allFilters); + const rows = allData.data; + + if (!rows.length) { + alert('No hay datos para exportar'); + return; + } + + const exportData = rows.map(c => ({ + 'Fecha CFDI': c.cfdiFechaEmision ? new Date(c.cfdiFechaEmision).toLocaleDateString('es-MX') : '', + 'UUID': c.cfdiUuid || '', + 'Tipo Comprobante': formatTipoComprobante(c.cfdiTipoComprobante), + 'Estatus CFDI': c.cfdiStatus === 'Vigente' || c.cfdiStatus === '1' ? 'Vigente' : 'Cancelado', + 'RFC Emisor': c.cfdiRfcEmisor || '', + 'Nombre Emisor': c.cfdiNombreEmisor || '', + 'RFC Receptor': c.cfdiRfcReceptor || '', + 'Nombre Receptor': c.cfdiNombreReceptor || '', + 'Clave ProdServ': c.claveProdServ || '', + 'No. Identificación': c.noIdentificacion || '', + 'Descripción': c.descripcion, + 'Cantidad': c.cantidad, + 'Unidad': c.claveUnidad || c.unidad || '', + 'Valor Unitario': c.valorUnitario, + 'Importe': c.importe, + 'Descuento': c.descuento, + 'IVA Trasladado': c.ivaTraslado, + 'IVA Retención': c.ivaRetencion, + 'ISR Retención': c.isrRetencion, + })); + + const ws = XLSX.utils.json_to_sheet(exportData); + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, 'Conceptos'); + + const colWidths = Object.keys(exportData[0]).map(key => ({ + wch: Math.max(key.length, ...exportData.map(row => String(row[key as keyof typeof row]).length)) + })); + ws['!cols'] = colWidths; + + const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); + const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + + const fileName = `conceptos_${new Date().toISOString().split('T')[0]}.xlsx`; + saveAs(blob, fileName); + } catch (error) { + console.error('Error exporting conceptos:', error); + alert('Error al exportar conceptos'); + } finally { + setExporting(false); + } + }; + const handleDownloadPdf = async (facturapiId: string | null) => { if (!facturapiId) return; try { @@ -1039,8 +1097,8 @@ export default function CfdiPage() {