feat: SAT sync improvements and documentation
- Add custom date range support for SAT synchronization - Fix UUID cast in SQL queries for sat_sync_job_id - Fix processInitialSync to respect custom dateFrom/dateTo parameters - Add date picker UI for custom period sync - Add comprehensive documentation for SAT sync implementation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
245
docs/SAT-SYNC-IMPLEMENTATION.md
Normal file
245
docs/SAT-SYNC-IMPLEMENTATION.md
Normal file
@@ -0,0 +1,245 @@
|
||||
# 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)
|
||||
|
||||
```sql
|
||||
-- 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)
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
```json
|
||||
{
|
||||
"@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
|
||||
|
||||
```typescript
|
||||
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
|
||||
|
||||
```env
|
||||
# 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
|
||||
|
||||
1. **Encriptación de credenciales**: AES-256-GCM con IV único
|
||||
2. **Almacenamiento seguro**: Certificado, llave y contraseña encriptados
|
||||
3. **Autenticación**: JWT con tenantId embebido
|
||||
4. **Aislamiento**: Cada tenant tiene su propio schema en PostgreSQL
|
||||
|
||||
## Servicios Systemd
|
||||
|
||||
```bash
|
||||
# API Backend
|
||||
systemctl status horux-api
|
||||
|
||||
# Web Frontend
|
||||
systemctl status horux-web
|
||||
```
|
||||
|
||||
## Comandos Útiles
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
- [ ] 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)
|
||||
Reference in New Issue
Block a user