TiFactura · Notificador AFIP — estado 2026-08-27
Lo que eran 6 proyectos casi idénticos mantenidos a mano es hoy un solo jar donde cada instalación se declara con configuración explícita: una base, cuatro flags de impuestos y dos quirks. Un cambio regulatorio se hace una vez. Un cliente nuevo no toca código. Activar un impuesto es una línea de YAML.
01 — Así quedó hoy
02 — La configuración
Un archivo por instalación, fuera del jar (config\application-prod.yml, al lado del jar — run.bat lo crea del template en el primer arranque). Esto es TODO lo que define una instalación:
# ============ QUÉ ES ESTA INSTALACIÓN (explícito — la única forma) ============ tifactura: label: "ALMACOR" # nombre para el cockpit (opcional, recomendado) base: TipreRetail # REQUERIDO: TipreRetail (tabla de_tresu) | TipreSucursales (detresu). # Define nombres de columnas y el filtro flagcontrol de Sucursales. impuestos: # REQUERIDOS los 4, en SI/NO. Falta uno → NO ARRANCA. iibb: SI # Ingresos Brutos (código ARCA 2) comind: SI # Comercio e Industria (código ARCA 3) percepcion-iva: NO # Percepción IVA 21/10.5 (viaja como ARCA 99 + descripción) impuestos-internos: SI # Impuesto Interno (código ARCA 4) quirks: # opcionales (default NO) — el "caso TIZIANO", explícito total-desde-fprecio-total: NO # importeTotal desde la columna cruda fprecioTotal (solo Retail) registra-mensaje-error: NO # escribe/limpia cMensajeError ante fallo/éxito (solo Retail) cuit: "30xxxxxxxxx" # CUIT del ente (recomendado): el Manager resuelve el comercio por CUIT (v2) # ============ INFRAESTRUCTURA ============ server: port: 8080 # puerto del cockpit/doc/status — cambialo si está ocupado spring: datasource: # la base del cliente (coherente con tifactura.base) url: jdbc:sqlserver://HOST:1433;databaseName=TipreRetail username: usuario password: ******** # SOLO acá — nunca dentro del jar ni en el repo (config\ está gitignored) # ============ OPERACIÓN ============ notify.to.afip.cron.scheduler: "0 0/5 * * * ?" # cuándo corre el job (acá: cada 5 min) tifacturaonlinemanager.service.url: http://HOST:8087/TiFacturaOnlineManager/resource/rest/trxWS process.max.results: 50 # tope de comprobantes por punto de venta por corrida (≥1 o no arranca) # ============ IDS FISCALES (códigos ARCA — viajan tal cual al XML) ============ id: ente.facturador: 1 # id interno del comercio en el Manager (NO es código ARCA) tributo: ing.bruto: 2 # ARCA 2 = Impuestos provinciales — VERIFICADO EN VIVO (Anexo B) comind: 3 # ARCA 3 = Impuestos municipales — VERIFICADO EN VIVO impinterno: 4 # ARCA 4 = Impuestos Internos — VERIFICADO EN VIVO (no usar 10) perciva: 99 # ARCA 99 = "Otro" + Desc — así viaja la Percepción de IVA iva: { "0": 3, "105": 4, "21": 5 } # alícuotas ARCA — comillas OBLIGATORIAS logging.file.name: ./log/tifactura.log
| Situación | Qué pasa |
|---|---|
| base ausente o inválida | NO ARRANCA — mensaje claro con los dos valores válidos. |
| Falta cualquiera de los 4 flags de impuestos, o un valor no es SI/NO | NO ARRANCA — ningún impuesto queda apagado por accidente. |
| Quirk de Retail sobre base Sucursales | NO ARRANCA — combinación físicamente imposible (esas columnas no existen en detresu). |
| process.max.results ≤ 0 | NO ARRANCA la corrida — antes era un "procesa cero para siempre" silencioso. |
| Flag en NO | El impuesto jamás se emite y sus columnas ni se consultan — inmune a columnas ausentes por instalación. |
| Flag en SI | Se emite cuando el importe de la fila ≠ 0 — el dato decide caso a caso. |
El template real (config-template\application-prod.yml, también en el Release) trae todo esto comentado + la tabla oficial ARCA completa + el sello de verificación en vivo. Referencia clave-por-clave en el manual /doc.
03 — La matriz de referencia
No hay presets en el código — esta matriz es conocimiento, no mecanismo: al instalar un cliente, copiás su fila al YAML.
| Cliente | Base · tabla | iibb | comind | percIVA | impInternos | Quirks / lógica particular |
|---|---|---|---|---|---|---|
| DINO | TipreRetail · de_tresu | SI | SI | SI | NO | Referencia; único solo-percepción (alíc. 3% / 1.5%). |
| ALMACOR | TipreRetail · de_tresu | SI | SI | NO | SI | Imp. interno a monto fijo (base 0, alícuota 0). |
| BECERRA | TipreRetail · de_tresu | SI | SI | NO | SI | Igual que ALMACOR. |
| TIZIANO | TipreRetail · de_tresu | SI | SI | NO | SI | Ambos quirks SI: total desde fprecioTotal + registra cMensajeError. |
| CARACOL | TipreSucursales · detresu | SI | SI | SI | SI | El único con ambos. Filtro flagcontrol>0. NC/ND sin fecha asociada (preservado). |
| CYRE | TipreSucursales · detresu | SI | SI | NO | SI | Como CARACOL sin percepción. |
04 — El sello
Anexo A — Lo que había
Todo detectado por las revisiones del día y resuelto (salvo lo marcado como deuda):
El template traía valores de ejemplo (comind: 4, iva: 6/7/8) que viajan tal cual al XML de ARCA — trampa de copy-paste que habría emitido códigos incorrectos. Quedó: códigos oficiales (2/3/4/99, IVA 3/4/5) verificados EN VIVO contra ARCA (Anexo B).
Tras el refactor, la estrategia respetaba los flags pero el SQL del total no — con iibb: NO el total incluía un impuesto no declarado. Quedó: los 4 impuestos gateados simétricamente en SELECT, suma de tributos y total.
Nombre mágico con typo booteaba con impuestos apagados · max.results=0 procesaba cero para siempre sin error · quirk imposible se degradaba en silencio. Quedó: flags explícitos obligatorios + fail-fast en todas esas rutas — y al final, los nombres mágicos se eliminaron del todo (decisión de hoy: el YML declara todo).
Un arranque fallido dejaba el JVM vivo con el puerto tomado respondiendo 404 (lo encontró el testing E2E de instalación; dos jueces lo habían pasado por alto). Quedó: salida dura del proceso — probado: proceso muerto, puerto libre.
El original escribía el error en la base ante fallos y lo limpiaba al notificar — se había caído sin documentar (CRITICAL del primer Judgment Day). Quedó: restaurado verbatim; hoy es el quirk registra-mensaje-error.
~650 MB por heap sin tope (quedó -Xmx256m ≈ 400 MB medidos) · CPU en reposo = 0% medido (los picos eran arranque o el cron de dev cada 1 segundo) · puerto no configurable (quedó server.port) · run.bat no funcionaba en layout de instalación (quedó dual).
null→0 en importes (el legacy propagaba null; cambiarlo a ciegas es riesgo fiscal — necesita test con fila NULL real) · alias de columnas duplicados SELECT/mapper · SQL rebuild en hot path · constructor posicional de 34 args · GET feCompUltimoAutorizado sin cuit (falla en Manager multi-comercio — hallado por el E2E).
Anexo B — IDs fiscales
Llamada real a FEParamGetTiposTributos / FEParamGetTiposIva (WSAA con certificado, homologación, 2026-08-27):
| Config | Código | Catálogo ARCA (vivo) | Estado |
|---|---|---|---|
| ing.bruto | 2 | Impuestos provinciales (desde 2010) | ✓ vigente |
| comind | 3 | Impuestos municipales (desde 2010) | ✓ vigente |
| impinterno | 4 | Impuestos Internos (desde 2010) — el 10 NO existe en WSFE | ✓ vigente |
| perciva | 99 | "Otro" + Desc (los específicos 5=IIBB y 6=Perc.IVA existen desde 2017 como alternativa — migrar sería cambio deliberado) | ✓ vigente |
| iva 0/10.5/21 | 3/4/5 | Alícuotas (+6=27%, 8=5%, 9=2.5%) | ✓ vigentes |
Cadena de evidencia: producción legada (años facturando) → manuales oficiales → Excel oficial otros_Tributos.xlsx (archivado en docs/) → respuesta viva del WS. Re-verificable con tools\consulta-tributos-arca.ps1.
Anexo C — E2E vivo
Seis combinaciones (todas las filas de la matriz, quirk de TIZIANO incluido) dispararon notificaciones REALES contra el Manager local y ARCA homologación. Cada barrera superada enseñó algo:
| Pasada | Barrera | Qué quedó probado |
|---|---|---|
| v1 | ARCA obs 703 (numeración secuencial) | El circuito llega a ARCA; el Manager persistió el intento con total=1280 y tributos=70 EXACTOS (1000 neto + 210 IVA + 15 comInd + 25 IIBB + 30 percIVA) + reconciliación + CbteFchHsGen. |
| v3 | Dedup del Manager (UQ_Trx_nextgen) | ARCA aceptó la numeración; la defensa anti-duplicados del Manager funciona (ticket único por día — mis datos sintéticos lo violaban). |
| v4 | ARCA obs 1444 (PV no habilitado) | 4 comprobantes persistidos en el Manager con desglose de IVA y tributos hijos; solo faltan datos maestros de ARCA. |