refactor(cfdi): descarga masiva de XMLs por filtros en lugar de checkboxes

- Backend: POST /cfdi/download-xmls acepta CfdiFilters, usa getXmlsByFilters con LIMIT 1000
- Frontend: eliminados checkboxes y estado selectedIds; botón Descargar XMLs usa filtros activos
- Si >1000 resultados, muestra confirm() de advertencia pero permite proceder
- Agregada documentación técnica y changelog
This commit is contained in:
Horux Dev
2026-05-24 21:40:08 +00:00
parent 5c940847af
commit e35eae2a72
6 changed files with 415 additions and 87 deletions

View File

@@ -82,28 +82,33 @@ export async function downloadXmlsZip(req: Request, res: Response, next: NextFun
return next(new AppError(400, 'Tenant no configurado'));
}
const ids = req.body.ids as number[];
if (!Array.isArray(ids) || ids.length === 0) {
return next(new AppError(400, 'Se requiere un array de IDs'));
}
if (ids.length > 1000) {
return next(new AppError(400, 'Máximo 1,000 CFDIs por descarga'));
}
const filters: CfdiFilters = {
tipo: req.body.tipo as any,
tipoComprobante: req.body.tipoComprobante as any,
estado: req.body.estado as any,
fechaInicio: req.body.fechaInicio as string,
fechaFin: req.body.fechaFin as string,
rfc: req.body.rfc as string,
emisor: req.body.emisor as string,
receptor: req.body.receptor as string,
search: req.body.search as string,
contribuyenteId: req.body.contribuyenteId as string,
};
const cfdis = await cfdiService.getXmlsByIds(req.tenantPool, ids);
const cfdis = await cfdiService.getCfdiXmlsForZip(req.tenantPool, filters);
const zip = new AdmZip();
let added = 0;
for (const cfdi of cfdis) {
if (cfdi.xml) {
const filename = `${cfdi.uuid || cfdi.id}.xml`;
const filename = `${cfdi.uuid || 'cfdi'}.xml`;
zip.addFile(filename, Buffer.from(cfdi.xml, 'utf8'));
added++;
}
}
if (added === 0) {
return next(new AppError(404, 'No se encontraron XMLs para los CFDIs seleccionados'));
return next(new AppError(404, 'No se encontraron XMLs para los filtros aplicados'));
}
const zipBuffer = zip.toBuffer();