Saltar a contenido

Reglas de negocio — API pública de creación de guías

Estado: reglas levantadas en entrevista con Iker el 2026-10-23, contrastadas con el código de ApiLambdaCrearGuia, ApiLambdaCargarGuias, ApiLambdaAnularGuia y el modal Angular modal-creacion-pedidos. No hay código de la API desplegado. Cupo financiero y alarmas de pedidos tienen su propio documento: cupo.md y alarmas-pedidos.md (en construcción). Aquí solo se referencian. Pendiente a futuro: Iker creará una base de conocimiento; migrar estas specs allí cuando exista.


Cómo leer este documento

Cada regla tiene un id RN-XXX, un enunciado, su fuente y su estado.

Estado Significado
Confirmada Iker la decidió o la aprobó (entrevista 2026-10-23, brief del proyecto o ADR/documento ya aprobado)
Pendiente Falta un dato o una decisión. Hay una recomendación, pero no es regla hasta que Iker la confirme

Pendientes: los ids RN-P-xx de este documento se llamaban P-xx; se renombraron para no chocar con los de pendientes-preprod.md (decisiones antes de PreProd).

Fuentes: CR = Lambdas_NET_LogiGho/LambdasLogiGho.Aplicacion/Logigho/ApiLambdaCrearGuia; CG = .../ApiLambdaCargarGuias/src/ApiLambdaCargarGuias; AN = .../ApiLambdaAnularGuia/src/ApiLambdaAnularGuia; Modal = Angular SitioLogiGho/SitioLogiGho/src/app/components/modal-creacion-pedidos/modal-creacion-pedidos.component.ts; "Decisión Iker" = entrevista del 2026-10-23.

Los nombres de campo de la API son propuestos (camelCase); la columna "Campo actual" indica el campo del flujo de hoy en CargaPedido.


1. Alcance y principios

Id Regla Fuente Estado
RN-001 La API replica el flujo actual y sus destinos: inserta en CargaPedido, llama a la transportadora, actualiza CargaPedido, inserta en PedidosInter (mismo formato PascalCase, Estado = "Creado"), dispara la etiqueta (/creacionEtiqueta, Step Function Step_Creacion_Etiqueta, buckets bucket-guias-inter-prod y bucket-guias-pdf-prod) y avisa al inventario (/actualizaInventarioLotes {Guias}) CR/.../CargaInterUseCase.cs:251-255; Modal:1343-1348; ApiPublicaGuias.md Confirmada
RN-002 Transportadoras de v1: Interrapidísimo primero (F1); luego Envia, TCC, Servientrega y D2E (F3). XCargo (D2) no Decisión Iker Confirmada
RN-003 Fuera de v1: contraentrega (COD), recogidas (FECHA RECOGIDA), cotización y operación fuera de Colombia. Por tanto APLICA CONTRA PAGO es siempre NO y Total recaudo es 0 (decisión de Iker, 2026-10-24: se valida como campo separado del valor declarado, que siempre debe ser ≥ 45 000; ya no se copia el valor declarado al recaudo) Decisión Iker; ApiPublicaGuias.md Confirmada
RN-004 Las reglas que varían por transportadora (valor declarado mínimo, límites de peso y dimensiones, longitudes de texto, capacidades de entrega y anulación) viven en una colección de reglas en BD, no en variables de entorno ni en el código. Agregar una transportadora o ajustar un límite no exige desplegar Decisión Iker Confirmada
RN-005 Los defectos conocidos no se replican: guías duplicadas por reintentos, pedidos huérfanos, transportadora desconocida que cae a Envia, y cliente que manda IdTienda/TiendaProveedor/Estado arbitrarios hallazgos-lambdas-actuales.md Confirmada

2. Campos de entrada de la guía

El body de POST /v1/guias es un objeto con los campos de esta sección. Un lote (sección 7) es una lista de estos mismos objetos.

2.1 Tabla de campos

Campo API Campo actual Obligatorio Formato / valores Regla
referencia — (nuevo) Sí en lotes Texto, único por cliente RN-010
tiendaId IdTienda Sí Id de una tienda permitida al cliente RN-030
transportadora TRANSPORTADORA Sí INTERRAPIDISIMO, ENVIA, TCC, SERVIENTREGA, D2E RN-025
destinatario.nombres NOMBRE COMPLETO Sí Texto RN-016
destinatario.apellidos NOMBRE COMPLETO Sí Texto RN-016
destinatario.tipoDocumento fijo "CC" en Inter/TCC No CC, CE, NIT, PAS, TI; default CC RN-017
destinatario.numeroDocumento IDENTIFICACION (OPCIONAL) No Texto numérico RN-017
destinatario.telefono TELEFONO Sí Dígitos nacionales del país de la tienda (CO: 10 dígitos) RN-018
destinatario.correo CORREO (OPCIONAL) No Correo válido RN-021
destinatario.direccion DIRECCION Sí Texto, largo máximo por transportadora RN-019
destinatario.ciudad CIUDAD Sí DANE de 8 dígitos RN-050
peso PESO Sí kg, decimal, máx. 2 decimales RN-013, RN-014
largo, ancho, alto LARGO, ANCHO, ALTO Sí cm RN-013
valorDeclarado VALOR DECLARADO Sí Entero COP > 0 y ≥ 45 000 (mínimo de la transportadora) RN-011, RN-012
totalRecaudo Total recaudo No Entero COP ≥ 0; campo distinto del valor declarado. Sin contraentrega vale 0 (o no se envía); mayor que 0 se rechaza con CONTRAENTREGA_NO_DISPONIBLE mientras la contraentrega esté fuera de v1 RN-003
tipoEntrega TIPO ENTREGA No 1 entrega en dirección (default); 2 reclame en oficina RN-053
diceContener DICE CONTENER Por definir Texto RN-022
observaciones OBSERVACIONES No Texto RN-022
productos[] ID STOCK n / CANTIDAD STOCK n Según tienda { idProducto, cantidad }, máx. 18 RN-035 a RN-037
tipoEtiqueta TIPO ETIQUETA No Sticker o Mediana; default Sticker RN-020
datosAdicionales — (nuevo) No Objeto con claves permitidas por cliente RN-024

2.2 Reglas

Id Regla Fuente Estado
RN-010 Decisión 2026-10-24: la clave de idempotencia por guía es Idempotency-Key, tanto en POST /v1/guias como en cada guía de un lote (ADR-003). La referencia (id del pedido del integrador) se acepta como dato de la guía; si es obligatoria en lotes y si va además de la clave sigue pendiente (RN-P-14) Decisión Iker; ADR-003 Confirmada (clave); referencia pendiente
RN-011 valorDeclarado es obligatorio y entero COP > 0. No hay default silencioso: hoy Inter cae a 10 000 si el valor no parsea (CR/.../CargaInterUseCase.cs:92) y Envia usa un VALOR BASE PRODUCTO fijo de 10 000 (CR/.../CargaEnviaUseCase.cs:173) Decisión Iker Confirmada
RN-012 El valor declarado mínimo se parametriza por transportadora en la colección de reglas (RN-004). La configuración deja espacio para distinguir con/sin recaudo cuando entre COD. Valor inicial (decisión de Iker, 2026-10-24): 45 000 COP para TODAS las transportadoras, con o sin recaudo. Lo que distingue con y sin recaudo es el campo AplicaContraPago (en v1 siempre NO); se revisa si aparecen problemas Decisión Iker Confirmada
RN-013 peso, largo, ancho y alto son obligatorios, sin default. Hoy los use cases parsean a 0 si el valor es inválido (CR/.../CargaInterUseCase.cs:98-101) y el front manda 1 kg y 10×10×10 cm por defecto (Modal:1227-1230). Valor ausente, no numérico o ≤ 0 → error de campo Decisión Iker Confirmada
RN-014 El peso acepta decimal (máx. 2 decimales). Si la transportadora exige entero se redondea hacia arriba, y la respuesta devuelve el peso facturable ya redondeado. Hoy Envia/D2E hacen int.TryParse (un peso 1.5 queda en 0), Servientrega hace Floor (CargaServientregaUseCase.cs:161) e Inter/TCC aceptan decimal Decisión Iker Confirmada
RN-015 Límites mínimos y máximos de peso y de dimensiones (lado máximo, suma de lados) por transportadora, configurables en la colección de reglas. Hoy el código no valida máximos (Inter siempre crea PAQUETE PEQUEÑO, IdTipoEnvio = 3; TCC pasa a paquetería si el peso > 5 kg). Mientras no haya valores, la API devuelve el error de la transportadora Decisión Iker Confirmada (valores: ver RN-P-02)
RN-016 El destinatario se envía con nombres y apellidos separados, ambos obligatorios. La API arma el nombre completo internamente. Elimina el parseo frágil por espacios (con una sola palabra Inter duplica nombre y apellidos, CR/.../CargaInterUseCase.cs:151-153) Decisión Iker Confirmada
RN-017 El documento es opcional, EXCEPTO en las transportadoras que lo exigen (regla DocumentoObligatorio de ApiReglasTransportadora; por defecto Interrapidísimo, decisión de Iker 2026-10-25, probado en PreProd: Inter rechaza documento vacío o cero; la API responde 400 antes de reservar cupo). tipoDocumento es un enum (CC, CE, NIT, PAS, TI) con default CC; si viene número sin tipo se asume CC. Hoy el tipo está fijo en "CC" (CR/.../CargaInterUseCase.cs:130). El mapeo del tipo a lo que acepta cada transportadora se define al integrar cada una (ver RN-P-06) Decisión Iker Confirmada
RN-018 El teléfono se valida y normaliza según el país de la tienda: acepta +57, espacios y guiones y guarda solo los dígitos nacionales. Colombia: celular de 10 dígitos (3XXXXXXXXX) o fijo de 7/10 dígitos. Inválido → error de campo, nunca 0 (hoy long.TryParse cae a 0, CR/.../CargaInterUseCase.cs:156). Las reglas por país están en el catálogo de RN-101 Decisión Iker Confirmada
RN-019 Los largos máximos de texto (dirección, observaciones, "dice contener", nombres) son por transportadora en la colección de reglas. Si se exceden, la API rechaza indicando el máximo; no trunca. Hoy TCC trunca en silencio (dirección 50, observaciones 250, nombre 60; CargaTccUseCase.cs:124-152) Decisión Iker Confirmada (valores de Inter: ver RN-P-02)
RN-020 tipoEtiqueta es opcional, enum Sticker | Mediana, default Sticker. La respuesta de creación no espera el PDF: la etiqueta se genera de forma asíncrona (RN-001) y se obtiene con GET /v1/guias/{numero}/etiqueta Decisión Iker; endpoints.md Confirmada
RN-021 correo es opcional; si viene debe tener formato de correo válido Recomendación Pendiente
RN-022 diceContener obligatorio (el flujo actual lo manda siempre y alimenta Productos en PedidosInter, CR/.../CargaInterUseCase.cs:230); observaciones opcional con default Pedido generado desde Logigho, que es el valor del front (Modal:1239) Recomendación Pendiente
RN-023 Los siguientes campos los fija el servidor y el cliente no puede enviarlos: Estado (Pendiente al ingresar, luego el flujo), Origen (API), IdCarga, Tienda (nombre), TiendaProveedor, sucursal remitente, CIUDAD ORIGEN, DIRECCION ORIGEN, Total Flete, Total Servicio, Total Sobreflete, NumeroPreenvio, APLICA CONTRA PAGO y FORMA DE PAGO (esta última según reglas-modalidad-pago.ts). Los defaults del front (ASESOR, CODIGO OFICINA = 1, CODIGO REGIONAL = 3, SEGURO, TELEFONO REMITENTE) se definen al implementar cada transportadora (ver RN-P-07) Decisión Iker; Modal:1210-1251 Confirmada (valores fijos: ver RN-P-07)
RN-024 Esquema estricto: un campo no definido o prohibido → 400 CAMPO_NO_PERMITIDO con el nombre del campo. Excepción: datosAdicionales, un objeto cuyas claves permitidas, tipo y largo máximo se configuran por cliente API. Un cliente normal no tiene ninguna; las tiendas propias de LogiGho, que también usarán la API y el MCP, tienen sus 2–3 campos extra (datos de venta, etc.). Los valores se guardan en CargaPedido/PedidosInter con el mismo nombre que usan hoy Decisión Iker Confirmada (nombres de los campos: ver RN-P-03)
RN-025 transportadora fuera del enum → 400; no permitida al cliente → 403 TRANSPORTADORA_NO_PERMITIDA. Nunca cae a Envia (hoy el switch usa Envia como default, CR/Function.cs:151, CG/Function.cs:130-135) Decisión Iker; hallazgos-lambdas-actuales.md Confirmada

3. Tienda, origen, sucursal remitente y productos

Id Regla Fuente Estado
RN-030 tiendaId es obligatorio y se valida contra las tiendas del cliente. Si no pertenece al cliente → 403 TIENDA_NO_PERMITIDA. TiendaProveedor nunca se acepta del cliente Decisión Iker Confirmada
RN-031 Una tienda puede pertenecer a varios clientes API; el permiso, los productos y la lista de transportadoras se evalúan por cliente Decisión Iker Confirmada
RN-032 La sucursal remitente se resuelve en el servidor con la misma regla de hoy, nunca desde el body: si la guía tiene proveedor, se toma la Sucursal de la tienda proveedora; si no, la Sucursal de la tienda. Si queda vacía (o N/A) se usa la sucursal genérica. Solo Inter la usa (CodigoConvenioRemitente / IdSucursal) CR/Function.cs:114-121; CR/.../CargaInterUseCase.cs:103,123; decisión Iker Confirmada
RN-033 Origen del paquete (decisión de Iker, 2026-10-24, reemplaza la anterior): en Dropshipping el paquete sale del proveedor del producto; la dirección de la tienda dropshipper no importa. Si el proveedor no tiene bien configurados el DANE y la dirección, no se generan guías con sus productos (422 ORIGEN_NO_CONFIGURADO). Una tienda Propia despacha desde su propia dirección. DANE y dirección salen siempre de la misma tienda y no se mezclan. Sin default a Medellín. El integrador no envía origen Decisión Iker Confirmada
RN-034 Todos los proveedores deben tener su origen configurado (acción de Iker antes de salir a producción) Decisión Iker Confirmada
RN-035 Tienda Dropshipping: ≥ 1 producto obligatorio; todos del mismo proveedor (si no → error); cada producto debe existir y estar permitido para la tienda y para el cliente (públicos o privados asignados). TiendaProveedor y la sucursal se derivan del producto en el servidor. Replica el front (Modal:1014-1058, 1525-1650) Decisión Iker; Modal Confirmada
RN-036 Tienda Propia: los productos son opcionales; si vienen, deben existir y ser permitidos (el front lo valida también para tiendas propias, Modal:443-449) Decisión Iker; Modal Confirmada
RN-037 productos es un arreglo [{ idProducto, cantidad }] con cantidad entero > 0, máximo 18 líneas (hoy ID STOCK n/CANTIDAD STOCK n: 12 en la creación individual y 18 en la masiva, CR/.../CargaInterUseCase.cs:191). Si hay ID debe haber cantidad y viceversa (Modal:1525-1540). El servidor calcula Cantidad Total Productos Decisión Iker; Modal Confirmada
RN-038 La tienda se resuelve por id, no por nombre. Hoy la sucursal del proveedor se busca por NombreTienda en minúsculas (CR/Function.cs:116), lo que falla si hay nombres repetidos CR/Function.cs:114-121 Confirmada
RN-039 Tras crear la guía, la API avisa al inventario con POST /actualizaInventarioLotes { Guias: [numero] }, como hoy lo hace el front en la creación manual. Si el aviso falla, no se pierde: se reintenta desde la cola (RN-065) Modal:1343-1348; ADR-003 Confirmada

4. Ciudades, tipo de entrega, capacidades por transportadora

Id Regla Fuente Estado
RN-050 destinatario.ciudad es código DANE de 8 dígitos (ej. 05001000). Un DANE de 5 dígitos se normaliza a 8 (completa con 000, como ya hace Envia, CargaEnviaUseCase.cs:187-190) Decisión Iker Confirmada
RN-051 La API valida la cobertura antes de llamar a la transportadora. Ciudad sin cobertura → 422 CIUDAD_SIN_COBERTURA. Catálogo de cobertura según transportadora: CiudadesInter (Inter, Envia, D2E), CiudadesServientrega, CiudadesTCC (solo Estado = ACTIVA, CargaTccUseCase.cs:86-92). Hoy Inter no valida que la ciudad exista (CR/.../CargaInterUseCase.cs:94) CR/Function.cs:69-78; decisión Iker Confirmada
RN-052 La API expone un catálogo de ciudades con cobertura por transportadora. El nombre de ciudad y el departamento que se guardan en PedidosInter (Ciudad, Departamento) salen del catálogo, no del cliente Decisión Iker; CR/.../CargaInterUseCase.cs:249 Confirmada
RN-053 tipoEntrega: 1 = entrega en dirección (default), 2 = reclame en oficina. Hoy solo Interrapidísimo ofrece reclame en oficina. Con otra transportadora + 2 → error Decisión Iker; CR/.../CargaInterUseCase.cs:110-116 Confirmada
RN-054 Existe una matriz de capacidades por transportadora en la colección de reglas (RN-004): tipos de entrega soportados, anulación, límites de peso/dimensiones, largos de texto, valor declarado mínimo. Cuando se implemente otra transportadora con una capacidad nueva (ej. reclame en oficina) basta activarla en la matriz, sin cambiar el contrato Decisión Iker Confirmada
RN-055 Por transportadora se mantienen las reglas propias que hoy viven en cada Carga*UseCase (ej. TCC: paquetería si peso > 5 kg y liquidación obligatoria antes del despacho con fail-fast, CargaTccUseCase.cs:97,208-229). La documentación detallada de cada una se agrega al integrar la transportadora (F3) CargaTccUseCase.cs Confirmada

5. Errores de transportadora

Id Regla Fuente Estado
RN-060 Los errores usan ProblemDetails (RFC 9457) con codigo estable y traceId; nunca stack ni mensaje interno. Catálogo de códigos en endpoints.md endpoints.md Confirmada
RN-061 Si la transportadora rechaza la guía → 422 TRANSPORTADORA_RECHAZO con transportadora, código y mensaje originales y un mensaje normalizado en español. Hoy el error vuelve como texto "Error {mensaje}" dentro de Resultado[i] con HTTP 200 y el front debe detectar startsWith('ERROR') (Modal:1337-1338). La API no usa ese formato endpoints.md; Modal:1337-1356 Confirmada
RN-062 Catálogo de mensajes normalizados: mapear los errores frecuentes de Inter a un código y un texto accionable para el integrador Recomendación Pendiente (RN-P-08)
RN-063 Transportadora caída o circuito abierto → 503 TRANSPORTADORA_NO_DISPONIBLE. Timeout o 5xx ambiguo tras enviar el POST → solicitud INCIERTA: nunca se reintenta a ciegas el POST de creación; solo se reintenta si el error ocurrió antes de enviar. Un reconciliador la resuelve y no se crea otra guía para esa solicitud hasta entonces ADR-003 Confirmada
RN-064 Compatibilidad con los destinos actuales: una guía rechazada deja en CargaPedido Estado = "Rechazado" y el mensaje en ERROR, como hoy (CR/.../CargaInterUseCase.cs:264-270). Estado de la solicitud en la API: FALLIDA CR/.../CargaInterUseCase.cs:264-270; ADR-003 Confirmada
RN-065 Los pasos posteriores a la creación (insert en PedidosInter, etiqueta, inventario) son idempotentes por número de guía; si fallan, la solicitud queda marcada y se reintenta desde la cola. No se tragan los errores como hoy (CR/.../CargaInterUseCase.cs:257-260), para no dejar pedidos huérfanos ADR-003 Confirmada
RN-066 Decisión 2026-10-24: POST /v1/guias espera al worker hasta ESPERA_RESPUESTA_SEGUNDOS (20 por defecto, tope 25 porque el API Gateway corta a los 29 s). Si la guía ya está creada responde 201 con el numeroGuia; si la transportadora la rechazó, 422 TRANSPORTADORA_RECHAZO con el motivo; si el worker no terminó, 202 y el integrador consulta con GET /v1/solicitudes/{id}, que está disponible en todo momento Decisión Iker Confirmada
RN-067 Decisión 2026-10-24: una solicitud FALLIDA (rechazada por la transportadora o por falta de cupo) libera su Idempotency-Key: la misma clave crea una guía nueva, aunque quede un registro de más en la base (la fallida se guarda como clave~id). Así no hay lógica de reintentos sobre la misma solicitud. Una guía CREADA o en curso sigue siendo idempotente Decisión Iker; ADR-003 Confirmada
RN-068 Decisión 2026-10-24: toda guía creada por la API sin cupo se guarda (ApiSolicitudesGuia en FALLIDA y CargaPedido en Rechazado) y el campo ERROR dice que se rechazó porque la cuenta no tenía cupo disponible Decisión Iker; RN-064 Confirmada

6. Anulación

POST /v1/guias/{numero}/anulacion (scope guias:anular).

Id Regla Fuente Estado
RN-070 La anulación solo marca la guía como Anulada internamente, igual que ApiLambdaAnularGuia hoy (AN/.../AnularGuiaUseCase.cs:64-67). No llama a la transportadora. Riesgo conocido: la guía sigue viva en la transportadora (ver R-01) Decisión Iker Confirmada
RN-071 La matriz de capacidades (RN-054) incluye anulacionExterna (false para todas en v1). Si más adelante una transportadora la soporta, se activa en la matriz Decisión Iker Confirmada
RN-072 Decisión 2026-10-24: los estados anulables son una lista por transportadora, configurable en la base: «Creado» (Interrapidísimo), «generada en…» (Envía), «en alistamiento del cliente» (Servientrega). El MVP es solo Inter, así que solo «Creado». El front de anulación cambia a Anulada con motivo y avisa a inventario en lotes de 1400, y el backend se alinea con eso. Texto anterior: Solo se puede anular en estados iniciales, una lista configurable. El backend de hoy exige Estado == "Creado" (AN/.../AnularGuiaUseCase.cs:52); el front también admite "generada en…" y "en alistamiento del cliente" (anular-guias.component.ts:267, citado en cupo.md). Una guía despachada no se anula Decisión Iker; cupo.md RC-024 Confirmada (lista inicial: ver RN-P-05)
RN-073 Sin plazo en horas: el estado ya limita la ventana Decisión Iker Confirmada
RN-074 El cliente solo puede anular guías creadas por él mediante la API (ApiSolicitudesGuia), no cualquier guía de la tienda (ej. creadas por Angular o carga masiva) Decisión Iker Confirmada
RN-075 Anular una guía ya anulada es idempotente: responde 200 con el estado actual (hoy AN responde error "ya se encuentra anulado", AnularGuiaUseCase.cs:40-49) Decisión Iker Confirmada
RN-076 La anulación es gratis y libera la reserva de cupo por el monto vigente cupo.md RC-024 Confirmada
RN-077 Efecto en inventario: se marca Anulada en PedidosInter y se avisa a /actualizaInventarioLotes { Guias: [numero] }. El reconciliador de ApiLambdaInventario ya reconoce Estado = Anulada y registra el movimiento Anulacion, que devuelve el stock (CalculadoraResumen.cs, ClasificadorEstado.cs:26) ApiLambdaInventario; propuesta Pendiente (RN-P-09)

7. Lotes

POST /v1/lotes y GET /v1/lotes/{id}. Pensado para carga masiva.

Id Regla Fuente Estado
RN-080 Máximo 50 guías por lote, configurable en BD por cliente (ApiClientes.TopeLote; sin el campo, 50). Pasarse es 422 LOTE_DEMASIADO_GRANDE y no se procesa ninguna Decisión Iker Implementada (2026-10-25)
RN-081 Lote parcial, no "todo o nada": se crean las guías válidas y las inválidas vuelven rechazadas en la misma respuesta. Una guía mala no tumba las otras 99. Reemplaza el borrador "valida todo antes" de endpoints.md Decisión Iker Confirmada
RN-082 Respuesta 202: loteId y, por guía, { indice, referencia, estado (ACEPTADA \| RECHAZADA), rechazoId, codigo, campo, mensaje } Decisión Iker Confirmada
RN-083 rechazoId es un identificador único y no repetible que genera la API por cada rechazo, para que el integrador y soporte lo citen Decisión Iker Confirmada
RN-084 Una guía rechazada en la validación (campo inválido, ciudad sin cobertura, producto o tienda no permitidos) no consume cupo, no crea registros ni consume la clave. Excepción posterior (2026-10-24, RN-068): la guía rechazada por falta de cupo SÍ queda registrada (FALLIDA con el motivo en ERROR); en un lote vuelve RECHAZADA y trae su solicitudId Decisión Iker Confirmada, con la excepción
RN-085 Reuso de referencia: libre si la guía fue RECHAZADA o FALLIDA; bloqueada si está CREADA (devuelve el resultado guardado) o INCIERTA (409 hasta que el reconciliador la resuelva) Decisión Iker; ADR-003 Confirmada
RN-086 Aceptado el lote, cada guía es independiente: una rechazada por la transportadora queda FALLIDA, libera su cupo y no afecta a las demás. Un mensaje SQS por guía (idempotente por id de solicitud) ADR-003; ApiPublicaGuias.md Confirmada
RN-087 Cupo en un lote: se evalúa guía a guía en el orden del lote; las que ya no caben se rechazan con CUPO_INSUFICIENTE y las anteriores siguen aceptadas Recomendación; definir con el chat de cupo Pendiente (RN-P-10)
RN-088 GET /v1/lotes/{id} devuelve el progreso y el estado final por guía (CREADA, FALLIDA, INCIERTA) con su número de guía endpoints.md Implementada (2026-10-25)
RN-089 Decisión 2026-10-24: el lote se identifica con un identificador único generado por la API (un ObjectId, el _id del documento del lote en ApiLotesGuia), sin números negativos ni contador. Cada guía del lote lo lleva en el campo LoteApi de CargaPedido y PedidosInter. CargaPedido.IdCarga se queda en "-1" (como las guías individuales): Angular calcula la siguiente carga como Math.max(...IdCarga) + 1 en importacion-pedidos.component.ts, y un IdCarga no numérico daría NaN en la próxima carga masiva y dejaría la carga sin número para modal-generar-guias y exportacion-pedidos Decisión Iker; verificado en el front Implementada (2026-10-25)
RN-090 Cada guía de un lote lleva su propia idempotencyKey (RN-010); el cuerpo de la guía es el mismo que el de POST /v1/guias, sin la clave. Una clave repetida dentro del lote rechaza la segunda (IDEMPOTENCY_REPETIDA_EN_LOTE); reenviar el lote devuelve las mismas solicitudes; una clave con otro body es IDEMPOTENCY_CONFLICTO. Un fallo inesperado deja esa guía NO_PROCESADA y se reenvía el lote Decisión Iker; ADR-003 Implementada (2026-10-25)

8. Clientes API

Id Regla Fuente Estado
RN-090 Alta, edición, bloqueo/desbloqueo, rotación de secreto y permisos de clientes por /admin/v1/clientes-api con el pool interno. Gerencia y Admin pueden todo, con motivo obligatorio en cada cambio. Los cupos siguen la regla de cupo.md Decisión Iker; endpoints.md Confirmada
RN-091 Todo cambio de gerencia o administradores queda en ApiAuditoria con antes, después, quién, cuándo y motivo ApiPublicaGuias.md; decisión Iker Confirmada
RN-092 Cliente bloqueado o suspendido → 403 CLIENTE_BLOQUEADO. El bloqueo cubre el perfil y la API key endpoints.md Confirmada
RN-093 Permisos por cliente: tiendas, transportadoras, productos e IPs. Siempre salen del perfil en servidor, nunca del token ni del body ApiPublicaGuias.md Confirmada
RN-094 Productos: el cliente hereda lo que la tienda puede usar hoy (públicos + privados asignados). El administrador puede definir una lista explícita opcional que restringe a esos productos. Una tienda en varios clientes puede tener listas distintas por cliente Decisión Iker Confirmada
RN-095 IP: lista de IPs permitidas opcional por cliente (403 IP_NO_PERMITIDA); el WAF mantiene además el bloqueo global y el límite por IP ApiPublicaGuias.md; endpoints.md Confirmada
RN-096 Las tiendas propias de LogiGho usan la misma API (y el MCP) como clientes API normales, con datosAdicionales (RN-024) Decisión Iker Confirmada
RN-097 Qué pasa con las guías ya encoladas cuando un cliente se bloquea: ¿se terminan, se cancelan antes de llamar a la transportadora? Recomendación: no llamar a la transportadora si el cliente quedó bloqueado antes de CREANDO Pendiente (RN-P-11)

9. Bases internacionales

La operación en otros países queda fuera de v1, pero el código y los datos no queman Colombia ni el peso colombiano.

Id Regla Fuente Estado
RN-100 El país y la moneda los define la tienda (v1: CO / COP); el request no los envía. La guía guarda codigoPais (ISO 3166) y moneda (ISO 4217) y la respuesta los devuelve. Valor declarado, flete y cupo siempre en la moneda de la tienda, sin conversión Decisión Iker Confirmada
RN-101 Las reglas que cambian por país (formato de ciudad, formato de teléfono, tipos de documento) viven en un catálogo por país en BD. v1 solo tiene las de Colombia: ciudad DANE8, teléfono 10 dígitos, documentos CC/CE/NIT/PAS/TI. Otro país = agregar un registro (regex + catálogo de ciudades), sin cambiar código Decisión Iker Confirmada
RN-102 La ciudad se guarda como { pais, sistema, codigo } (ej. { "CO", "DANE", "05001000" }) Decisión Iker Confirmada
RN-103 Zona horaria: hoy las fechas se escriben restando 5 horas a UTC (CR/.../CargaInterUseCase.cs:216-218). Debe pasar a ser una propiedad del país de la tienda Recomendación Pendiente (RN-P-12)

10. Pendientes y riesgos

Pendientes de datos o decisión

Id Pendiente Responsable
RN-P-01 Resuelto 2026-10-24: mínimo de 45 000 COP para todas las transportadoras, con o sin recaudo (RN-012). Se vuelve a abrir solo si aparecen problemas Iker
RN-P-02 Límites de peso y dimensiones, y largos máximos de texto de Inter y de las demás transportadoras (RN-015, RN-019) Iker
RN-P-03 Nombres, tipo y largo de los 2–3 campos de datosAdicionales de las tiendas propias (RN-024) Iker
RN-P-04 Resuelto 2026-10-24: en Dropshipping el origen es el del proveedor (RN-033) Iker
RN-P-05 Resuelto 2026-10-24: estados anulables por transportadora, configurables (RN-072); MVP solo «Creado» Iker
RN-P-06 Mapeo de tipoDocumento a cada transportadora (Inter hoy solo manda CC) (RN-017) Desarrollo, al integrar cada transportadora
RN-P-07 Valores fijos del servidor: ASESOR, CODIGO OFICINA, CODIGO REGIONAL, SEGURO, TELEFONO REMITENTE (hoy 3112222222 por defecto en TCC) y FORMA DE PAGO (RN-023) Iker / Desarrollo
RN-P-08 Catálogo de mensajes normalizados de errores de Inter (RN-062) Desarrollo
RN-P-09 Confirmar el efecto de la anulación en inventario (RN-077) Iker
RN-P-10 Comportamiento del cupo dentro de un lote (RN-087) Chat de cupo
RN-P-11 Guías encoladas cuando se bloquea un cliente (RN-097) Iker
RN-P-12 Zona horaria por país (RN-103) Desarrollo
RN-P-13 correo, diceContener y observaciones (RN-021, RN-022) Iker
RN-P-14 referencia: Iker dijo «sí» a tener referencias en las guías. Falta saber si es obligatoria en lotes y opcional en la guía unitaria, y si va además de Idempotency-Key. La clave de idempotencia por guía es Idempotency-Key en POST /v1/guias y en cada guía de un lote (decisión 2026-10-24) Iker
RN-P-15 Migrar estas especificaciones a la base de conocimiento cuando exista Iker / Claude (recordar)
RN-P-16 Productos privados y Product HUB. Hoy el front deja usar un producto privado de OTRA tienda si hay una autorización vigente en ProductHubAutorizaciones. Iker dijo (2026-10-24) que un producto privado del proveedor no debe poder usarse. La API lo rechaza y deja las autorizaciones de Product HUB apagadas hasta que Iker confirme si deben aplicar. (ProductHubAutorizaciones no existe en PreProd.) Iker

Riesgos aceptados

Id Riesgo Mitigación
R-01 La anulación solo marca internamente (RN-070): la guía sigue viva en la transportadora y podría despacharse y cobrarse como una guía real aunque en LogiGho figure Anulada y libere cupo Decisión consciente de Iker. Vigilar con la conciliación de novedades de la transportadora. La matriz (RN-071) permite activar la anulación externa por transportadora sin cambiar el contrato

Discrepancias con otros documentos

Documento Dice Esta especificación
endpoints.md línea 36 POST /v1/lotes "valida todo antes" Lote parcial con rechazoId (RN-081 a RN-084). Actualizar endpoints.md
endpoints.md línea 34 anulacion "anula la guía en la transportadora y libera cupo" Solo marca interna (RN-070). Actualizar endpoints.md
ApiPublicaGuias.md línea 116 reglas-negocio.md "en construcción" Este documento

Referencias