Ir al contenido

Pipeline de inserción

El endpoint insertar facturas procesa cada batch en un orden estricto de prioridad. Cada paso es un filtro: si falla, detiene el proceso y devuelve un 422. Conocer este orden te permite diagnosticar exactamente por qué se rechazó un batch y en qué etapa.

flowchart TD
    Start([POST /facturas/insertar]) --> Auth{ApiKey válido?}
    Auth -- no --> E401([401])
    Auth -- sí --> P1{1· body es array no vacío?}
    P1 -- no --> E1([422 body inválido])
    P1 -- sí --> P2{2· campos obligatorios?}
    P2 -- no --> E2([422 errores·])
    P2 -- sí --> P3{3· fechas V1/V2/V3?}
    P3 -- no --> E3([422 FECHAS_INVALIDAS<br/>TODO el batch])
    P3 -- sí --> P4{4· manifiestos hoy/nuevos?}
    P4 -- no --> E4([422 MANIFIESTOS_FECHA_INVALIDA<br/>TODO el batch])
    P4 -- sí --> P5{5· batch duplicado hoy?}
    P5 -- sí --> D([200 resumen original])
    P5 -- no --> P6[6· persistir payload crudo]
    P6 --> P7[7· procesar por manifiesto]
    P7 --> P8{rechazos por manifiesto?}
    P8 -- sí --> R([422 + inserta los válidos])
    P8 -- no --> OK([200 éxito])

    style E3 fill:#fde3e3,stroke:#c0392b,color:#7a271a
    style E4 fill:#fde3e3,stroke:#c0392b,color:#7a271a
    style OK fill:#dcf3e3,stroke:#1f8a4c,color:#14532d
    style D fill:#dcf3e3,stroke:#1f8a4c,color:#14532d
  1. El cuerpo debe ser un array JSON no vacío. Si llega vacío, nulo o con otro tipo, se responde 422 con “El body debe ser un array JSON de facturas no vacío.”

  2. Se revisa que cada factura traiga sus campos obligatorios y que cada línea traiga los suyos. Cualquier falta acumula un error en errores[] y se responde 422. El Total debe ser numérico y ≥ 0; LineasFactura no puede estar vacío.

  3. Es la línea de defensa más temprana contra data corrupta: ocurre antes de tocar la base de datos. Revisa cada factura del manifiesto: ninguna puede ser futura ni tener más de 30 días de antigüedad (ver reglas de fecha). La mezcla de fechas dentro de un manifiesto está permitida. Si una sola factura falla, se rechaza ese manifiesto completo con motivo: FECHAS_INVALIDAS. La respuesta trae manifiestos_validos[] y manifiestos_rechazados[] con el detalle. El rechazo queda en el log; la notificación in-app a admins es opcional (off por defecto).

  4. Si intentas agregar facturas a un manifiesto que ya existe y fue creado antes de hoy, se rechaza todo el batch con motivo: MANIFIESTOS_FECHA_INVALIDA. La respuesta trae manifiestos_no_afectados[] con los manifiestos válidos a reenviar por separado.

  5. Se calcula un hash del contenido. Si un batch idéntico ya se procesó hoy (y no falló), no se reprocesa: se responde 200 con el resumen del proceso original. Esto hace seguro reintentar ante un timeout.

  6. El lote recibido se guarda tal cual, con un batch_uuid. Esto da trazabilidad completa: ante cualquier duda, Hosana puede revisar exactamente qué se recibió.

  7. Aquí se procesa manifiesto por manifiesto, en este orden:

    1. Validar almacenesAlmacen inexistente → ALMACENES_DESCONOCIDOS.
    2. Manifiesto cerradoMANIFIESTO_CERRADO.
    3. Facturas duplicadas en otro manifiestoFACTURAS_DUPLICADAS_EN_OTRO_MANIFIESTO.
    4. Crear el manifiesto si no existe (fecha operativa derivada de FechaFactura).
    5. Clasificar facturas: nuevas (se insertan), idénticas (sin cambios), o con diferencias (conflicto pendiente de revisión).
    6. Insertar las nuevas en bloque y recalcular los totales del manifiesto.

    Un rechazo aquí es por manifiesto: las facturas de los manifiestos válidos del mismo batch sí entran.

  8. Se arma el resumen con los conteos y, si hubo rechazos, el arreglo manifiestos_rechazados[]. El código HTTP es 200 si no hubo ningún rechazo, o 422 si hubo al menos un manifiesto rechazado.

Una distinción que conviene tener clara: los pasos 3 y 4 son todo o nada sobre el batch completo, mientras que el paso 7 actúa por manifiesto. Cuando ves insertadas: 0 junto a un motivo de fecha, el rechazo fue temprano; cuando ves algunas insertadas y otras rechazadas, ocurrió durante el procesamiento.