Exportar Gastos
Exportar contenido
Exportación de gastos a formato Excel para análisis externo o envío a asesor.
Componente
Sección titulada «Componente»<ExportSheet open={exportOpen} onOpenChange={setExportOpen} onExport={handleExport}/>Características
Sección titulada «Características»- Selección de período con calendarios (fecha inicio y fin)
- Validación de fechas (no futuras, inicio < fin)
- Exportación a Excel con formato profesional
- Incluye todos los campos relevantes del gasto
- Cálculos agregados (subtotales, totales de IVA)
Función de exportación
Sección titulada «Función de exportación»const handleExport = async (startDate: Date, endDate: Date) => { // 1. Obtener gastos del período const { data: expenses } = await supabase .from('expenses') .select('*') .eq('business_id', currentBusinessId) .gte('expense_date', format(startDate, 'yyyy-MM-dd')) .lte('expense_date', format(endDate, 'yyyy-MM-dd')) .order('expense_date', { ascending: true });
// 2. Generar Excel const workbook = XLSX.utils.book_new(); const worksheet = XLSX.utils.json_to_sheet( expenses.map(exp => ({ 'Fecha': format(new Date(exp.expense_date), 'dd/MM/yyyy'), 'Concepto': exp.name, 'Proveedor': exp.vendor_name || '-', 'NIF Proveedor': exp.vendor_tax_id || '-', 'Categoría': exp.category || '-', 'Nº Factura': exp.invoice_number || '-', 'Base Imponible': exp.amount, 'IVA (%)': exp.tax_rate, 'IVA (€)': exp.tax_amount, 'Total': exp.total_amount, 'IVA Deducible': exp.deductible_tax_amount || 0, '% Deducible': exp.deductible_percentage || 0, 'Estado': exp.status === 'verified' ? 'Verificado' : 'Registrado', })) );
// 3. Aplicar formato worksheet['!cols'] = [ { wch: 12 }, // Fecha { wch: 30 }, // Concepto { wch: 25 }, // Proveedor { wch: 12 }, // NIF { wch: 20 }, // Categoría { wch: 15 }, // Factura { wch: 12 }, // Base { wch: 8 }, // IVA % { wch: 10 }, // IVA € { wch: 12 }, // Total { wch: 12 }, // Deducible { wch: 10 }, // % { wch: 12 }, // Estado ];
// 4. Agregar totales const totalBase = expenses.reduce((sum, e) => sum + (e.amount || 0), 0); const totalIVA = expenses.reduce((sum, e) => sum + (e.tax_amount || 0), 0); const totalGeneral = expenses.reduce((sum, e) => sum + e.total_amount, 0); const totalDeducible = expenses.reduce((sum, e) => sum + (e.deductible_tax_amount || 0), 0);
XLSX.utils.sheet_add_aoa(worksheet, [ ['', '', '', '', '', 'TOTALES:', totalBase, '', totalIVA, totalGeneral, totalDeducible] ], { origin: -1 });
// 5. Agregar hoja al libro XLSX.utils.book_append_sheet(workbook, worksheet, 'Gastos');
// 6. Descargar const fileName = `Gastos_${format(startDate, 'yyyy-MM-dd')}_${format(endDate, 'yyyy-MM-dd')}.xlsx`; XLSX.writeFile(workbook, fileName);
toast({ title: "Exportación completada", description: `${expenses.length} gastos exportados a Excel`, });};Formato del Excel
Sección titulada «Formato del Excel»| Fecha | Concepto | Proveedor | NIF Proveedor | Categoría | Nº Factura | Base Imponible | IVA (%) | IVA (€) | Total | IVA Deducible | % Deducible | Estado |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 15/01/2024 | Licencia software | Microsoft | B12345678 | Software | INV-2024-001 | 200,00 | 21 | 42,00 | 242,00 | 42,00 | 100 | Verificado |
| … | … | … | … | … | … | … | … | … | … | … | … | … |
| TOTALES: | 1.500,00 | 315,00 | 1.815,00 | 315,00 |
Validaciones
Sección titulada «Validaciones»// Ambas fechas obligatoriasif (!startDate || !endDate) { toast({ title: "Error", description: "Por favor selecciona ambas fechas", variant: "destructive", }); return;}
// Fecha inicio < fecha finif (startDate > endDate) { toast({ title: "Error", description: "La fecha de inicio debe ser anterior a la fecha de fin", variant: "destructive", }); return;}
// No fechas futurasconst today = new Date();if (startDate > today || endDate > today) { toast({ title: "Error", description: "Las fechas no pueden ser futuras", variant: "destructive", }); return;}