API REST¶
Referencia de los endpoints REST (Spring MVC) de TiFacturaOnlineNext: versión, flujo CAEA para el POS y el contrato de errores. Los endpoints SOAP están en API SOAP; el ciclo de negocio, en El ciclo de facturación.
El Cockpit (ABM de SucPosPV, observabilidad) expone sus propios endpoints REST y se documenta aparte: ver Cockpit.
Endpoints¶
Todos son @RestController Spring MVC; el produces/consumes es application/json. La columna Acceso refleja el estado actual de seguridad (ver nota más abajo).
| Controller | Ruta | Método | Acceso | Qué hace |
|---|---|---|---|---|
VersionController |
/ |
GET |
abierto | Devuelve la versión (v20250328). |
CaeaWsRestController |
/caeaWS/getCaea |
GET |
abierto | Lista los CAEAs vigentes/futuros del comercio (paso 1 del flujo POS). |
CaeaNotificacionRestController |
/fecaeaSolicitar |
POST |
abierto | Registra un comprobante CAEA emitido offline por el POS (notificador DINO). |
CaeaNotificacionRestController |
/feCompUltimoAutorizado |
GET |
abierto | Último comprobante autorizado en ARCA para (ptoVta, cbteTipo). |
Seguridad: hoy todo abierto (scaffold)
SecurityConfig es un scaffold de hito: csrf().disable() + anyRequest().permitAll(). No hay roles ni autenticación todavía — eso es SPEC-014 (login DB, roles). Por eso la columna Acceso es "abierto" en todos los casos. El único candado parcial del sistema es el del Cockpit (header X-Cockpit-Secret, no es auth real); ver Cockpit.
VersionController¶
El más simple: GET / devuelve un string JSON con la versión.
@GetMapping(value = "/", produces = "application/json")
public String getVersion() { return VERSION; } // "v20250328"
En el sistema real la versión es ParentEntityManager.VERSION; acá la constante actúa de stand-in del contrato.
CaeaWsRestController — GET /caeaWS/getCaea¶
Paso 1 del flujo POS: lista los CAEAs vigentes/futuros del comercio en JSON. Es la reescritura del legacy JAX-RS (CaeaWSRest) a Spring MVC; delega en CaeaConsultaService.
Acepta dos query params opcionales nrosuc y nropos (tipo Integer, para distinguir "no vino" de 0). Si llegan ambos, agrega nropvcae / nropvcaea / cuit a la respuesta:
El handoff es de una sola vez: obtenerPVParaPOS devuelve la fila solo si el POS no obtuvo aún los datos (y los sella); si ya los obtuvo, devuelve null y el POS recibe solo los CAEAs.
La respuesta es GetCaeaResponse (@JsonInclude(NON_NULL) — los extras nulos no se serializan):
{
"caeas": [
{ "caea": "...", "periodo": 202606, "orden": 1,
"fchVigDesde": "...", "fchVigHasta": "...",
"fchTopeInf": "...", "fchProceso": "..." }
],
"nropvcae": "5",
"nropvcaea": "6",
"cuit": "..."
}
Path: falta el prefijo de prod
El legacy servía en /TiFacturaOnlineManager/resource/rest/caeaWS/getCaea. Acá el recurso queda en /caeaWS/getCaea; el prefijo /resource/rest + context-path para igualar la URL de prod es config de despliegue (pendiente, igual que cxf.path para SOAP).
CaeaNotificacionRestController — notificador DINO¶
Endpoints consumidos por el notificador DINO (fase 2 anti-doble-factura). No usa @RequestMapping de clase para evitar colisión con /caeaWS: ambos cuelgan de la raíz del context-path.
POST /fecaeaSolicitar¶
Recibe el Trx JSON del notificador (TrxCaeaRequest, no la entidad JPA), lo registra en ARCA y persiste la fila CAEA. Es idempotente: si el comprobante ya existe (mismo ptoVta + comprobante + CAEA + V2) lo devuelve sin re-insertar ni re-reportar a ARCA. Delega en CaeaNotificacionService.registrarCaea. Devuelve ResponseEntity<Trx> (la Trx persistida con id, resultado y caea seteados).
TrxCaeaRequest espeja los campos que envía DINO (TiFacturaOnlineManagerClient.fecaeaSolicitar): cabecera del comprobante, receptor, importes, fechas de servicio, caea / cbteFchHsGen, datos POS (nroTicketPos / nroSuc / nroPos) y las colecciones alicuotaIvas / tributos / comprobantesAsociados. Es un DTO explícito para aislar el contrato JSON del modelo de dominio.
GET /feCompUltimoAutorizado¶
Devuelve el último número de comprobante autorizado en ARCA para el (ptoVta, cbteTipo) dado. Contrato del notificador: devuelve Integer (0 si no hay ninguno).
Contrato de errores REST (DefaultExceptionHandler)¶
INVARIANTE (REFERENCE.md §5.8). Es la reescritura funcional del legacy (JAX-RS @Provider ExceptionMapper<Exception>) a un @RestControllerAdvice Spring MVC, con comportamiento observable idéntico.
Ante cualquier excepción (@ExceptionHandler(Exception.class)) devuelve:
| Componente | Valor |
|---|---|
| HTTP status | 500 INTERNAL_SERVER_ERROR |
Header exception-class |
nombre completo de la clase (e.getClass().getName()) |
Header exception-message |
String.valueOf(e.getMessage()) |
Content-Type |
application/json |
| Body | el stacktrace completo (de e.printStackTrace) |
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.header(ERROR_TYPE, e.getClass().getName()) // "exception-class"
.header(ERROR_MESSAGE, String.valueOf(e.getMessage())) // "exception-message"
.contentType(MediaType.APPLICATION_JSON)
.body(errors.toString()); // stacktrace
Mensaje null → header literal \"null\"
El legacy pasaba e.getMessage() crudo al header (puede ser null). Acá se usa String.valueOf(...) para evitar NPE al setear el header en Spring: si el mensaje es null, el header queda con el string "null". Si en paridad (SPEC-016) se detecta que el cliente espera el header ausente, se revisa.
Por dónde seguir¶
- API SOAP — los 3 endpoints SOAP (incluida la variante SOAP de
getCaea). - Cockpit — los endpoints REST de administración y observabilidad.
- El ciclo de facturación — dónde encaja el flujo CAEA del POS.