cbb29086cc
Consolida el disparador, los huecos de datos y el protocolo de prueba para continuar el desarrollo con decisiones trazables.
412 lines
33 KiB
Markdown
412 lines
33 KiB
Markdown
# Investigación de la API de Jira — qué probar exactamente
|
||
|
||
**Fecha:** 30-jul-2026 · **Actualizado:** 10-ago-2026
|
||
**Propósito:** lista cerrada de pruebas y preguntas para habilitar la integración **Jira → cotización BIND** (estimada en ~10 h, [REGISTRO #51](../bitacora/REGISTRO.md)). Documento de trabajo interno; sirve también como briefing para el agente/chat especializado en la API de Jira.
|
||
|
||
**Estado validado (30-jul):**
|
||
- Sitio: `https://balam-jsm-temp.atlassian.net`. El token regenerado de Pedro, usado con Basic auth y `pedro.ayala@balamtalentoestrategico.com`, respondió **200** a `GET /rest/api/3/myself`.
|
||
- Facturación es el proyecto JSM **`FAC`** (`projectId: 10034`, `serviceDeskId: 35`), de tipo `service_desk` y estilo `classic` (company-managed).
|
||
- La búsqueda de FAC devolvió **66 tickets**. La API vigente es `GET /rest/api/3/search/jql`, con paginación por `nextPageToken`; el endpoint clásico `/rest/api/3/search` responde **410 Gone**.
|
||
- Estatus confirmados: `Open`, `En proceso de facturación`, `En espera por colaborador`, `En validación nacional`, `En validación extranjera`, `Facturado` y `Cancelado`. No se observó un estatus llamado “Resuelto”.
|
||
- Límites de consumo ya aclarados por Pedro (sin tope mensual; 3 límites de velocidad; telemetría solo en headers `X-RateLimit-*`).
|
||
|
||
---
|
||
|
||
## ⭐ Decisiones de negocio recibidas (correo del 7-ago) y su verificación por API (10-ago)
|
||
|
||
Balam contestó las tres preguntas del 30-jul. Arturo respondió el **4-ago** (en verde sobre el correo de Noé), Noé lo reenvió el **7-ago**. Fuente: `RV_ Seguimiento_ medición de consumo API de Jira y accesos.eml`.
|
||
|
||
| Decisión de Balam | Quién / cuándo | Verificación por API (10-ago) |
|
||
|---|---|---|
|
||
| La cotización BIND **se genera al entrar a `En proceso de facturación`** | Arturo, 4-ago | ✅ Estatus y transición `Iniciar facturación` ya inventariados (Bloque 3) |
|
||
| **Todo se tramita como facturación normal**; el caso recurrente espera a que se explore el módulo de Proyectos de BIND | Arturo, 4-ago | ⚠️ El campo `Facturación recurrente` sigue siendo **obligatorio** y se está llenando (FAC-100: `Si`, periodo `12`) |
|
||
| Se observan **todos los request types** de la bandeja de facturación, no solo `Facturación adicional` | Arturo, 4-ago | 🔴 **10 de 69 tickets no tienen request type alguno** y ninguno trae campos de facturación (ver Bloque 1) |
|
||
| Monto y conceptos van **como campos de Jira**, no del adjunto; **omitir el campo de recurrencia** | Arturo, 4-ago | ⚠️ `Monto sin IVA` ya existe y funciona; **`conceptos` no existe como campo en todo el sitio** (ver Bloque 2) |
|
||
| Las pruebas de escritura son **prueba acompañada sobre un ticket**, no proyecto `FACTEST` | Noé, 7-ago | Se descarta el sandbox en la instancia de Balam → aplica el protocolo del Bloque 6 sin excepción |
|
||
|
||
**Lo que sigue abierto tras estas respuestas:** de dónde salen los **conceptos/partidas** de la cotización, qué hacer con los tickets sin campos estructurados, si nacional/extranjero cambia la cotización o solo el paquete de salida, **PUE vs PPD**, la fecha de la prueba acompañada y la migración a cuenta de servicio.
|
||
|
||
---
|
||
|
||
## Bloque 0 — Acceso autenticado ✅
|
||
|
||
El 401 del 29-jul quedó explicado por la combinación de token previo y datos de conexión incompletos. Pedro confirmó el correo, regeneró el token y compartió el dominio del sitio.
|
||
|
||
**Configuración que funcionó:**
|
||
```text
|
||
GET https://balam-jsm-temp.atlassian.net/rest/api/3/myself
|
||
Authorization: Basic base64(pedro.ayala@balamtalentoestrategico.com:<token>)
|
||
Accept: application/json
|
||
```
|
||
|
||
El resultado fue **HTTP 200**. Por tanto, para esta integración se usará la API directa del sitio con Basic auth; no hay evidencia de que se requiera una ruta `api.atlassian.com/ex/jira/{cloudId}`.
|
||
|
||
**Prueba canónica de auth (la primera que debe correrse siempre):**
|
||
```
|
||
GET /rest/api/3/myself
|
||
```
|
||
Interpretación de la respuesta:
|
||
- **200** → auth OK; además devuelve `accountId` (identidad con la que la plataforma va a escribir — dato de gobierno, ver Bloque 7).
|
||
- **401** → credencial inválida/inactiva o esquema mal armado.
|
||
- **403** → credencial VÁLIDA pero sin permiso → problema de permisos, no de token. Distinguir 401 de 403 es el diagnóstico más barato que existe.
|
||
|
||
> ⚠️ **Registrar siempre los headers de la respuesta 401 completos.** Ahí vive la pista (`WWW-Authenticate`, `X-Seraph-LoginReason`, `X-Failure-Category`).
|
||
|
||
---
|
||
|
||
## Bloque 1 — Topología: Jira Service Management confirmado ✅
|
||
|
||
FAC está confirmado como **Jira Service Management (JSM)**. Por ello la integración requiere dos familias de API:
|
||
|
||
| API | Para qué | Cuándo usarla |
|
||
|---|---|---|
|
||
| `/rest/api/3/...` | Issues genéricos: JQL, campos, transiciones, adjuntos, changelog | Lectura/sync, transiciones, trazabilidad |
|
||
| `/rest/servicedeskapi/...` | Requests de portal: request types, campos del formulario, aprobaciones, SLA, comentarios públicos vs internos | Crear tickets como los crea un humano; leer aprobaciones y SLA |
|
||
|
||
**Resultados:**
|
||
```
|
||
GET /rest/api/3/project/FAC
|
||
```
|
||
→ `projectTypeKey: service_desk`, `style: classic`, `id: 10034`.
|
||
|
||
```
|
||
GET /rest/servicedeskapi/servicedesk
|
||
```
|
||
→ FAC corresponde a `serviceDeskId: 35`.
|
||
|
||
Request types **publicados en el portal** (`GET /rest/servicedeskapi/servicedesk/35/requesttype`, `isLastPage: true`):
|
||
|
||
| requestTypeId | Nombre | Campos obligatorios |
|
||
|---:|---|---:|
|
||
| 84 | Bajas | 7 |
|
||
| 83 | Facturación adicional | 10 |
|
||
| 389 | Automatización | 1 (solo `summary`) |
|
||
| 12 | Facturación | 1 (solo `summary`) |
|
||
|
||
Contratos verificados el 10-ago con `/requesttype/{id}/field`:
|
||
|
||
| Request type | Hallazgo |
|
||
|---|---|
|
||
| **Bajas** (`84`) | Empresa origen, Summary, adjunto de Cálculo/VoBo de Finiquito, Nombre del Cliente, Nombre del Colaborador, Fecha de la Baja y Motivo de la Baja. |
|
||
| **Facturación adicional** (`83`) | Empresa origen, `MES / DESCRIPCIÓN / CLIENTE` (es el `summary`), Cliente Nuevo, Nombre del Cliente, adjunto de cotización/CSF, Tipo de Moneda, Días de Crédito, Facturación recurrente, Periodo de recurrencia y **`Monto sin IVA`**. Es el contrato más completo. ⚠️ **Cambió desde el 30-jul:** se agregó `Monto sin IVA` y desapareció `Periodo de Incidencias`. |
|
||
| **Automatización** (`389`) | Solo exige Summary. |
|
||
| **Facturación** (`12`) | Solo exige Summary. |
|
||
|
||
### 🔴 “Todos los request types” incluye tickets sin request type
|
||
|
||
La bandeja de FAC muestra en el filtro de la UI **6 de 6** opciones: las 4 de arriba más **`Empty`** y **`Emailed request`**. Ninguna de esas dos aparece en `servicedeskapi` porque no están publicadas en el portal. El conteo real sobre los **69 tickets** de FAC (10-ago):
|
||
|
||
| Request type | Tickets | c/Monto | c/Moneda | c/Cliente | c/Adjunto |
|
||
|---|---:|---:|---:|---:|---:|
|
||
| 83 — Facturación adicional | 48 | **2** | 48 | 48 | 48 |
|
||
| **(sin request type)** | **10** | 0 | 0 | 0 | 3 |
|
||
| 84 — Bajas | 6 | 0 | 0 | 6 | 6 |
|
||
| 389 — Automatización | 4 | 0 | 0 | 0 | 4 |
|
||
| 12 — Facturación | 1 | 0 | 0 | 0 | 1 |
|
||
|
||
Los **10 tickets sin request type** tienen `creator` y `reporter` = **`Automation for Jira`**: nacen de una regla de Automation desde otras bandejas (HH, SA, IN, RH), no del portal. Y **no son ruido**: `FAC-91` es uno de ellos, está vivo en `En validación nacional` y su summary es `[FACTURA COMPLETA - Staff Augmentation] Axians - Incident Manager — RH-36`. Es decir, **hay facturación real entrando por una vía que no tiene ni un solo campo estructurado** — los datos viajan codificados en el `summary` y en la `description` (ADF), más 2 adjuntos.
|
||
|
||
`Emailed request` hoy tiene 0 tickets, pero existe en la configuración: cualquier correo a la bandeja aterriza ahí, también sin campos.
|
||
|
||
**Implicación:** el acuerdo literal “todos los request types” significa que **~14% de los tickets no puede generar una cotización automática** con el diseño de campos estructurados. Hay dos salidas y conviene que Balam elija explícitamente: (a) acotar la automatización a los request types que sí traen campos y dejar los demás en tratamiento manual, o (b) que Automation for Jira propague los campos al crear el ticket en FAC. La opción (b) es trabajo del lado de Balam, no de la plataforma.
|
||
|
||
---
|
||
|
||
## Bloque 2 — Modelo de datos del ticket FAC (el mapeo) 🔴
|
||
|
||
Esto es lo que decide si la integración es de 10 h o de 25. **La pregunta de fondo: ¿los datos de facturación vienen en campos estructurados o en texto libre?** Si vienen en texto libre, hay que negociar campos nuevos con Pedro o meter parsing frágil.
|
||
|
||
**Lo que la plataforma necesita de cada ticket para armar una cotización en BIND:**
|
||
|
||
| Dato requerido | Por qué | Qué verificar |
|
||
|---|---|---|
|
||
| Cliente | Match contra `Clients` de BIND (por RFC o nombre normalizado) | ¿Campo custom? ¿Lista desplegable? ¿Texto libre? ¿Trae RFC? |
|
||
| Monto y moneda | Cotización BIND; la cartera **jamás mezcla monedas** | ¿Campo numérico? ¿Viene la moneda separada o embebida en el texto? |
|
||
| Nacional vs internacional | Determina PDF+XML (nacional) vs solo PDF (extranjero) | ¿Se deduce del cliente o hay campo/etiqueta? |
|
||
| Concepto / descripción | Línea de la cotización | Ver formato (ver ⚠️ ADF abajo) |
|
||
| Tipo de solicitud | adicional / recurrente / baja / headhunting / staff augmentation | ¿Request type, issue type, o campo? |
|
||
| Folio `FAC-nnn` | Trazabilidad ticket ↔ cotización ↔ factura (persistir en el modelo) | Confirmar formato y estabilidad (ver Bloque 5, ⚠️ moves) |
|
||
| Solicitante / área | Auditoría | `reporter` vs `requester` de JSM (no son lo mismo) |
|
||
| Adjuntos | Constancia fiscal, Excel de horas (CEMEX), estado de cuenta | Cómo se descargan y con qué auth |
|
||
|
||
**Resultados de lectura:**
|
||
```
|
||
GET /rest/api/3/issue/FAC-98?expand=names,renderedFields
|
||
```
|
||
→ caso real de tipo Bajas: cliente Axians, colaborador, fecha y motivo de baja en campos estructurados; una evidencia adjunta; sin descripción. Los valores de texto enriquecido regresan como ADF.
|
||
|
||
### Mapeo de campos confirmado (10-ago)
|
||
|
||
| Campo de Jira | `fieldId` | Tipo | Valores | → BIND |
|
||
|---|---|---|---|---|
|
||
| Empresa origen | `customfield_11423` | option | `Balam`, `RegioTurk`, `Helmstone` | Emisor (multi-empresa) |
|
||
| MES / DESCRIPCIÓN / CLIENTE | `summary` | string | texto libre | Referencia / parseo de respaldo |
|
||
| Cliente Nuevo | `customfield_10052` | option | `Si`, `No` | Decide si hay que dar de alta el cliente |
|
||
| Nombre del Cliente | `customfield_10202` | **ADF** (textarea) | texto enriquecido | Match contra `Clients` de BIND |
|
||
| Tipo de Moneda | `customfield_10053` | option | `MXN`, `USD`, `OTRO` | Moneda de la cotización |
|
||
| Días de Crédito | `customfield_10054` | option | `30`, `45`, `NA` | Condiciones de pago |
|
||
| Facturación recurrente | `customfield_10552` | option | `Si`, `No` | Fuera de alcance por ahora (Arturo, 4-ago) |
|
||
| Periodo de recurrencia | `customfield_10553` | string | texto | Fuera de alcance por ahora |
|
||
| **Monto sin IVA** | **`customfield_11556`** | **number/float** | — | **Total de la cotización** |
|
||
| Approvers | `customfield_10003` | array/user | — | Gobierno (ver Bloque 3) |
|
||
|
||
⚠️ **`Nombre del Cliente` es ADF, no string.** El match contra BIND tiene que extraer texto plano de un documento estructurado, no leer un campo de texto. Nada garantiza que el nombre escrito a mano coincida con la razón social en BIND; **el campo no trae RFC**, que sería la llave confiable.
|
||
|
||
### 🔴 Dos huecos que el acuerdo del 4-ago no cierra
|
||
|
||
1. **`Monto sin IVA` existe pero está prácticamente vacío.** Solo **2 de 69** tickets lo tienen: `FAC-100` y `FAC-101`, ambos creados el **4-ago** — el mismo día en que Arturo contestó el correo. El campo se agregó en ese momento; los 67 tickets anteriores lo tienen en `null`. Es buena noticia (el acuerdo ya se implementó) con dos consecuencias: no hay histórico para validar el mapeo contra facturas reales, y la obligatoriedad solo aplica al crear por portal — un ticket nacido de Automation entra con `null` igual.
|
||
|
||
2. **`conceptos` / partidas no existe como campo en NINGUNA parte del sitio.** `GET /rest/api/3/field` filtrado por monto/concepto/partida/importe/precio/cantidad/RFC devuelve únicamente:
|
||
- `customfield_11556` — `Monto sin IVA` (en uso)
|
||
- `customfield_11522` — `Monto con IVA` (existe, **no está en el formulario 83**)
|
||
- `customfield_10031` — `Total forms` (de JSM, no es de facturación)
|
||
|
||
Con un solo monto agregado **no se pueden armar partidas**: la cotización BIND queda de una sola línea con la descripción del `summary`. Eso puede ser aceptable como decisión, pero **hay que tomarla explícitamente**, y no cubre el caso ACUNTIA. Que exista `Monto con IVA` sin usar además abre la pregunta de si el IVA lo calcula BIND o viene dado.
|
||
|
||
**El caso ACUNTIA ya tiene evidencia:** `FAC-100` es exactamente eso — summary `Julio/CONSULTORIA Y SERVICIOS (Eduardo Fiallo CEMEXUSA)/ACUNTIA`, `Helmstone`, `USD`, 45 días, `Monto sin IVA = 7594.00`, con 2 adjuntos. **Un solo monto para un ticket que históricamente representa 40–48 facturas** ([REGISTRO #55](../bitacora/REGISTRO.md) punto 6). El supuesto “un ticket → una cotización” necesita confirmarse contra este caso antes de codificar.
|
||
|
||
> ⚠️ **ADF (Atlassian Document Format).** En Jira Cloud v3, `description` y los comentarios **no son texto plano ni wiki markup: son JSON estructurado**. Hay que decidir ya si se parsea ADF o se pide `expand=renderedFields` (HTML). Y al **escribir** comentarios/descripciones hay que **construir ADF válido**, no mandar un string. Es la trampa que más tiempo cuesta si se descubre tarde.
|
||
|
||
> ⚠️ **Adjuntos:** confirmar si `content` (URL de descarga) requiere el mismo Basic auth y si redirige. Y aplica la misma regla que con BIND: los adjuntos traen **datos reales de clientes** (constancias, estados de cuenta) — no van a disco del repo ni a documentos.
|
||
|
||
---
|
||
|
||
## Bloque 3 — Workflow, estatus y transiciones (el disparador) ✅🟡
|
||
|
||
**Disparador confirmado por Arturo el 4-ago: la cotización BIND se crea al entrar a `En proceso de facturación`.** El inventario técnico ya estaba levantado, así que la regla de negocio queda cerrada.
|
||
|
||
**Inventario confirmado:**
|
||
```
|
||
GET /rest/api/3/project/FAC/statuses → estatus por tipo de issue, con id y statusCategory
|
||
```
|
||
|
||
| Estatus | ID | Categoría |
|
||
|---|---:|---|
|
||
| Open | 1 | To Do |
|
||
| En proceso de facturación | 10305 | In Progress |
|
||
| Facturado | 10306 | Done |
|
||
| En espera por colaborador | 10339 | In Progress |
|
||
| Cancelado | 10372 | Done |
|
||
| En validación nacional | 10635 | In Progress |
|
||
| En validación extranjera | 10669 | In Progress |
|
||
|
||
**Transiciones de lectura confirmadas** (son contextuales al estatus actual):
|
||
|
||
| Ticket / estatus actual | transitionId | Destino |
|
||
|---|---:|---|
|
||
| FAC-98 / En proceso de facturación | 6 | En espera por colaborador |
|
||
| FAC-98 / En proceso de facturación | 8 | En validación nacional |
|
||
| FAC-98 / En proceso de facturación | 9 | En validación extranjera |
|
||
| FAC-98 / En proceso de facturación | 2 | Cancelado |
|
||
| FAC-91 / En validación nacional | 2 | Cancelado |
|
||
| FAC-89 / Cancelado | 12 | Open |
|
||
|
||
`FAC-97` ya está Facturado y no expone transiciones. Las respuestas consultadas no devolvieron campos obligatorios para las transiciones anteriores. Aun así, no se ejecutará ninguna transición sin la sesión acompañada.
|
||
|
||
**Diagrama de workflow compartido por Balam:** confirma la ruta completa y los nombres de transición:
|
||
|
||
```text
|
||
Open --[Iniciar facturación]--> En proceso de facturación
|
||
En proceso de facturación --[Pausar actividad]--> En espera por colaborador
|
||
En espera por colaborador --[Retomar actividad]--> En proceso de facturación
|
||
En proceso de facturación --[Validar documentación nacional]--> En validación nacional
|
||
En proceso de facturación --[Validar documentación extranjera]--> En validación extranjera
|
||
En validación nacional o extranjera --[Facturación completa]--> Facturado
|
||
En validación nacional o extranjera --[Rechazar actividad]--> En proceso de facturación
|
||
```
|
||
|
||
El diagrama también contempla cancelación desde los estados de trabajo y reapertura; la API confirmó al menos `Cancelado --[Reabrir Ticket]--> Open` en FAC-89. **No existe un estado “Resuelto” en el workflow.** Con la respuesta del 4-ago, la regla queda: **`Iniciar facturación` (Open → En proceso de facturación) dispara la cotización**; `Facturado` confirma que la factura se emitió.
|
||
|
||
### 🔴 Hallazgo crítico: el estatus disparador dura minutos, no horas
|
||
|
||
Recorrido real de `FAC-100` (4–5 ago), desde su changelog:
|
||
|
||
| Hora | Transición | Autor |
|
||
|---|---|---|
|
||
| 05-ago 11:51:25 | `Open` → **`En proceso de facturación`** | Arturo Rosas |
|
||
| 05-ago 11:54:09 | → `En validación extranjera` | Arturo Rosas |
|
||
| 05-ago 12:16:37 | → `Facturado` | **Araceli Sánchez** |
|
||
|
||
**El ticket estuvo 2 minutos 44 segundos en el estatus disparador**, y 25 minutos de punta a punta. Hoy solo **1 de los 69 tickets** está parado en `En proceso de facturación` (65 ya están `Facturado`).
|
||
|
||
**Consecuencia de diseño, no negociable:** un poller de 15 min que pregunte *“¿qué tickets están hoy en `En proceso de facturación`?”* **se pierde la mayoría de los disparos**. La detección **tiene que leer el changelog** y buscar el *cruce* de estado dentro de la ventana, exactamente como se resolvió la detección de pagos en BIND (ADR-004). Esto confirma y vuelve obligatorio lo que antes era una preferencia de arquitectura, y refuerza el caso de los webhooks (Bloque 4) para reducir la latencia.
|
||
|
||
### ⭐ Hallazgo nuevo: el workflow tiene aprobaciones de JSM
|
||
|
||
Ni FAC-98 ni el diagrama lo mostraban. Tanto `FAC-100` como `FAC-91` traen:
|
||
- `customfield_10003` **Approvers** = `Araceli Sánchez`
|
||
- `customfield_10025` **Approvals** = el estatus donde vive la aprobación (`En validación extranjera` / `En validación nacional`)
|
||
|
||
Es decir, **el paso a `Facturado` pasa por una aprobación formal de Araceli**, no por una transición simple. Implicaciones: (1) la plataforma **no debe intentar aprobar** — eso es decisión humana; (2) si algún día tuviera que transicionar a `Facturado`, la vía correcta es `/rest/servicedeskapi/request/{id}/approval`, no `/transitions`; (3) la aprobación es un buen punto de trazabilidad para saber quién autorizó cada factura.
|
||
|
||
⚠️ **Trampas:**
|
||
1. ~~**`Facturado` como estatus ≠ campo `resolution`.**~~ **Resuelto (10-ago):** en `FAC-100`, `status = Facturado` **y** `resolution = Done` **y** `resolutiondate` poblada, todo consistente. Ambas señales sirven; se usará el cruce de estatus en el changelog por coherencia con el resto del diseño.
|
||
2. **Las transiciones son contextuales**: `/transitions` solo devuelve las salidas del estado actual, y pueden tener **pantallas con campos obligatorios**. Probar con `expand=transitions.fields` para saber si transicionar por API exige llenar algo.
|
||
3. **`issuetype` de FAC es `admon`**, no “Service Request”. Cualquier JQL o creación por API debe usar ese nombre.
|
||
|
||
**Changelog = la fuente de la detección.** `expand=changelog` da cada cambio de estatus con timestamp y autor. Verificado en FAC-100 (`total: 6`) y FAC-91 (`total: 8`): vienen completos y sin paginar en tickets de este tamaño. Para tickets con mucho historial hay que usar `/rest/api/3/issue/{key}/changelog`, que sí pagina.
|
||
|
||
---
|
||
|
||
## Bloque 4 — Estrategia de sincronización: polling vs webhooks 🟡
|
||
|
||
El scheduler de la plataforma ya existe (`BackgroundService` + `PeriodicTimer` a 15 min). La pregunta es qué le pega a Jira.
|
||
|
||
**a) Búsqueda por JQL — validado.**
|
||
El endpoint clásico `GET /rest/api/3/search` respondió **410 Gone**. La integración debe usar `GET /rest/api/3/search/jql`, con `nextPageToken`. La lectura de FAC recuperó 66 tickets con ese mecanismo.
|
||
|
||
JQL de delta a validar:
|
||
```
|
||
project = FAC AND updated >= "-20m" ORDER BY updated ASC
|
||
```
|
||
⚠️ **`updated` en JQL tiene granularidad de minuto**, no de segundo → el checkpoint necesita **ventana de solape** (igual que el re-barrido de facturas abiertas de BIND) o se pierden tickets en el borde.
|
||
|
||
Validar también: `fields=` para pedir solo lo necesario (menos payload, menos puntos), y el tope real de `maxResults`.
|
||
|
||
**b) Webhooks.** Tres caminos, con dueños distintos:
|
||
|
||
| Opción | Quién la configura | Nota |
|
||
|---|---|---|
|
||
| Webhook de sitio (admin) | **Pedro** (requiere admin de Jira) | El más limpio; exige endpoint público |
|
||
| **Regla de Jira Automation** con "Send web request" | **Pedro, sin escribir código** | La más realista a corto plazo; se puede acotar a FAC y a un estatus |
|
||
| Webhook dinámico vía OAuth app | Desarrollo | **Expiran a los 30 días**, hay que refrescarlos |
|
||
|
||
**Recomendación:** **arrancar con polling** y dejar el webhook para después. Ningún webhook sirve hasta que exista un endpoint público, y Azure sigue pendiente del lado de Balam. El polling además es reversible y no depende de que Pedro toque su instancia.
|
||
|
||
**c) Rate limits — headers verificados ✅ (10-ago).** La respuesta de `/rest/api/3/search/jql` sí los emite:
|
||
|
||
```text
|
||
X-RateLimit-Limit: 350
|
||
X-RateLimit-Remaining: 348
|
||
RateLimit-Policy: "jira-burst-based";q=100;w=1
|
||
RateLimit: "jira-burst-based";r=348;t=1
|
||
```
|
||
|
||
Tres notas: (1) la telemetría existe y el autorregulado por headers es viable, como se le dijo a Erika el 29-jul; (2) el límite observado es **350**, no los 100/s que mencionó Pedro — hay que leer el header y no hardcodear el número; (3) aparecen también los headers estándar `RateLimit-*` (RFC) además de los `X-RateLimit-*`, así que el cliente debe tolerar ambos. `X-RateLimit-NearLimit` no apareció porque no se llegó al 20% del umbral. No se provocó un 429 deliberadamente contra producción.
|
||
|
||
---
|
||
|
||
## Bloque 5 — La bandeja padre: de dónde nacen realmente los tickets 🟡
|
||
|
||
Pedro dijo que procesos que **se cierran en RH o Administración General caen en Facturación**. Técnicamente eso puede ser cuatro cosas distintas, y cada una se sincroniza diferente:
|
||
|
||
| Mecanismo | Cómo detectarlo | Implicación |
|
||
|---|---|---|
|
||
| **Issue link** (RH-45 relacionado con FAC-89) | `issuelinks` en el issue | Escuchar FAC basta; el link da contexto |
|
||
| **Clon / creación por Automation** | `changelog` + campo `creator` (usuario de automation) | Escuchar FAC basta |
|
||
| **Subtarea / hijo** | `parent` / `subtasks` | Relevante para ACUNTIA (1 ticket ↔ 40 facturas) |
|
||
| **Move entre proyectos** | `changelog` con cambio del campo `project` | 🔴 **La llave del ticket CAMBIA** (RH-45 → FAC-89). Cualquier folio persistido se rompe |
|
||
|
||
**Resultado de la prueba (10-ago): es creación por Automation, no move. ✅**
|
||
|
||
Los 10 tickets sin request type tienen `creator` = `reporter` = **`Automation for Jira`**, y sus changelogs (revisados en FAC-91) **no muestran cambios de `project` ni de `key`**. El patrón es: la regla de Automation **crea** un ticket nuevo en FAC y lo **liga** al original con `issuelinks`. Ejemplos de summary, que llevan el origen embebido:
|
||
|
||
```text
|
||
FAC-91 [FACTURA COMPLETA - Staff Augmentation] Axians - Incident Manager — RH-36
|
||
FAC-1 Seguimiento del Ticket Cerrado: HH-1 - Prueba #1
|
||
FAC-28 Seguimiento del Ticket con pago anticipado: HH-8 - TLE
|
||
```
|
||
|
||
Se ven tres bandejas de origen: **HH** (headhunting), **SA** (staff augmentation), **IN**, y **RH**. Dos patrones de regla: `Seguimiento del Ticket Cerrado:` y `Seguimiento del Ticket con pago anticipado:` — el segundo probablemente implique PUE y toca la pregunta pendiente de PUE/PPD.
|
||
|
||
**Conclusiones para el modelo de datos:**
|
||
- **Escuchar FAC basta** para detectar el disparo; el origen se obtiene de `issuelinks` sin salir del proyecto.
|
||
- No hay evidencia de moves, así que la llave `FAC-nnn` **parece** estable. Aun así conviene **persistir el `issue.id` numérico** (FAC-100 = `17308`, FAC-91 = `14348`): es inmutable por diseño y el costo de guardarlo es cero.
|
||
- ⚠️ Estos tickets son la vía sin campos estructurados del Bloque 1. Si la automatización debe cubrirlos, **la regla de Automation de Balam tendría que propagar los campos** al crear el ticket en FAC.
|
||
|
||
---
|
||
|
||
## Bloque 6 — Escritura (CRUD): qué probar, cómo aprobarlo y dónde 🔴
|
||
|
||
**Confirmado por Noé el 7-ago: prueba acompañada sobre un ticket acordado. No habrá proyecto `FACTEST`.** Eso cierra la pregunta pero **deja el riesgo intacto**: se escribirá en producción, y el token tiene permisos para crear, editar, transicionar, comentar, adjuntar e incluso borrar tickets en FAC. El protocolo de abajo pasa de recomendación a requisito, y el sandbox propio (ver recuadro al final del bloque) pasa de opcional a necesario para desarrollar sin tocar Balam.
|
||
|
||
**Protocolo obligatorio para cualquier prueba de escritura:**
|
||
1. Preparar un script idempotente y de una sola operación; sin bucles, sin búsquedas masivas y sin credenciales embebidas.
|
||
2. Compartir el script y el payload de ejemplo con Pedro/Arturo antes de la sesión; documentar endpoint, ticket destino, efecto esperado y reversión.
|
||
3. Acordar el ticket de prueba y una ventana de ejecución. Preferir un proyecto sandbox (`FACTEST`) o un ticket creado expresamente para la prueba.
|
||
4. Ejecutarlo acompañado, registrar el `HTTP status`, el `issue.id`/`key` y verificar el resultado por API.
|
||
5. No probar `DELETE`; no es una capacidad necesaria para la plataforma y no es reversible en producción.
|
||
|
||
**Operaciones a validar, en este orden (de menos a más invasivo):**
|
||
|
||
1. **Comentar** — `POST /rest/api/3/issue/{key}/comment` (cuerpo en ADF).
|
||
⚠️ En JSM hay **comentarios públicos (los ve el cliente) vs internos**: `POST /rest/servicedeskapi/request/{id}/comment` con `public: true|false`. **La plataforma debe escribir SIEMPRE internos.** Publicar por error un comentario visible al cliente es el error más caro y menos reversible de este bloque.
|
||
2. **Adjuntar** — `POST /rest/api/3/issue/{key}/attachments`.
|
||
⚠️ Exige el header `X-Atlassian-Token: no-check` y `multipart/form-data`. Sin ese header falla con un error que no explica nada. Es la vía para dejar el PDF/XML como evidencia en el ticket.
|
||
3. **Transicionar** — `POST /rest/api/3/issue/{key}/transitions` con el `transition.id` del Bloque 3.
|
||
4. **Crear** — decisión real de diseño: `POST /rest/api/3/issue` (crudo, se salta el request type y el ticket queda "raro" en el portal) vs `POST /rest/servicedeskapi/request` (respeta request type y se ve como uno normal). **Si es JSM, la segunda es la correcta.**
|
||
5. **Editar** — `PUT /rest/api/3/issue/{key}`.
|
||
6. **Borrar** — `DELETE /rest/api/3/issue/{key}`. Requiere permiso de admin de proyecto. **Probablemente ni se tenga ni convenga tenerlo**; en producción el borrado no debe ser una capacidad de la plataforma.
|
||
|
||
> 🔴 **Dónde probar.**
|
||
> ~~Pedir a Pedro un proyecto de pruebas `FACTEST`~~ → **descartado por Noé el 7-ago:** será prueba acompañada sobre un ticket. Queda entonces una sola vía de mitigación:
|
||
>
|
||
> **Crear un sitio propio y gratuito de Jira Cloud** (plan Free, hasta 10 usuarios) con un proyecto JSM que replique el workflow de FAC. Sirve para desarrollar el cliente, el parser de ADF, la paginación, las aprobaciones y las transiciones **sin tocar nada de Balam** ni depender de que respondan. Es el sandbox que BIND nunca tuvo. Contra producción solo se corre lectura y, al final, la única prueba acompañada.
|
||
>
|
||
> Con el `FACTEST` descartado, esto ya no es una alternativa: es el único lugar donde se puede equivocar sin costo.
|
||
|
||
---
|
||
|
||
## Bloque 7 — Gobierno y seguridad 🟡
|
||
|
||
- ✅ ~~**`propuesta/token-jira.txt` NO está en `.gitignore`**~~ → **Resuelto:** ignorado en [`.gitignore:9`](../.gitignore). Sigue pendiente mover el token a user-secrets / Key Vault y borrarlo de disco. Mismo pendiente que arrastra `bind_token_api.txt`.
|
||
- **Cuenta de servicio vs cuenta personal de Pedro** (ya planteado en el borrador de correo del 29-jul): hoy todo lo que la plataforma escriba en Jira queda firmado con el nombre de Pedro, y una rotación suya deja la integración muerta. Verificar con `GET /rest/api/3/myself` con qué identidad se está actuando. **Sin respuesta al 10-ago.**
|
||
- 🔴 **Alcance de permisos:** validado con `GET /rest/api/3/mypermissions` para FAC. El token puede navegar, crear, editar, transicionar, comentar, adjuntar y borrar tickets. Es un alcance excesivo para producción; la integración no debe implementar borrado y conviene migrar a una cuenta de servicio con permisos mínimos.
|
||
- **Vigencia 27-jul-2027** → dejar registrado el vencimiento y el plan de rotación desde ahora.
|
||
- **Datos de clientes en adjuntos y descripciones** — misma regla que BIND: nunca a disco del repo ni a documentos compartidos.
|
||
|
||
---
|
||
|
||
## Bloque 8 — Preguntas para Pedro / Balam (no se resuelven con la API)
|
||
|
||
**Cerradas con el correo del 7-ago:**
|
||
|
||
1. ~~**¿Puede crear un proyecto de pruebas `FACTEST`?**~~ → **No.** Prueba acompañada sobre un ticket (Noé, 7-ago).
|
||
2. ~~**¿Debe observarse `Facturación adicional` (83), `Facturación` (12) u otro?**~~ → **Todos los request types** de la bandeja (Arturo, 4-ago). ⚠️ Con la salvedad del Bloque 1: 10 tickets no tienen request type ni campos.
|
||
3. ~~**¿Cuál estatus dispara la cotización?**~~ → **`En proceso de facturación`** (Arturo, 4-ago).
|
||
4. ~~**¿Monto del adjunto o como campo?**~~ → **Campo de Jira.** Ya implementado (`customfield_11556`), omitiendo recurrencia (Arturo, 4-ago).
|
||
|
||
**Abiertas:**
|
||
|
||
5. 🔴 **¿De dónde salen los CONCEPTOS/partidas?** El acuerdo resolvió el monto pero no los conceptos, y **no existe campo para ellos en el sitio**. ¿Cotización de una sola línea con el `summary` como descripción, o se agrega un campo?
|
||
6. 🔴 **¿Qué pasa con los tickets creados por Automation for Jira** (10 de 69, sin ningún campo estructurado, incluido `FAC-91` que está vivo)? ¿Se acota la automatización o la regla de Automation propaga los campos?
|
||
7. 🔴 **ACUNTIA / `FAC-100`:** ¿un ticket con `Monto sin IVA` único debe generar **una** cotización, o sigue siendo el caso de 40–48 facturas?
|
||
8. **¿Nacional vs extranjero cambia la cotización** o solo el paquete de salida (PDF+XML vs PDF)? Hay dos estatus de validación distintos y una aprobación por cada rama.
|
||
9. **¿Quién puede crear webhooks o reglas de Automation** apuntando a una URL nuestra, y bajo qué proceso? Gana urgencia: el estatus disparador dura minutos (Bloque 3).
|
||
10. **PUE vs PPD** — la pregunta que no se ha alcanzado a hacer en cuatro sesiones ([REGISTRO #52](../bitacora/REGISTRO.md)). Los tickets `Seguimiento del Ticket con pago anticipado:` sugieren que sí hay casos PUE reales.
|
||
11. **Cuenta de servicio** en lugar de la cuenta personal de Pedro, y fecha para la prueba acompañada.
|
||
|
||
---
|
||
|
||
## Orden de ataque sugerido
|
||
|
||
| # | Acción | Bloqueado por |
|
||
|---|---|---|
|
||
| 1 | ✅ Blindar el token (`.gitignore`) — falta secrets/Key Vault | — |
|
||
| 2 | ✅ Mapeo de campos y contratos de request type verificados (10-ago) | — |
|
||
| 3 | Implementar lectura con `/search/jql`, cursor y ventana de solape | — |
|
||
| 4 | **Detección por changelog del cruce a `En proceso de facturación`** | — (ya desbloqueado por el acuerdo del 4-ago) |
|
||
| 5 | Parser de ADF para `Nombre del Cliente` + match contra `Clients` de BIND | ⚠️ Sin RFC; definir tolerancia del match |
|
||
| 6 | Armado de la cotización BIND | 🔴 Definición de conceptos/partidas (pregunta 5) |
|
||
| 7 | Levantar un sandbox Jira propio (plan Free) | — (ya no depende de Balam) |
|
||
| 8 | Preparar y compartir el script de escritura mínimo para revisión | — |
|
||
| 9 | Ejecutar una única prueba de escritura acompañada | Fecha de Balam + script revisado + ticket acordado |
|
||
|
||
**Lo que puede avanzar ya:** el cliente de lectura, manejo de ADF, paginación por cursor, mapeo de campos, detección incremental por changelog y el sandbox propio. **Lo único que sigue bloqueado es el armado final de la cotización**, por la definición de conceptos. La escritura queda fuera del flujo automático hasta la sesión acompañada.
|
||
|
||
---
|
||
|
||
## Briefing corto para desarrollo / revisión técnica
|
||
|
||
> Contexto validado: Jira Cloud JSM en `balam-jsm-temp.atlassian.net`; proyecto FAC company-managed (`projectId: 10034`, `serviceDeskId: 35`). La autenticación directa con Basic `email:token` funciona. El token tiene permisos de escritura amplios, pero **no se debe ejecutar ningún POST, PUT o DELETE fuera de una prueba acompañada y aprobada**.
|
||
>
|
||
> Para la capa de lectura, usar `GET /rest/api/3/search/jql`, paginar por `nextPageToken` y aplicar una ventana de solape al checkpoint de `updated`. No usar `/rest/api/3/search`: responde 410.
|
||
>
|
||
> Para JSM, usar `/rest/servicedeskapi` al consultar request types y su contrato de campos. FAC publica 4 request types: Bajas (84), Facturación adicional (83), Automatización (389) y Facturación (12); los cuatro contratos están verificados. **Facturación adicional (83) es el único con datos de facturación** e incluye `Monto sin IVA` (`customfield_11556`, number). **No existe campo de conceptos/partidas en el sitio.**
|
||
>
|
||
> **El disparador acordado es el cruce a `En proceso de facturación`, y dura minutos** (FAC-100: 2m44s). La detección debe leer el changelog y buscar el cruce dentro de la ventana; consultar el estatus actual no sirve. El `issuetype` es `admon`. El workflow tiene **aprobaciones de JSM** con Araceli como aprobadora en las ramas de validación nacional/extranjera: la plataforma nunca aprueba.
|
||
>
|
||
> **10 de 69 tickets nacen de `Automation for Jira`** desde HH/SA/IN/RH, sin request type y sin ningún campo estructurado; los datos van en el `summary` y la `description` (ADF), con el origen en `issuelinks`. Persistir el `issue.id` numérico además de la llave.
|
||
>
|
||
> Pendientes técnicos: parser de ADF para `Nombre del Cliente` (no trae RFC), armado de la cotización cuando se defina el tema de conceptos, y diseñar un script de escritura de una sola operación para revisión previa. El script debe ser idempotente, no incluir credenciales y ejecutarse únicamente en el sandbox propio o acompañado en el ticket de prueba acordado. **No habrá `FACTEST`.**
|