feat(sat): factura global + fecha_efectiva, fallback tenant-contribuyente, fix anio_global typo
Factura Global & fecha_efectiva: - Migracion 045_factura_global.sql: periodicidad, meses_global, año_global, fecha_efectiva - sat-parser.service.ts: extrae InformacionGlobal del XML - sat.service.ts: calcFechaEfectiva con soporte bimestral (periodicidad 05) - metricas-compute, dashboard, impuestos, cfdi, export, conciliacion, alertas: reemplaza fecha_emision-1h por COALESCE(fecha_efectiva, fecha_emision-1h) - Script recalc-metricas.ts para recalculo manual Fallback datos fiscales tenant → contribuyente: - contribuyente.service.ts: fetchTenantFiscalData + mergeContribuyenteWithTenant rellena regimenFiscal, codigoPostal y domicilio cuando el contribuyente tiene el mismo RFC que el tenant y sus campos estan vacios - contribuyente.controller.ts y contribuyente-config.controller.ts: pasan req.user!.tenantId al servicio Fix critico SAT sync: - sat.service.ts: anio_global → año_global en INSERT/UPDATE de CFDIs (la migracion creo 'año_global' con tilde; el codigo usaba 'anio_global', causando fallo en 100% de inserciones de CFDI) - determineChunkMonths: salta sondeo si existe job previo con requestIds - MAX_POLL_ATTEMPTS: 45 → 500 (~8h) para syncs iniciales grandes Docs: - docs/sessions/2026-05-22-factura-global-contribuyente-fallback.md
This commit is contained in:
@@ -333,7 +333,7 @@ export async function getCancelados(req: Request, res: Response, next: NextFunct
|
||||
total_mxn as "totalMxn", fecha_cancelacion as "fechaCancelacion"
|
||||
FROM cfdis
|
||||
WHERE status IN ('Cancelado', '0')
|
||||
AND fecha_emision >= $1::date
|
||||
AND (fecha_emision - interval '1 hour') >= $1::date
|
||||
${cf}
|
||||
ORDER BY fecha_emision DESC
|
||||
`, [hace5.toISOString().split('T')[0]]);
|
||||
@@ -364,7 +364,7 @@ export async function getCancelacionesPeriodoAnterior(req: Request, res: Respons
|
||||
FROM cfdis
|
||||
WHERE status IN ('Cancelado', '0')
|
||||
AND fecha_cancelacion >= $1::date
|
||||
AND fecha_emision < $1::date
|
||||
AND COALESCE(fecha_efectiva, fecha_emision - interval '1 hour') < $1::date
|
||||
${cf}
|
||||
ORDER BY fecha_cancelacion DESC
|
||||
`, [inicioMes]);
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function uploadFiel(req: Request, res: Response, next: NextFunction
|
||||
return next(new AppError(400, 'cerFile, keyFile y password son requeridos'));
|
||||
}
|
||||
const contribuyenteId = String(req.params.id);
|
||||
const contrib = await getContribuyenteById(req.tenantPool!, contribuyenteId);
|
||||
const contrib = await getContribuyenteById(req.tenantPool!, contribuyenteId, req.user!.tenantId);
|
||||
if (!contrib) return next(new AppError(404, 'Contribuyente no encontrado'));
|
||||
|
||||
const result = await fielService.uploadFielContribuyente(req.tenantPool!, contribuyenteId, cerFile, keyFile, password);
|
||||
@@ -62,7 +62,7 @@ export async function deleteFiel(req: Request, res: Response, next: NextFunction
|
||||
export async function createOrg(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const contribuyenteId = String(req.params.id);
|
||||
const contrib = await getContribuyenteById(req.tenantPool!, contribuyenteId);
|
||||
const contrib = await getContribuyenteById(req.tenantPool!, contribuyenteId, req.user!.tenantId);
|
||||
if (!contrib) return next(new AppError(404, 'Contribuyente no encontrado'));
|
||||
|
||||
const result = await facturapiService.createOrgContribuyente(req.tenantPool!, contribuyenteId, contrib.nombre);
|
||||
|
||||
@@ -40,14 +40,14 @@ const updateSchema = createSchema.partial();
|
||||
export async function list(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const visibleIds = await getEntidadesVisibles(req.tenantPool!, req.user!.userId, req.user!.role);
|
||||
const rows = await contribuyenteService.listContribuyentes(req.tenantPool!, visibleIds);
|
||||
const rows = await contribuyenteService.listContribuyentes(req.tenantPool!, visibleIds, req.user!.tenantId);
|
||||
return res.json({ data: rows });
|
||||
} catch (err) { return next(err); }
|
||||
}
|
||||
|
||||
export async function getById(req: Request, res: Response, next: NextFunction) {
|
||||
try {
|
||||
const row = await contribuyenteService.getContribuyenteById(req.tenantPool!, String(req.params.id));
|
||||
const row = await contribuyenteService.getContribuyenteById(req.tenantPool!, String(req.params.id), req.user!.tenantId);
|
||||
if (!row) return next(new AppError(404, 'Contribuyente no encontrado'));
|
||||
return res.json(row);
|
||||
} catch (err) { return next(err); }
|
||||
|
||||
Reference in New Issue
Block a user