fix: facturapi onboarding, CSF scraper, SAT sync initial, doc notifications

- Auto-update fiscal data on org creation via updateOrgLegalOnCreate
- Add Carta Manifiesto embedded iframe in CSD config page
- Fix CSF scraper: 60s timeout + manual RFC fallback when SAT doesn't auto-populate
- Fix contribuyenteId propagation in constancia frontend hooks/API
- Fix needsInitialSync to check per-contribuyente, not just per-tenant
- Fix documento notifications for global_admin using viewingTenantId
- Extract CSF manually for Carlos Husberto Torres Romero
- Trigger initial SAT sync for Carlos Husberto Torres Romero
- Update org legal data in Facturapi for Carlos Husberto (tax_system 612 + address)

Files changed:
- apps/api/src/controllers/documentos.controller.ts
- apps/api/src/jobs/sat-sync.job.ts
- apps/api/src/services/constancia.service.ts
- apps/api/src/services/contribuyente-facturapi.service.ts
- apps/api/src/services/sat/sat-csf-login.ts
- apps/web/app/(dashboard)/configuracion/csd/page.tsx
- apps/web/lib/api/constancias.ts
- apps/web/lib/hooks/use-constancias.ts
- docs/sessions/2026-05-17-facturapi-csf-sync-notifications.md
This commit is contained in:
Horux Dev
2026-05-17 04:28:32 +00:00
parent 1c92b8eaf1
commit 44d7c796c9
9 changed files with 292 additions and 84 deletions

View File

@@ -18,6 +18,7 @@ export async function loginSatCsf(
cerPath: string,
keyPath: string,
password: string,
knownRfc?: string,
): Promise<CsfLoginSession> {
const context = await browser.newContext({
acceptDownloads: true,
@@ -73,6 +74,7 @@ export async function loginSatCsf(
await fileInputs.nth(1).setInputFiles(keyPath);
// Esperar a que el cert async parsing termine (RFC auto-populado por SAT).
let rfcPopulated = false;
try {
await loginPage.waitForFunction(
() => {
@@ -80,15 +82,36 @@ export async function loginSatCsf(
return rfc !== null && rfc.value.length >= 12;
},
null,
{ timeout: 30_000 },
{ timeout: 60_000 },
);
} catch (err) {
rfcPopulated = true;
} catch {
// Fallback: si tenemos el RFC conocido, intentar llenarlo manualmente
// (el SAT a veces no auto-popula en tiempo esperado pero acepta el envío igual).
if (knownRfc && knownRfc.length >= 12) {
try {
const rfcInput = loginPage.locator('#rfc').first();
await rfcInput.evaluate((el: HTMLElement, val: string) => {
(el as HTMLInputElement).disabled = false;
(el as HTMLInputElement).value = val;
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
}, knownRfc);
await loginPage.waitForTimeout(500);
rfcPopulated = true;
} catch {
// Manual fill failed, will debug-dump below
}
}
}
if (!rfcPopulated) {
const html = await loginPage.content();
const { writeFileSync, mkdirSync } = await import('node:fs');
const debugDir = '/tmp/horux-csf-debug';
try { mkdirSync(debugDir, { recursive: true }); } catch { /* ok */ }
writeFileSync(`${debugDir}/04c-rfc-timeout-html.html`, html);
throw err;
writeFileSync(`${debugDir}/04c-rfc-timeout-html-${Date.now()}.html`, html);
throw new Error('El SAT no auto-populó el RFC tras subir el certificado y no se pudo llenar manualmente');
}
// Password + Enviar