Saltar a contenido

Guías de tareas

Recetas concretas para tareas puntuales. A diferencia de la Referencia (que describe qué hay) o de Entender el sistema (que explica por qué), acá el foco es cómo hago X, paso a paso.

Casi todo esto pega contra AFIP homologación

Las recetas de CAE/CAEA asumen el perfil dev (AFIP en HOMOLOGACION) y el backend arriba. Nunca corras un "test de prueba" apuntando a producción: algunos endpoints emiten comprobantes reales. Si no tenés el backend levantado, mirá primero Setup del entorno.

Backend

Emitir un CAE de prueba

Emite una Factura B de Consumidor Final por $121 (neto 100 + IVA 21) contra AFIP homologación, para un POS configurado.

  1. Asegurate de tener un SucPosPV cargado (ver más abajo) y de saber su suc/pos.
  2. Pegale al test runner del cockpit:
    curl -X POST http://localhost:8080/api/cockpit/test/cae ^
      -H "Content-Type: application/json" ^
      -d "{\"suc\": 1, \"pos\": 1}"
    
  3. La respuesta trae {ok, durationMs, comprobante, cae, resultado, caeFchVto, traffic}. resultado: "A" = aprobado. El bloque traffic tiene el XML SOAP exacto que se mandó/recibió de ARCA.

Probar el anti-doble-facturación

Reenviá el mismo nroTicketPos y vas a recibir el CAE existente en vez de uno nuevo: ejercita la idempotencia del flujo real (fecaeSolicitarNextGen).

curl -X POST http://localhost:8080/api/cockpit/test/cae ^
  -H "Content-Type: application/json" ^
  -d "{\"suc\": 1, \"pos\": 1, \"nroTicketPos\": \"TICKET-DEMO-001\"}"

Es un CAE real en homologación

El backend loguea un WARN ruidoso ([COCKPIT-CAE-PRUEBA] EMITIENDO CAE REAL…). Solo usalo en el ambiente de prueba. Detalle en Cockpit.

Configurar un SucPosPV

SucPosPV mapea sucursal + POS físico → punto de venta AFIP. El ABM va gateado por secret.

  1. Definí el secret al arrancar (env var COCKPIT_ADMIN_SECRET, ya está en run.bat). Sin secret, el ABM responde 503.
  2. Dá de alta el mapeo (mandando el secret en el header X-Cockpit-Secret):
    curl -X POST http://localhost:8080/api/cockpit/sucpospv ^
      -H "X-Cockpit-Secret: %COCKPIT_ADMIN_SECRET%" ^
      -H "Content-Type: application/json" ^
      -d "{\"suc\": 1, \"pos\": 1, \"pvcae\": 3, \"pvcaea\": 4}"
    
    pvcaea es opcional (un POS puede facturar solo CAE).
  3. Verificá la lista:
    curl http://localhost:8080/api/cockpit/sucpospv -H "X-Cockpit-Secret: %COCKPIT_ADMIN_SECRET%"
    
  4. (Opcional) Validá los PV contra AFIP a demanda:
    curl -X POST http://localhost:8080/api/cockpit/sucpospv/1/validar-arca ^
      -H "X-Cockpit-Secret: %COCKPIT_ADMIN_SECRET%"
    
    409 = el PV no existe o está bloqueado en AFIP; 502 = AFIP no respondió.

Detalle de códigos y revalidación en Cockpit.

Correr el smoke contra AFIP homologación

El smoke pega contra la red real de AFIP con el cert .p12. Está gateado (@EnabledIfSystemProperty): no corre en el mvn test normal.

:: atajo del repo (equivale al comando de abajo)
tt.bat

:: o explícito:
mvn -o test -Dtest=AfipHomologacionSmokeTest -Dafipsmoke=true -Dafip.p12.password=<clave-del-p12>

AfipHomologacionSmokeTest hace el flujo end-to-end de lectura: WSAA LoginCms (firma CMS → token) + WSFE FECompUltimoAutorizado (read-only, no emite).

El TA tiene cooldown — corré el smoke UNA vez

AFIP rechaza el re-login si ya hay un TA vigente ("ya posee un TA valido") por ~12 h. El propio test lo avisa. No lo corras en loop. La clave del .p12 va por system property (-Dafip.p12.password=…), nunca en el repo.

Hay smoke tests hermanos para otros flujos: CaeaHomologacionSmokeTest (CAEA) y, contra DB real, CockpitRealDbSmokeTest / RealDbSchemaValidationTest (perfil realdb, gateados aparte).

Ver el estado de los jobs

curl http://localhost:8080/api/cockpit/jobs

Devuelve una fila por job con cron, ultimaEjecucion, resultado (OK/ERROR), error y proximaEjecucion. Para entender qué hace cada job y cómo dar de alta uno nuevo, mirá Jobs Quartz.

Despliegue (Windows)

Instalar como servicio con NSSM

En producción el backend corre como servicio de Windows (arranca solo con el sistema, se reinicia ante caídas, no depende de una consola abierta). Usamos NSSM (Non-Sucking Service Manager), que envuelve java.exe como servicio con apagado graceful, logs rotados y arranque automático.

Prerequisitos

  • El fat jar tifactura-spring.jar ya compilado en el AppDirectory (generalo con mvn -DskipTests package — debe ser el jar de Spring Boot, no el "thin jar").
  • JDK instalado (apuntá java.exe a la versión con la que validaste el jar; ver nota de versión abajo).
  • NSSM en el PATH (o invocalo con su ruta completa).
  • La base SQL Server accesible y las variables de entorno configuradas (ver más abajo — el servicio no usa run.bat).
  • Creá la carpeta de logs antes de arrancar: mkdir c:\Work\TiFacturaOnlineNext\logs.

Registro y configuración del servicio (corré en una consola como administrador):

nssm install TiFacturaOnlineNext "c:\Program Files\Java\jdk-21\bin\java.exe"
nssm set TiFacturaOnlineNext AppParameters "-Dserver.shutdown=graceful -Dspring.lifecycle.timeout-per-shutdown-phase=15s -jar tifactura-spring.jar"
nssm set TiFacturaOnlineNext AppDirectory "c:\Work\TiFacturaOnlineNext"
nssm set TiFacturaOnlineNext Start SERVICE_AUTO_START
nssm set TiFacturaOnlineNext AppStdout "c:\Work\TiFacturaOnlineNext\logs\service.out.log"
nssm set TiFacturaOnlineNext AppStderr "c:\Work\TiFacturaOnlineNext\logs\service.err.log"
nssm set TiFacturaOnlineNext AppRotateFiles 1
nssm set TiFacturaOnlineNext AppRotateOnline 1
nssm set TiFacturaOnlineNext AppRotateBytes 10485760
nssm set TiFacturaOnlineNext AppStopMethodConsole 20000
nssm set TiFacturaOnlineNext AppStopMethodWindow 5000
nssm set TiFacturaOnlineNext AppStopMethodThreads 5000
nssm set TiFacturaOnlineNext DisplayName "TiFactura Online (Spring)"
nssm set TiFacturaOnlineNext Description "Backend facturacion AFIP - Spring Boot (java directo, graceful shutdown)"

Las variables de entorno son obligatorias — el servicio no lee run.bat

Corriendo como servicio no existen las variables que setea run.bat. Cargalas con AppEnvironmentExtra (una línea, pares CLAVE=valor) antes de iniciar, o el arranque falla (DB, secret del ABM, auth del cockpit):

nssm set TiFacturaOnlineNext AppEnvironmentExtra ^
  DB_PASS=tu_password ^
  COCKPIT_ADMIN_SECRET=tu_secret ^
  COCKPIT_USER=tu_usuario ^
  COCKPIT_PASS=tu_clave
Sumá las que tu entorno necesite (DB_USER, DB_HOST, AFIP_CUIT, etc.). Detalle de cada una en Configuración y perfiles.

Qué hace cada parámetro clave

  • -Dserver.shutdown=graceful + timeout-per-shutdown-phase=15s — al frenar el servicio, Spring deja terminar las requests/jobs en curso (hasta 15 s) antes de cerrar. Importante para no cortar una emisión de CAE a la mitad.
  • AppStopMethodConsole 20000 — NSSM le da 20 s a la app para apagarse sola (envía Ctrl-C) antes de forzar; es mayor que los 15 s de Spring a propósito, para que el graceful complete. Recién después prueba cerrar ventana (...Window) y matar hilos (...Threads).
  • AppRotate* — rota service.out.log / service.err.log al superar 10 MB (AppRotateBytes), incluso en caliente (AppRotateOnline).
  • Start SERVICE_AUTO_START — arranca con Windows.

Operar el servicio

nssm start   TiFacturaOnlineNext      :: iniciar
nssm stop    TiFacturaOnlineNext      :: detener (graceful)
nssm restart TiFacturaOnlineNext      :: reiniciar
nssm status  TiFacturaOnlineNext      :: estado (SERVICE_RUNNING / SERVICE_STOPPED)
nssm edit    TiFacturaOnlineNext      :: editar la config en una ventana
nssm remove  TiFacturaOnlineNext confirm   :: desinstalar el servicio

También sirven los comandos nativos de Windows (sc start TiFacturaOnlineNext, services.msc). Tras arrancar, verificá: el cockpit en http://localhost:8080/cockpit y el log en c:\Work\TiFacturaOnlineNext\logs\service.out.log.

La versión de Java tiene que ser la soportada

El ejemplo apunta a jdk-21, pero usá la misma versión con la que validaste el jar. El proyecto compila para Java 17 y es sensible a la versión del runtime (con un JDK demasiado nuevo el arranque puede romper). Antes de instalar el servicio, confirmá que el jar levanta a mano con ese java.exe:

cd c:\Work\TiFacturaOnlineNext
"c:\Program Files\Java\jdk-21\bin\java.exe" -jar tifactura-spring.jar
Si arranca bien a mano, andará como servicio.

Documentación

Correr esta doc en local

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
mkdocs serve

Abrí http://127.0.0.1:8000. mkdocs serve recarga en vivo al editar.

Antes de pushear:

mkdocs build --strict

Exportar la doc a un PDF

El sitio se exporta a un único PDF (con portada, índice y los diagramas Mermaid renderizados) vía mkdocs-exporter. La primera vez hay que instalar el Chromium headless:

pip install -r requirements.txt
python -m playwright install chromium

El export está desactivado por defecto (para que serve/build sean rápidos). Se activa con la variable PDF_EXPORT:

$env:PDF_EXPORT = "true"; mkdocs build

El PDF queda en site/pdf/tifacturaonline-documentacion.pdf.

Mermaid y el separador ;

Mermaid usa ; como separador de sentencias: no uses ; dentro del texto de un nodo o el diagrama no compila (usá <br/> para saltos de línea). La portada vive en pdf-cover.html y el hook que renderiza Mermaid en el PDF es docs/assets/wait-mermaid.js — no lo borres.

Por dónde seguir