126 lines
4.6 KiB
TypeScript
126 lines
4.6 KiB
TypeScript
import ExcelJS from 'exceljs';
|
|
import type { Pool } from 'pg';
|
|
|
|
export async function exportCfdisToExcel(
|
|
pool: Pool,
|
|
filters: { tipo?: string; estado?: string; fechaInicio?: string; fechaFin?: string }
|
|
): Promise<Buffer> {
|
|
let whereClause = 'WHERE 1=1';
|
|
const params: any[] = [];
|
|
let paramIndex = 1;
|
|
|
|
if (filters.tipo) {
|
|
whereClause += ` AND type = $${paramIndex++}`;
|
|
params.push(filters.tipo);
|
|
}
|
|
if (filters.estado) {
|
|
whereClause += ` AND status = $${paramIndex++}`;
|
|
params.push(filters.estado);
|
|
}
|
|
if (filters.fechaInicio) {
|
|
whereClause += ` AND fecha_emision >= $${paramIndex++}`;
|
|
params.push(filters.fechaInicio);
|
|
}
|
|
if (filters.fechaFin) {
|
|
whereClause += ` AND fecha_emision <= $${paramIndex++}`;
|
|
params.push(filters.fechaFin);
|
|
}
|
|
|
|
const { rows: cfdis } = await pool.query(`
|
|
SELECT uuid, type, serie, folio, fecha_emision, status,
|
|
rfc_emisor, nombre_emisor, rfc_receptor, nombre_receptor,
|
|
subtotal, subtotal_mxn, descuento, descuento_mxn,
|
|
iva_traslado, iva_traslado_mxn, isr_retencion, isr_retencion_mxn,
|
|
iva_retencion, iva_retencion_mxn,
|
|
total, total_mxn, moneda, tipo_cambio,
|
|
metodo_pago, forma_pago, uso_cfdi
|
|
FROM cfdis
|
|
${whereClause}
|
|
ORDER BY fecha_emision DESC
|
|
`, params);
|
|
|
|
const workbook = new ExcelJS.Workbook();
|
|
const sheet = workbook.addWorksheet('CFDIs');
|
|
|
|
sheet.columns = [
|
|
{ header: 'UUID', key: 'uuid', width: 40 },
|
|
{ header: 'Tipo', key: 'type', width: 10 },
|
|
{ header: 'Serie', key: 'serie', width: 10 },
|
|
{ header: 'Folio', key: 'folio', width: 10 },
|
|
{ header: 'Fecha Emisión', key: 'fecha_emision', width: 15 },
|
|
{ header: 'RFC Emisor', key: 'rfc_emisor', width: 15 },
|
|
{ header: 'Nombre Emisor', key: 'nombre_emisor', width: 30 },
|
|
{ header: 'RFC Receptor', key: 'rfc_receptor', width: 15 },
|
|
{ header: 'Nombre Receptor', key: 'nombre_receptor', width: 30 },
|
|
{ header: 'Subtotal', key: 'subtotal', width: 15 },
|
|
{ header: 'Subtotal MXN', key: 'subtotal_mxn', width: 15 },
|
|
{ header: 'IVA Trasladado', key: 'iva_traslado', width: 15 },
|
|
{ header: 'IVA Trasladado MXN', key: 'iva_traslado_mxn', width: 15 },
|
|
{ header: 'Total', key: 'total', width: 15 },
|
|
{ header: 'Total MXN', key: 'total_mxn', width: 15 },
|
|
{ header: 'Moneda', key: 'moneda', width: 8 },
|
|
{ header: 'T.C.', key: 'tipo_cambio', width: 10 },
|
|
{ header: 'Estado', key: 'status', width: 12 },
|
|
];
|
|
|
|
sheet.getRow(1).font = { bold: true };
|
|
sheet.getRow(1).fill = {
|
|
type: 'pattern',
|
|
pattern: 'solid',
|
|
fgColor: { argb: 'FF4472C4' },
|
|
};
|
|
sheet.getRow(1).font = { bold: true, color: { argb: 'FFFFFFFF' } };
|
|
|
|
cfdis.forEach((cfdi: any) => {
|
|
sheet.addRow({
|
|
...cfdi,
|
|
fecha_emision: new Date(cfdi.fecha_emision).toLocaleDateString('es-MX'),
|
|
subtotal: Number(cfdi.subtotal),
|
|
subtotal_mxn: Number(cfdi.subtotal_mxn),
|
|
iva_traslado: Number(cfdi.iva_traslado),
|
|
iva_traslado_mxn: Number(cfdi.iva_traslado_mxn),
|
|
total: Number(cfdi.total),
|
|
total_mxn: Number(cfdi.total_mxn),
|
|
});
|
|
});
|
|
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
|
return Buffer.from(buffer);
|
|
}
|
|
|
|
export async function exportReporteToExcel(
|
|
pool: Pool,
|
|
tipo: 'estado-resultados' | 'flujo-efectivo',
|
|
fechaInicio: string,
|
|
fechaFin: string
|
|
): Promise<Buffer> {
|
|
const workbook = new ExcelJS.Workbook();
|
|
const sheet = workbook.addWorksheet(tipo === 'estado-resultados' ? 'Estado de Resultados' : 'Flujo de Efectivo');
|
|
|
|
if (tipo === 'estado-resultados') {
|
|
const { rows: [totales] } = await pool.query(`
|
|
SELECT
|
|
COALESCE(SUM(CASE WHEN type = 'EMITIDO' AND tipo_comprobante = 'I' THEN subtotal_mxn ELSE 0 END), 0) as ingresos,
|
|
COALESCE(SUM(CASE WHEN type = 'RECIBIDO' AND tipo_comprobante = 'I' THEN subtotal_mxn ELSE 0 END), 0) as egresos
|
|
FROM cfdis
|
|
WHERE status NOT IN ('Cancelado', '0') AND fecha_emision BETWEEN $1 AND $2
|
|
`, [fechaInicio, fechaFin]);
|
|
|
|
sheet.columns = [
|
|
{ header: 'Concepto', key: 'concepto', width: 40 },
|
|
{ header: 'Monto', key: 'monto', width: 20 },
|
|
];
|
|
|
|
sheet.addRow({ concepto: 'INGRESOS', monto: '' });
|
|
sheet.addRow({ concepto: 'Total Ingresos', monto: Number(totales?.ingresos || 0) });
|
|
sheet.addRow({ concepto: '', monto: '' });
|
|
sheet.addRow({ concepto: 'EGRESOS', monto: '' });
|
|
sheet.addRow({ concepto: 'Total Egresos', monto: Number(totales?.egresos || 0) });
|
|
sheet.addRow({ concepto: '', monto: '' });
|
|
sheet.addRow({ concepto: 'UTILIDAD NETA', monto: Number(totales?.ingresos || 0) - Number(totales?.egresos || 0) });
|
|
}
|
|
|
|
const buffer = await workbook.xlsx.writeBuffer();
|
|
return Buffer.from(buffer);
|
|
}
|