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:
@@ -43,16 +43,19 @@ async function getTenantsWithFiel(): Promise<string[]> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica si un tenant necesita sincronización inicial
|
||||
* Verifica si un tenant (o un contribuyente específico dentro del tenant)
|
||||
* necesita sincronización inicial.
|
||||
*/
|
||||
async function needsInitialSync(tenantId: string): Promise<boolean> {
|
||||
const completedSync = await prisma.satSyncJob.findFirst({
|
||||
where: {
|
||||
tenantId,
|
||||
type: 'initial',
|
||||
status: 'completed',
|
||||
},
|
||||
});
|
||||
async function needsInitialSync(tenantId: string, contribuyenteId?: string): Promise<boolean> {
|
||||
const where: any = {
|
||||
tenantId,
|
||||
type: 'initial',
|
||||
status: 'completed',
|
||||
};
|
||||
if (contribuyenteId) {
|
||||
where.contribuyenteId = contribuyenteId;
|
||||
}
|
||||
const completedSync = await prisma.satSyncJob.findFirst({ where });
|
||||
|
||||
return !completedSync;
|
||||
}
|
||||
@@ -62,10 +65,6 @@ async function needsInitialSync(tenantId: string): Promise<boolean> {
|
||||
*/
|
||||
async function syncTenant(tenantId: string): Promise<void> {
|
||||
try {
|
||||
// Determinar tipo de sync
|
||||
const needsInitial = await needsInitialSync(tenantId);
|
||||
const syncType = needsInitial ? 'initial' : 'daily';
|
||||
|
||||
// Obtener contribuyentes del tenant
|
||||
const tenant = await prisma.tenant.findUnique({
|
||||
where: { id: tenantId },
|
||||
@@ -81,6 +80,8 @@ async function syncTenant(tenantId: string): Promise<void> {
|
||||
|
||||
// Si no hay contribuyentes, sincronizar a nivel tenant (legacy Horux 360)
|
||||
if (contribuyenteIds.length === 0) {
|
||||
const needsInitial = await needsInitialSync(tenantId);
|
||||
const syncType = needsInitial ? 'initial' : 'daily';
|
||||
const status = await getSyncStatus(tenantId);
|
||||
if (status.hasActiveSync) {
|
||||
console.log(`[SAT Cron] Tenant ${tenantId} ya tiene sync activo, omitiendo`);
|
||||
@@ -92,7 +93,7 @@ async function syncTenant(tenantId: string): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sincronizar cada contribuyente
|
||||
// Sincronizar cada contribuyente (cada uno puede necesitar su propio initial)
|
||||
for (const contribuyenteId of contribuyenteIds) {
|
||||
try {
|
||||
const status = await getSyncStatus(tenantId, contribuyenteId);
|
||||
@@ -101,6 +102,8 @@ async function syncTenant(tenantId: string): Promise<void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
const needsInitial = await needsInitialSync(tenantId, contribuyenteId);
|
||||
const syncType = needsInitial ? 'initial' : 'daily';
|
||||
console.log(`[SAT Cron] Iniciando sync ${syncType} para tenant ${tenantId} contribuyente ${contribuyenteId}`);
|
||||
const jobId = await startSync(tenantId, syncType, undefined, undefined, contribuyenteId);
|
||||
console.log(`[SAT Cron] Job ${jobId} iniciado para tenant ${tenantId} contribuyente ${contribuyenteId}`);
|
||||
@@ -187,14 +190,6 @@ async function getTenantsConSatIncremental(): Promise<string[]> {
|
||||
*/
|
||||
async function incrementalSyncTenant(tenantId: string): Promise<void> {
|
||||
try {
|
||||
const completedInitial = await prisma.satSyncJob.findFirst({
|
||||
where: { tenantId, type: 'initial', status: 'completed' },
|
||||
});
|
||||
if (!completedInitial) {
|
||||
console.log(`[SAT Cron Inc] Tenant ${tenantId} sin sync inicial completado, omitiendo incremental`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Obtener contribuyentes del tenant
|
||||
const tenant = await prisma.tenant.findUnique({
|
||||
where: { id: tenantId },
|
||||
@@ -210,6 +205,13 @@ async function incrementalSyncTenant(tenantId: string): Promise<void> {
|
||||
|
||||
// Si no hay contribuyentes, sincronizar a nivel tenant (legacy)
|
||||
if (contribuyenteIds.length === 0) {
|
||||
const completedInitial = await prisma.satSyncJob.findFirst({
|
||||
where: { tenantId, type: 'initial', status: 'completed' },
|
||||
});
|
||||
if (!completedInitial) {
|
||||
console.log(`[SAT Cron Inc] Tenant ${tenantId} sin sync inicial completado, omitiendo incremental`);
|
||||
return;
|
||||
}
|
||||
const status = await getSyncStatus(tenantId);
|
||||
if (status.hasActiveSync) {
|
||||
console.log(`[SAT Cron Inc] Tenant ${tenantId} con sync activo, omitiendo`);
|
||||
@@ -221,9 +223,17 @@ async function incrementalSyncTenant(tenantId: string): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sincronizar cada contribuyente
|
||||
// Sincronizar cada contribuyente solo si ya tiene su initial completado
|
||||
for (const contribuyenteId of contribuyenteIds) {
|
||||
try {
|
||||
const hasInitial = await prisma.satSyncJob.findFirst({
|
||||
where: { tenantId, contribuyenteId, type: 'initial', status: 'completed' },
|
||||
});
|
||||
if (!hasInitial) {
|
||||
console.log(`[SAT Cron Inc] Tenant ${tenantId} contribuyente ${contribuyenteId} sin sync inicial, omitiendo incremental`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const status = await getSyncStatus(tenantId, contribuyenteId);
|
||||
if (status.hasActiveSync) {
|
||||
console.log(`[SAT Cron Inc] Tenant ${tenantId} contribuyente ${contribuyenteId} con sync activo, omitiendo`);
|
||||
|
||||
Reference in New Issue
Block a user