- Document current implementation status - Add pending items to verify after SAT rate limit resets - Include test tenant info and verification commands - List known issues and workarounds Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.9 KiB
8.9 KiB
Implementación de Sincronización SAT
Resumen
Sistema de sincronización automática de CFDIs con el SAT (Servicio de Administración Tributaria de México) para Horux360.
Componentes Implementados
1. Backend (API)
Servicios
| Archivo | Descripción |
|---|---|
src/services/fiel.service.ts |
Gestión de credenciales FIEL (e.firma) |
src/services/sat/sat-client.service.ts |
Cliente para el servicio web del SAT |
src/services/sat/sat.service.ts |
Lógica principal de sincronización |
src/services/sat/sat-crypto.service.ts |
Encriptación AES-256-GCM para credenciales |
src/services/sat/sat-parser.service.ts |
Parser de XMLs de CFDI |
Controladores
| Archivo | Descripción |
|---|---|
src/controllers/fiel.controller.ts |
Endpoints para gestión de FIEL |
src/controllers/sat.controller.ts |
Endpoints para sincronización SAT |
Job Programado
| Archivo | Descripción |
|---|---|
src/jobs/sat-sync.job.ts |
Cron job para sincronización diaria (3:00 AM) |
2. Frontend (Web)
Componentes
| Archivo | Descripción |
|---|---|
components/sat/FielUploadModal.tsx |
Modal para subir certificado y llave FIEL |
components/sat/SyncStatus.tsx |
Estado de sincronización con selector de fechas |
components/sat/SyncHistory.tsx |
Historial de sincronizaciones |
Página
| Archivo | Descripción |
|---|---|
app/(dashboard)/configuracion/sat/page.tsx |
Página de configuración SAT |
3. Base de Datos
Tabla Principal (schema public)
-- sat_sync_jobs: Almacena los trabajos de sincronización
CREATE TABLE sat_sync_jobs (
id UUID PRIMARY KEY,
tenant_id UUID NOT NULL,
type VARCHAR(20) NOT NULL, -- 'initial' | 'daily'
status VARCHAR(20) NOT NULL, -- 'pending' | 'running' | 'completed' | 'failed'
date_from TIMESTAMP NOT NULL,
date_to TIMESTAMP NOT NULL,
cfdi_type VARCHAR(20),
sat_request_id VARCHAR(100),
sat_package_ids TEXT[],
cfdis_found INTEGER DEFAULT 0,
cfdis_downloaded INTEGER DEFAULT 0,
cfdis_inserted INTEGER DEFAULT 0,
cfdis_updated INTEGER DEFAULT 0,
progress_percent INTEGER DEFAULT 0,
error_message TEXT,
started_at TIMESTAMP,
completed_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
retry_count INTEGER DEFAULT 0
);
-- fiel_credentials: Almacena las credenciales FIEL encriptadas
CREATE TABLE fiel_credentials (
id UUID PRIMARY KEY,
tenant_id UUID UNIQUE NOT NULL,
rfc VARCHAR(13) NOT NULL,
cer_data BYTEA NOT NULL,
key_data BYTEA NOT NULL,
key_password_encrypted BYTEA NOT NULL,
encryption_iv BYTEA NOT NULL,
encryption_tag BYTEA NOT NULL,
serial_number VARCHAR(100),
valid_from TIMESTAMP NOT NULL,
valid_until TIMESTAMP NOT NULL,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
Columnas agregadas a tabla cfdis (por tenant)
ALTER TABLE tenant_xxx.cfdis ADD COLUMN xml_original TEXT;
ALTER TABLE tenant_xxx.cfdis ADD COLUMN updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
ALTER TABLE tenant_xxx.cfdis ADD COLUMN last_sat_sync TIMESTAMP;
ALTER TABLE tenant_xxx.cfdis ADD COLUMN sat_sync_job_id UUID;
ALTER TABLE tenant_xxx.cfdis ADD COLUMN source VARCHAR(20) DEFAULT 'manual';
Dependencias
{
"@nodecfdi/sat-ws-descarga-masiva": "^2.0.0",
"@nodecfdi/credentials": "^2.0.0",
"@nodecfdi/cfdi-core": "^1.0.1"
}
Flujo de Sincronización
1. Usuario configura FIEL (certificado .cer + llave .key + contraseña)
↓
2. Sistema valida y encripta credenciales (AES-256-GCM)
↓
3. Usuario inicia sincronización (manual o automática 3:00 AM)
↓
4. Sistema desencripta FIEL y crea cliente SAT
↓
5. Por cada mes en el rango:
a. Solicitar CFDIs emitidos al SAT
b. Esperar respuesta (polling cada 30s)
c. Descargar paquetes ZIP
d. Extraer y parsear XMLs
e. Guardar en BD del tenant
f. Repetir para CFDIs recibidos
↓
6. Marcar job como completado
API Endpoints
FIEL
| Método | Ruta | Descripción |
|---|---|---|
| GET | /api/fiel/status |
Estado de la FIEL configurada |
| POST | /api/fiel/upload |
Subir nueva FIEL |
| DELETE | /api/fiel |
Eliminar FIEL |
Sincronización SAT
| Método | Ruta | Descripción |
|---|---|---|
| POST | /api/sat/sync |
Iniciar sincronización |
| GET | /api/sat/sync/status |
Estado actual |
| GET | /api/sat/sync/history |
Historial de syncs |
| GET | /api/sat/sync/:id |
Detalle de un job |
| POST | /api/sat/sync/:id/retry |
Reintentar job fallido |
Parámetros de sincronización
interface StartSyncRequest {
type?: 'initial' | 'daily'; // default: 'daily'
dateFrom?: string; // ISO date, ej: "2025-01-01T00:00:00"
dateTo?: string; // ISO date, ej: "2025-12-31T23:59:59"
}
Configuración
Variables de entorno
# Clave para encriptar credenciales FIEL (32 bytes hex)
FIEL_ENCRYPTION_KEY=tu_clave_de_32_bytes_en_hexadecimal
# Zona horaria para el cron
TZ=America/Mexico_City
Límites del SAT
- Antigüedad máxima: 6 años
- Solicitudes por día: Limitadas (se reinicia cada 24h)
- Tamaño de paquete: Variable
Errores Comunes del SAT
| Código | Mensaje | Solución |
|---|---|---|
| 5000 | Solicitud Aceptada | OK - esperar verificación |
| 5002 | Límite de solicitudes agotado | Esperar 24 horas |
| 5004 | No se encontraron CFDIs | Normal si no hay facturas en el rango |
| 5005 | Solicitud duplicada | Ya existe una solicitud pendiente |
| - | Información mayor a 6 años | Ajustar rango de fechas |
| - | No se permite descarga de cancelados | Facturas canceladas no disponibles |
Seguridad
- Encriptación de credenciales: AES-256-GCM con IV único
- Almacenamiento seguro: Certificado, llave y contraseña encriptados
- Autenticación: JWT con tenantId embebido
- Aislamiento: Cada tenant tiene su propio schema en PostgreSQL
Servicios Systemd
# API Backend
systemctl status horux-api
# Web Frontend
systemctl status horux-web
Comandos Útiles
# Ver logs de sincronización SAT
journalctl -u horux-api -f | grep "\[SAT\]"
# Estado de jobs
psql -U postgres -d horux360 -c "SELECT * FROM sat_sync_jobs ORDER BY created_at DESC LIMIT 5;"
# CFDIs sincronizados por tenant
psql -U postgres -d horux360 -c "SELECT COUNT(*) FROM tenant_xxx.cfdis WHERE source = 'sat';"
Changelog
2026-01-25
- Implementación inicial de sincronización SAT
- Integración con librería @nodecfdi/sat-ws-descarga-masiva
- Soporte para fechas personalizadas en sincronización
- Corrección de cast UUID en queries SQL
- Agregadas columnas faltantes a tabla cfdis
- UI para selección de periodo personalizado
- Cambio de servicio web a modo producción (next start)
Estado Actual (2026-01-25)
Completado
- Servicio de encriptación de credenciales FIEL
- Integración con @nodecfdi/sat-ws-descarga-masiva
- Parser de XMLs de CFDI
- UI para subir FIEL
- UI para ver estado de sincronización
- UI para seleccionar periodo personalizado
- Cron job para sincronización diaria (3:00 AM)
- Soporte para fechas personalizadas
- Corrección de cast UUID en queries
- Columnas adicionales en tabla cfdis de todos los tenants
Pendiente por probar
El SAT bloqueó las solicitudes por exceso de pruebas. Esperar 24 horas y luego:
- Ir a Configuración > SAT
- Clic en "Periodo personalizado"
- Seleccionar: 2025-01-01 a 2025-12-31
- Clic en "Sincronizar periodo"
Tenant de prueba
- RFC: CAS2408138W2
- Schema:
tenant_cas2408138w2 - Nota: Los CFDIs "recibidos" de este tenant están cancelados (SAT no permite descargarlos)
Comandos para verificar después de 24h
# Ver estado del sync
PGPASSWORD=postgres psql -h localhost -U postgres -d horux360 -c \
"SELECT status, cfdis_found, cfdis_downloaded, cfdis_inserted FROM sat_sync_jobs ORDER BY created_at DESC LIMIT 1;"
# Ver logs en tiempo real
journalctl -u horux-api -f | grep "\[SAT\]"
# Contar CFDIs sincronizados
PGPASSWORD=postgres psql -h localhost -U postgres -d horux360 -c \
"SELECT COUNT(*) as total FROM tenant_cas2408138w2.cfdis WHERE source = 'sat';"
Problemas conocidos
- "Se han agotado las solicitudes de por vida": Límite de SAT alcanzado, esperar 24h
- "No se permite la descarga de xml que se encuentren cancelados": Normal para facturas canceladas
- "Información mayor a 6 años": SAT solo permite descargar últimos 6 años
Próximos Pasos
- Probar sincronización completa después de 24h
- Verificar que los CFDIs se guarden correctamente
- Implementar reintentos automáticos para errores temporales
- Notificaciones por email al completar sincronización
- Dashboard con estadísticas de CFDIs por periodo
- Soporte para filtros adicionales (RFC emisor/receptor, tipo de comprobante)