From 82f9fa5d25955452178bbfa20abc1555983071d6 Mon Sep 17 00:00:00 2001 From: Johann Date: Thu, 20 Aug 2026 23:41:14 -0600 Subject: [PATCH] =?UTF-8?q?Sondeo=20de=20FAC-106=20y=20diagn=C3=B3stico=20?= =?UTF-8?q?del=20500:=20el=20payload=20ten=C3=ADa=20tres=20defectos=20de?= =?UTF-8?q?=20escala=20y=20sem=C3=A1ntica?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Preparación para la sesión del 21-ago. Todo solo lectura + dry-run. FAC-106 (creado por Pedro el 20-ago, asignado a Araceli) trae el formulario nuevo con request type "Cotización Bind". Servicio/Producto, Cantidad, IVA y Cliente ya son campos estructurados: el hueco de conceptos/partidas que bloqueaba B7 queda resuelto en el origen. Diagnóstico del 500 del 12-ago, leyendo 4 cotizaciones reales de BIND: - VATRate va como fracción (0.16), no como 16 - el VAT de partida es un MONTO, no una tasa (Price*Qty*0.16) - cada cotización usa un PriceListID distinto y ninguno coincide con el único que devuelve GET /api/PriceLists; conviene omitirlo Dry-run corregido ejecutado (operación #18); el body queda en el informe. Tres preguntas nuevas para la sesión: Empresa origen tiene 3 valores y hay un solo token; el combo IVA no ofrece 0% aunque hay clientes de exportación; y "Servicio de Enlace" existe 5 veces en BIND con unidad, unidad SAT y ChargeVAT distintos, sin mapeo definido. Bind:Mode está en Write fuera de sesión — hay que regresarlo a ReadOnly. Co-Authored-By: Claude Opus 5 (1M context) --- bitacora/PENDIENTES.md | 10 +- .../Sondeo-FAC-106-y-payload-2026-08-20.md | 108 ++++++++++++++++++ 2 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 planeacion/Sondeo-FAC-106-y-payload-2026-08-20.md diff --git a/bitacora/PENDIENTES.md b/bitacora/PENDIENTES.md index 25b6599..97dd6dd 100644 --- a/bitacora/PENDIENTES.md +++ b/bitacora/PENDIENTES.md @@ -6,8 +6,14 @@ _Última actualización: **2026-08-20, noche.** Cruce completo del buzón contra ## 🔥🔥 SESIÓN VIERNES 21-AGO, 7:00 AM — Noé, Araceli y Pedro -- [ ] 🔥 **Johann — inspeccionar `FAC-106` por API esta noche.** Pedro avisó que **la licencia bloquea la UI** y ofreció pantallazo; no hace falta: el **token PAF corre sobre la cuenta de Pedro**, que sí tiene licencia, y así se sondeó el sitio el 6-ago y el 11-ago. Lo que hay que sacar: **qué campos nuevos trae el formulario modificado**, si aparece algo que sirva de **conceptos/partidas**, y si `Monto sin IVA` sigue siendo `customfield_11556`. **Sin esto se llega a ciegas.** Ver [REGISTRO #67](REGISTRO.md). -- [ ] 🔥🔴 **Johann — resolver el ERROR 500 del POST de cotización antes de mañana.** El 12-ago la primera escritura real contra BIND **falló** ([REGISTRO #65](REGISTRO.md) §6): faltaban campos que el portal manda en ceros y, sobre todo, **la lista de precios**. Definición de Araceli: *"nosotros realmente no tenemos una lista de precios… ese lo podríamos agarrar del **monto sin IVA** del [ticket]. Ese sería nuestra lista de precios"* — y el precio se captura **directo, como campo abierto**, sin cantidad × tarifa. **Ajustar el shape del POST a eso y probar en local antes de la sesión.** Es el segundo intento de emitir la primera cotización real. +- [x] ~~🔥 **Johann — inspeccionar `FAC-106` por API**~~ → **HECHO (20-ago, noche).** Informe completo: [`../planeacion/Sondeo-FAC-106-y-payload-2026-08-20.md`](../planeacion/Sondeo-FAC-106-y-payload-2026-08-20.md). ⭐ **El formulario nuevo resuelve conceptos/partidas**: `Servicio/Producto` (combo, 17 categorías), `Cantidad`, `IVA` y `Cliente` (combo, 17 clientes de BIND) ya son campos estructurados; request type nuevo **`Cotización Bind`**. Config corregida: el campo de cliente pasó de `customfield_10202` a **`customfield_11598`** — era la causa de que el 12-ago *"el cliente no se detectó"*. +- [x] ~~🔥🔴 **Resolver el ERROR 500 del POST de cotización**~~ → **DIAGNOSTICADO (20-ago)** leyendo 4 cotizaciones reales de BIND. Tres defectos en el payload: **(1)** `VATRate` va como **fracción** (`0.16`), no como `16`; **(2)** el `VAT` de partida es **monto**, no tasa (`Price × Qty × 0.16` — verificado en 3 de 4); **(3)** cada cotización real usa un `PriceListID` distinto y **ninguno coincide** con el único que devuelve `GET /api/PriceLists` → **omitirlo**. Dry-run corregido ejecutado (operación #18); body listo en el informe. Falta la confirmación real, que es la prueba de mañana. +- [ ] 🔴 **PREGUNTAR MAÑANA — `Empresa origen` tiene 3 valores: Balam, RegioTurk y Helmstone.** ¿La cotización se emite siempre en la misma cuenta de BIND o hay una por empresa? Hay **un solo token**. Si son cuentas distintas, el alcance cambia. +- [ ] 🔴 **PREGUNTAR MAÑANA — el combo `IVA` de Jira solo ofrece `16%`.** No hay **0%**, y en el combo de clientes hay tres de exportación (ACUNTIA S.A.U., VictTec LLC, IAMCFORWARDER). El Discovery registró 16%/0% y en BIND hay cotizaciones reales con `VAT = 0`. **Falta la opción.** +- [ ] 🔴 **PREGUNTAR MAÑANA — "Servicio de Enlace" existe 5 veces en BIND**, con unidad, unidad SAT y `ChargeVAT` **distintos entre sí** (una cobra IVA, cuatro no). El combo de Jira manda una sola etiqueta: **la correspondencia etiqueta → ítem de BIND no está definida.** Se depuró el combo de Jira; **falta depurar BIND y fijar el mapeo**. +- [ ] ⚠️ **Fijar por escrito que manda el combo `Cliente` (11598)**: sobrevive `Nombre del cliente` (`11596`, texto libre) en el mismo formulario. +- [ ] 🔒🔴 **Regresar `Bind:Mode` a `ReadOnly`.** Está en **Write** ahora mismo, fuera de la sesión acompañada — contra lo prometido a Noé ([REGISTRO #31a](REGISTRO.md)). `dotnet user-secrets set "Bind:Mode" "ReadOnly" --project src/Balam.Api`. +- [ ] 🔧 **Cablear los 4 campos nuevos** (`11599` Servicio/Producto, `11600` Cantidad, `11601` IVA, `11597` Fecha de vencimiento) en `JiraFieldsOptions` y en el DTO de detalle, para que el wizard prellene la partida sola. No bloquea la prueba manual. - [ ] 🔥 **Johann — preparar el caso de escritura sobre `FAC-106`** (comprometido con Pedro el 19-ago). La capa ya existe y corre contra cualquier ticket FAC ([#64](REGISTRO.md)); ajustar el mapeo a los campos del **nuevo formulario** (Empresa origen · Summary · Descripción *(ahora combo)* · Nombre del cliente *(combo)* · Tipo de moneda · Monto sin IVA · Fecha de vencimiento). ⚠️ El 12-ago **el cliente no se detectó** porque el mapeo salía del `summary`/`description`: verificar que ahora venga de campo estructurado. - [ ] 🔥 **Johann — en la sesión: encender `Bind:Mode=Write` solo para emitir y regresarlo a ReadOnly antes de cerrar.** - [ ] ⚠️🔥 **Johann — anunciar al abrir la sesión el destino de la cotización real** (cancelarla al terminar vs. cliente de prueba) y que la prefactura pertenece a una sesión posterior. **Pendiente arrastrado del 12-ago; sigue sin resolverse.** diff --git a/planeacion/Sondeo-FAC-106-y-payload-2026-08-20.md b/planeacion/Sondeo-FAC-106-y-payload-2026-08-20.md new file mode 100644 index 0000000..ce70476 --- /dev/null +++ b/planeacion/Sondeo-FAC-106-y-payload-2026-08-20.md @@ -0,0 +1,108 @@ +# Sondeo de `FAC-106` y payload de cotización — 20-ago-2026, noche + +Preparación para la sesión del **viernes 21-ago, 7:00 am**. Todo lo de aquí es **solo lectura**: sondeo del ticket por API de Jira, lectura de catálogos de BIND y **dry-run** del endpoint de emisión (ninguna escritura). Ver [REGISTRO #65](../bitacora/REGISTRO.md) (la sesión del 12-ago que terminó en 500) y [#67](../bitacora/REGISTRO.md). + +--- + +## 1 · `FAC-106` — el formulario nuevo existe y es mucho mejor de lo esperado + +Creado por **Pedro** el 20-ago 4:12 pm, asignado a **Araceli**. Request type nuevo: **`Cotización Bind`** (id 1196, portal 35). Estatus `Open` (⚠️ **no** `En proceso de facturación`: mañana el disparo es manual, como estaba previsto). + +| Campo | ID | Tipo | Valor en FAC-106 | +|---|---|---|---| +| Empresa origen | `customfield_11423` | select | **Balam** | +| Cliente | `customfield_11598` | **select** | **CEMEX** | +| Servicio/Producto | `customfield_11599` | **select** | **Servicio de Enlace** | +| Cantidad | `customfield_11600` | number | **1.0** | +| Monto sin IVA | `customfield_11556` | number | **1234.0** | +| IVA | `customfield_11601` | select | **16%** | +| Tipo de Moneda | `customfield_10053` | select | **MXN** | +| Fecha de vencimiento | `customfield_11597` | date | **2026-08-27** | + +⭐ **El hueco de conceptos/partidas quedó resuelto.** `Servicio/Producto` + `Cantidad` + `IVA` son campos estructurados: ya hay con qué armar una partida sin parsear texto ni adjuntos. + +⭐ **`Cliente` dejó de ser ADF y ahora es combo** con **17 opciones** que corresponden a los clientes de BIND: ACUNTIA S.A.U. · ATC CONSOLIDADOS · BANCA AFIRME · CEMEX · DEACERO · FRISA FORJADOS · (persona física) · HELMSTONE · IAMCFORWARDER · PLAN CREDI · Público en General · REGIOTURK · SERVICIOS COMPARTIDOS TSM · SERVICIOS LOGISTICOS DYLO · TRANSPORTES LOGISTICOS ESPECIALIZADOS · TRASLADOS Y LOGISTICA ESPECIALIZADA · VictTec LLC. + +⭐ **Las 17 categorías de servicio de Pedro, confirmadas** en `Servicio/Producto`: Consultoría y Administración Corporativa · Servicios Profesionales Generales · Gestión de Proyectos Senior / PMO · Gestión de Mesa de Servicio (SDM) · Soporte Especializado L1 · Soporte Especializado L2 · Gestión de Incidentes · Gestión de Cambios · Gestión de Capacidad · Mesa de Ayuda / Service Desk · Desarrollo de Software · Reclutamiento (Headhunting) · Servicio de Enlace · Horas Extraordinarias · Viáticos · Licencias y Software · Liquidaciones y Finiquitos. + +### Pendientes que deja el formulario + +- 🔴 **`Empresa origen` tiene 3 valores: Balam, RegioTurk y Helmstone.** ¿La cotización se emite siempre en la misma cuenta de BIND, o hay una por empresa? El token actual es uno solo. **Preguntarlo mañana.** +- 🔴 **`IVA` solo ofrece `16%`.** No hay `0%` — y hay clientes de exportación en el combo (ACUNTIA S.A.U., VictTec LLC, IAMCFORWARDER). El Discovery registró **IVA 16%/0%**. Además, en BIND existe al menos una cotización real con `VAT = 0` pese a `VATRate = 0.16`. **Falta la opción 0%.** +- ⚠️ **Sobrevive `Nombre del cliente` (`customfield_11596`, texto libre)** además del combo `11598`. Dos campos de cliente en el mismo sitio: hay que fijar por escrito que **manda el combo**. +- ⚠️ **`customfield_10202`, el campo de cliente que la plataforma leía, ya no aplica.** Era la causa de que el 12-ago *"el cliente no se detectó"*. **Corregido** en `appsettings.Development.json` → `customfield_11598`. + +--- + +## 2 · El catálogo de BIND está peor de lo que se vio en la sesión + +`GET /api/Services` devuelve **67 servicios**; `GET /api/Products`, **3 productos**. Buscando el que trae el ticket: + +**"SERVICIO DE ENLACE" existe 5 veces**, con IDs distintos y **atributos fiscales que no coinciden entre sí**: + +| Code | Unit | SATUnit | ChargeVAT | +|---|---|---|---| +| `81111500` | *(vacío)* | 3984 | **true** | +| `Código - 00000` | E48 | 4376 | false | +| `Código - 00000` | E48 | 4376 | false | +| `Código - 00000` | Servicio | 4376 | false | +| `027` | E48 | 3984 | false | + +> 🔴 **Riesgo directo para mañana:** el combo de Jira manda **una etiqueta**, "Servicio de Enlace", y en BIND hay **cinco filas** que difieren en unidad, unidad SAT e incluso en si cobran IVA. **La correspondencia etiqueta → ítem de BIND es ambigua y nadie la ha definido.** Es la segunda mitad de la depuración que Araceli pidió el 12-ago: se depuró el combo de Jira, **falta depurar BIND y fijar el mapeo**. + +--- + +## 3 · Los tres errores que explican el 500 del 12-ago + +Verificado leyendo **4 cotizaciones reales** de BIND (folios 1001, 1005, 1012, 1021): + +1. 🔴 **`VATRate` va como fracción, no como porcentaje.** Todas las cotizaciones reales traen **`VATRate = 0.16`**. Mandar `16` es un factor de 100 de diferencia. +2. 🔴 **`VAT` de partida es un MONTO, no una tasa.** Comprobado en 3 de 4: `Price × Qty × 0.16 = VAT` (p. ej. 32,422.04 → 5,187.5264). El endpoint **pasa el valor tal cual**, así que quien llame tiene que calcularlo. Para FAC-106: 1234 × 1 × 0.16 = **197.44**. +3. 🟠 **`PriceListID`: cada cotización real usa una lista distinta** (`041d4514…`, `0c4bb05e…`, `0dfbe083…`, `1087dac9…`) y **ninguna coincide** con la única que devuelve `GET /api/PriceLists` (`03e4bb2d…`, "A"). Mandar la lista equivocada es candidato serio al 500. **Recomendación: omitirlo** y dejar que BIND aplique su default — el cliente ya omite los nulos. + +Además, sin confirmar: + +- ⚠️ **`ID` de partida.** El read model distingue `ID` (renglón) de `ProductID` (ítem del catálogo); el write model **solo tiene `ID`**. Mandar el GUID del servicio en `ID` puede ser justo lo que BIND rechaza. El body de abajo **omite `ID`** y manda la partida como texto con `Title`/`Unit` — que además es como Araceli captura. +- ⚠️ `Type` y `SelectedUnit` siguen sin documentar; van omitidos. + +--- + +## 4 · Body listo para mañana (dry-run ejecutado, operación #18) + +IDs resueltos contra BIND en vivo: **MXN** `b7e2c065-bd52-40ca-b508-3accdd538860` · **Matriz** `65ee189a-a163-4f23-8466-87627a5ba776` (única ubicación) · **CEMEX** `6f17c5bd-e7a0-4152-9702-4a486c1b7c69` (RFC `CEM880726UZA`, 90 días de crédito). + +```json +{ + "LocationID": "65ee189a-a163-4f23-8466-87627a5ba776", + "CurrencyID": "b7e2c065-bd52-40ca-b508-3accdd538860", + "ExchangeRate": 1.0, + "Items": [ + { "Title": "SERVICIO DE ENLACE", "Unit": "E48", "Price": 1234.0, + "Qty": 1.0, "VAT": 197.44, "IEPS": 0, "IndexNumber": 1 } + ], + "ClientProspect": { + "isNew": false, + "Client": { "ClientId": "6f17c5bd-…", "ClientName": "CEMEX" } + }, + "VATRate": 0.16, + "Comments": "Generada desde el ticket FAC-106 (prueba acompañada)." +} +``` + +**Si BIND vuelve a rechazar**, el orden de ataque es: (1) agregar `PriceListID` con el de una cotización reciente del mismo cliente; (2) mandar el GUID del servicio en `ID`; (3) probar `Type`. El endpoint ya expone `ex.Body` de BIND en el 502, así que el diagnóstico se lee en pantalla — no se repite el 500 ciego del 12-ago. + +--- + +## 5 · ⚠️ Seguridad: `Bind:Mode` está en **Write** ahora mismo + +`GET /api/emision/estado` responde `{"modo":"Write"}` — el candado de ADR-001 está **abierto** fuera de la sesión acompañada, contra lo que se le prometió a Noé ([REGISTRO #31a](../bitacora/REGISTRO.md)). Una confirmación accidental escribiría en producción. **Regresarlo a `ReadOnly`** y encenderlo solo durante la sesión: + +```bash +dotnet user-secrets set "Bind:Mode" "ReadOnly" --project src/Balam.Api +``` + +--- + +## 6 · Lo que falta cablear (no bloquea la prueba manual) + +El dry-run de arriba se armó **a mano** con los datos de `FAC-106`. Para que la pantalla lo arme sola faltan cuatro campos en la configuración y en el DTO de detalle: `Servicio/Producto` (11599), `Cantidad` (11600), `IVA` (11601) y `Fecha de vencimiento` (11597). Con eso el wizard prellena la partida completa desde el ticket.