fix(fiel): detect FIEL for despacho tenants via contribuyentes

hasFielConfigured() now checks both:
1. Legacy mode: fiel_credentials in central DB (Horux 360)
2. Despacho mode: fiel_contribuyente in tenant DB

This fixes the SAT daily sync omitting despacho tenants that have
FIEL loaded per-contribuyente but not in the central fiel_credentials table.
This commit is contained in:
Horux Dev
2026-04-30 04:17:18 +00:00
parent 8e83dd2276
commit 67cf2ae6fe

View File

@@ -1,10 +1,11 @@
import { Credential } from '@nodecfdi/credentials/node'; import { Credential } from '@nodecfdi/credentials/node';
import { writeFile, mkdir } from 'fs/promises'; import { writeFile, mkdir } from 'fs/promises';
import { join } from 'path'; import { join } from 'path';
import { prisma } from '../config/database.js'; import { prisma, tenantDb } from '../config/database.js';
import { env } from '../config/env.js'; import { env } from '../config/env.js';
import { encryptFielCredentials, encrypt, decryptFielCredentials } from './sat/sat-crypto.service.js'; import { encryptFielCredentials, encrypt, decryptFielCredentials } from './sat/sat-crypto.service.js';
import { emailService } from './email/email.service.js'; import { emailService } from './email/email.service.js';
import { isDespachoTenant } from '@horux/shared';
import type { FielStatus } from '@horux/shared'; import type { FielStatus } from '@horux/shared';
/** /**
@@ -305,9 +306,42 @@ export async function getDecryptedFiel(tenantId: string): Promise<{
} }
/** /**
* Verifica si un tenant tiene FIEL configurada y válida * Verifica si un tenant tiene FIEL configurada y válida.
* Para despachos, verifica si hay al menos un contribuyente con FIEL activa.
* Para legacy (Horux 360), verifica la FIEL a nivel de tenant.
*/ */
export async function hasFielConfigured(tenantId: string): Promise<boolean> { export async function hasFielConfigured(tenantId: string): Promise<boolean> {
// 1. Intentar FIEL a nivel de tenant (modo legacy Horux 360)
const status = await getFielStatus(tenantId); const status = await getFielStatus(tenantId);
return status.configured && !status.isExpired; if (status.configured && !status.isExpired) {
return true;
}
// 2. Para despachos, verificar FIEL por contribuyente
const tenant = await prisma.tenant.findUnique({
where: { id: tenantId },
select: { rfc: true, databaseName: true },
});
if (!tenant?.databaseName) {
return false;
}
const isDespacho = isDespachoTenant(tenant.rfc);
if (!isDespacho) {
return false;
}
try {
const pool = await tenantDb.getPool(tenantId, tenant.databaseName);
const { rows } = await pool.query(`
SELECT 1
FROM fiel_contribuyente
WHERE is_active = true AND valid_until > NOW()
LIMIT 1
`);
return rows.length > 0;
} catch (err: any) {
console.error(`[hasFielConfigured] Error consultando FIEL de contribuyentes para tenant ${tenantId}:`, err.message);
return false;
}
} }