Saltar a contenido

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.

CaeaWsRestControllerGET /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:

GET /caeaWS/getCaea
GET /caeaWS/getCaea?nrosuc=12&nropos=3

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).

GET /feCompUltimoAutorizado?ptoVta=5&cbteTipo=6

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.