Reemplaza logging por consola/archivo, agrega historial de intentos y soporte para notas de crédito
- Nuevo logger_manager.py (reemplaza logger_utilities.py): logging con formato de árbol, rotación diaria a sunat.log, y consola por stdout (antes iba por stderr y se duplicaba en logs/error.log del launchd). - Nuevo historial_manager.py: registra cada intento de consulta/descarga en historial.db para auditoría, con limpieza automática de registros de más de 180 días. - consulta_cpe.py: corrige el id de notas de crédito/débito (usa F7/F8, no 07/08) y agrega reintentos ante errores 5xx. - hana_manager.py: suma consulta a ORPC para notas de crédito (Indicator 07) y soporte de ObjType para actualizar la tabla correcta (OPCH/ORPC) al marcar PDF/XML descargado. - gestor_fallas.py / main.py: propagan objtype end-to-end y dejan constancia de cada intento en historial_manager. - Elimina login_api.py y reporte_fallas.py (código no usado / script manual sin uso reciente). - Actualiza .gitignore (sunat-venv/, historial.db*) y docs/ para reflejar el estado real del proyecto. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
99a587c4da
commit
c2503745bf
18 files changed
+647
-862
No files matched your search
+3
-2
@@ -26,6 +26,7 @@ WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
# Guarda el bloque [Unit]/[Service]/[Install] de arriba en un archivo, ej. sunat-cpe.service
|
||||
sudo cp sunat-cpe.service /etc/systemd/system/
|
||||
sudo systemctl enable sunat-cpe
|
||||
sudo systemctl start sunat-cpe
|
||||
@@ -63,7 +64,7 @@ NSSM redirige stdout/stderr a `C:\ruta\descarga_xml_sunat\logs\` por defecto (el
|
||||
Como servicio, el daemon usa `get_token_headless()` (headless, Firefox real) para renovar el token automáticamente sin intervención. Si Firefox no está instalado, el daemon lo detecta y usa `get_token.py headless=False` como respaldo (requiere escritorio). Para renovar manualmente:
|
||||
|
||||
```cmd
|
||||
C:\ruta\descarga_xml_sunat\sunat-env\Scripts\python get_token.py
|
||||
C:\ruta\descarga_xml_sunat\sunat-venv\Scripts\python get_token.py
|
||||
```
|
||||
|
||||
### Actualización
|
||||
@@ -83,4 +84,4 @@ COPY . .
|
||||
CMD ["python", "main.py"]
|
||||
```
|
||||
|
||||
Asegúrate de que `requirements.txt` incluya: `playwright`, `python-dotenv`, `requests`, `hdbcli`, `matplotlib`.
|
||||
Asegúrate de que `requirements.txt` incluya: `playwright`, `python-dotenv`, `requests`, `hdbcli`.
|
||||
+9
-6
@@ -2,22 +2,22 @@
|
||||
|
||||
| Archivo | Función |
|
||||
|---|---|
|
||||
| `main.py` | Daemon orquestador. Bucle infinito con horarios configurables, obtiene token, consulta HANA, procesa pendientes (nuevos + reintentos). |
|
||||
| `main.py` | Daemon orquestador. Bucle infinito con horarios configurables (`scheduler.json`), obtiene token, consulta HANA, procesa pendientes (nuevos + reintentos). |
|
||||
| `get_token_headless.py` | Login headless via Firefox real. Sin ventana visible. |
|
||||
| `get_token.py` | Login SOL via Playwright (headless=False). Navega menú → extrae JWT de `sessionStorage['SUNAT.token']`. |
|
||||
| `consulta_cpe.py` | Consulta API REST `api-cpe.sunat.gob.pe`. Retorna `(data, status_code)`. Lanza `TokenExpiredError` en 401. |
|
||||
| `hana_manager.py` | Conexión HANA vía `hdbcli`. Consulta pendientes en `OPCH`, actualiza flags de descarga. |
|
||||
| `gestor_fallas.py` | SQLite `fallas_descarga.db`. Registro de fallas con conteo de intentos y backoff progresivo (0min → 5min → 15min → ... → 12h, máx 20). |
|
||||
| `historial_manager.py` | SQLite `historial.db`. Registra cada intento de consulta/descarga (éxito o falla) para auditoría; limpia registros de más de 180 días. Incluye CLI (`python historial_manager.py --ruc/--serie/--numero/--tipo`) para buscar intentos. |
|
||||
| `logger_manager.py` | Logging con formato de árbol (indentado por tareas anidadas) a consola + archivo. Rotación diaria en `logs/sunat_YYYY-MM-DD.log`, limpieza automática de logs con más de 7 días. |
|
||||
| `smb_manager.py` | Monta recurso SMB (`mount_smbfs`/`mount.cifs`/`net use`) y sincroniza PDF/XML al NAS. Limpia JSON/ZIP temporales. |
|
||||
| `login_api.py` | Intento de `password_grant()` / `authorization_code` directo a SUNAT (sin navegador, generalmente ya no funciona). Se mantiene como referencia. |
|
||||
| `logger_utilities.py` | Redirige stdout/stderr a `logs/YYYY-MM-DD.log` + terminal. Rotación diaria. |
|
||||
| `reporte_fallas.py` | Genera resumen textual + 3 gráficos PNG desde `fallas_descarga.db`. |
|
||||
| `scheduler.json` | Horarios activos (`HORARIOS`) y días de la semana en que corre el daemon (`DIAS_ACTIVOS`). Editable sin tocar código. |
|
||||
| `token.json` | Token JWT auto-generado con expiración. |
|
||||
| `.env` | Credenciales HANA y SUNAT. |
|
||||
|
||||
## Flujo
|
||||
|
||||
1. `main.py` verifica día/horario → renueva token si expiró (get_token_headless → get_token.py headless=False)
|
||||
1. `main.py` verifica día/horario (`scheduler.json`) → renueva token si expiró (get_token_headless → get_token.py headless=False)
|
||||
2. `obtener_pendientes()` trae todos los documentos de OPCH donde `tienePDF='N'` o `tieneXML='N'`
|
||||
3. Separa en **nuevos** (no están en fallas DB) y **reintentos** (fallas pendientes con backoff cumplido)
|
||||
4. Por cada doc:
|
||||
@@ -26,5 +26,8 @@
|
||||
- Si OK → `descargar_archivo()` (XML + PDF + CDR)
|
||||
- `marcar_pdf_descargado()` / `marcar_xml_descargado()` actualizan HANA
|
||||
- Si era reintento exitoso → `eliminar_falla()`
|
||||
- `registrar_intento()` deja constancia del resultado en `historial.db`
|
||||
5. `sincronizar_a_smb()` monta NAS (si no está montado), copia PDF/XML via rsync (Mac/Linux) o shutil.move (Windows), y elimina JSON/ZIP temporales de `descargas/`
|
||||
6. Espera intervalo configurado (5 min modo rápido, 1 h modo full) y repite
|
||||
6. Espera intervalo configurado (según `scheduler.json`, ej. 5 min modo rápido, 30 min/1 h modo full) y repite
|
||||
|
||||
Al arrancar, `main.py` también corre mantenimiento: `limpiar_logs_antiguos(dias=7)` y `limpiar_historial_antiguo(dias=180)`.
|
||||
+6
-6
@@ -12,8 +12,8 @@
|
||||
|
||||
```bash
|
||||
# Crear y activar entorno virtual (recomendado)
|
||||
python3 -m venv sunat-env
|
||||
source sunat-env/bin/activate
|
||||
python3 -m venv sunat-venv
|
||||
source sunat-venv/bin/activate
|
||||
|
||||
# Instalar dependencias
|
||||
pip install -r requirements.txt
|
||||
@@ -50,7 +50,7 @@ SMB_SUBFOLDER=COMPRAS/TAGUMEDICA/ADJUNTOS_CORREOS
|
||||
|
||||
```bash
|
||||
# Activar entorno virtual
|
||||
source sunat-env/bin/activate
|
||||
source sunat-venv/bin/activate
|
||||
|
||||
# Obtener token manualmente (con navegador visible)
|
||||
python get_token.py
|
||||
@@ -61,10 +61,10 @@ python get_token_headless.py
|
||||
# Daemon completo (automático)
|
||||
python main.py
|
||||
|
||||
# Reporte de fallas (resumen texto + gráficos PNG)
|
||||
python reporte_fallas.py
|
||||
# Buscar intentos de descarga en el historial
|
||||
python historial_manager.py --ruc 20503662869 --serie F001 --numero 123
|
||||
```
|
||||
|
||||
## Logs
|
||||
|
||||
Todos los logs se guardan en `logs/YYYY-MM-DD.log`. Rotación automática diaria, los archivos mayores a 7 días se eliminan.
|
||||
Todos los logs se guardan en `logs/sunat_YYYY-MM-DD.log`. Rotación automática diaria, los archivos mayores a 7 días se eliminan.
|
||||
Reference in new issue
Block a user