Compare commits

..

28 Commits

Author SHA1 Message Date
JohannVelazquez cbb29086cc Documenta las definiciones Jira→BIND y su validación por API
Consolida el disparador, los huecos de datos y el protocolo de prueba para continuar el desarrollo con decisiones trazables.
2026-08-11 20:23:55 -06:00
JohannVelazquez 980baf0a0a Documenta la API de Jira FAC y protege su token
Consolida los hallazgos y decisiones pendientes para continuar el desarrollo sin exponer credenciales.
2026-08-01 12:38:39 -06:00
JohannVelazquez 820b8d41c8 Valida y consolida las horas al 27-jul: 41.58 h trazables desde el CSV
Las horas quedan validadas una por una contra evidencia fechada y el Excel
deja de tener cifras escritas a mano: se generan desde Seguimiento-horas.csv
y el script aborta si el detalle no cuadra con el total.

Correcciones de fondo:
- El Excel reportaba 17 h de Etapa 1 contra 16 h en el CSV (override manual).
- Comas sin escapar en el CSV ocultaban 1.00 h del 19-jul al parseo.
- El 10-jul estaba mal etiquetado: la mayor parte fue pulido del prototipo
  (E0-05), no el entregable de cierre (E0-06). Mismo total, etiquetas reales.
- Se incorporan 3.50 h no cobradas con evidencia: diseño del plan de Etapa 1
  (2.00 h) y preparación de las sesiones del 22 y 24-jul (1.50 h).
- Ajustes a la baja de Johann en horas reconstruidas: análisis del Discovery
  1.92→1.00 h, documentación de cobranza 1.50→0.75 h, guion 0.75→0.45 h.
  Las duraciones con transcript no se tocaron. Etapa 0 vuelve al rango 18–22 h.

Presentación del avance:
- Se reporta 75 % de Etapa 1 = 6 de 8 entregables cerrados, en lugar del 82 %
  ponderado anterior, que no distinguía trabajo hecho de trabajo bloqueado.
- Capa de escritura al 40 % (diseño, ADR-001 y modelo listos; falta el
  BindWriteClient y los shapes de los POST) y Jira al 90 % (conectividad
  resuelta el 27-jul; falta qué estatus dispara qué, sujeto a la definición
  de Balam). Modelo de facturas al 85 % con horas propias: ya no aparece
  avanzado con cero horas.
- Las 7 h que acumulaba "Demostración semanal" se reparten a las filas
  técnicas que les corresponden; esa fila se queda con gestión (1.75 h).

Nuevo: Avance-Balam-2026-07-27.xlsx, versión simple para Erika, derivada del
Excel interno para que ambos no puedan contradecirse.

Bitácora #58: Erika confirma que el Excel de horas es el insumo de
FACTURACIÓN, corrige su lectura de la capa de escritura al 100 %, y vuelve a
pedir la propuesta ajustada por Jira (pendiente desde el 22-jul). La sesión
del flujo de facturación no queda agendada: Balam la revisa internamente.
2026-07-28 22:21:04 -06:00
Johann bee2d02f50 Documenta semana 24-27 jul: validación de prototipo (aprobada), API de Jira y avance de Etapa 1
- REGISTRO #55: validación del prototipo Etapa 0 (24-jul) APROBADA; único bloqueo = definir el flujo de facturación en Jira (sesión propuesta por Araceli para el martes 28)
- REGISTRO #56: sesión de API de Jira con Pedro (27-jul) — token PAF a 1 año, bandeja FAC; + seguimiento por correo del mismo día con los límites de velocidad (65k puntos/h, burst/s, por-issue) y entrega del token por Google Drive
- REGISTRO #57: hilo de WhatsApp con Erika (21-27 jul) — coordinación, envío del flujo por correo y reagenda 23→24 jul; 3 imágenes inferidas
- Transcripciones y correo en fuentes/; guion de validación en planeacion/
- Avance-Etapa1-2026-07-27 (nota + mensaje para Erika) y Excel del corte del 27-jul (núcleo verificado; capa de escritura en pausa por definición de Balam)
- Seguimiento-horas: sesiones del 24-jul (validación) y 27-jul (API Jira)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-27 08:18:08 -06:00
Johann bebca73bfe Registra la sesión del 22-jul: alta de clientes en BIND, fee bancario (despacho) y flujo Jira confirmado
Transcript renombrado con fecha, entrada #54 en el REGISTRO, minuta de la
sesión llenada, PENDIENTES al día (PUE/PPD y particularidades de envío no
se tocaron; nuevos compromisos: diagrama Jira y sesión API con Pedro) y
0.80 h confirmadas en el control de horas.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 06:52:33 -06:00
Johann 117606d71d Ignora respaldos/ (dumps locales de la BD con datos reales de BIND) 2026-07-22 06:10:32 -06:00
Johann c3e984944e Cierre 21-jul: B4 con sync histórico verificado y B6 aplicado; horas, bitácora y Excel de avance al día 2026-07-22 00:06:54 -06:00
JohannVelazquez 388e772c40 Registra entrega del avance de Etapa 1 a Erika (16-jul, 8:40 pm)
Excel de avance enviado por WhatsApp con acuse de recibo; cierra ese
pendiente y el de permisos de escritura al repo (comprobado con el
push del scaffold). Actualiza fuente #46, REGISTRO y PENDIENTES.
2026-07-19 20:12:25 -06:00
JohannVelazquez e057fb9127 Etapa 1: plan de ejecución, corte de avance del 16-jul y fuentes
- Plan-Etapa1.md: plan detallado por fases/bloques (B0-B9) con horas,
  decisiones de arquitectura y lo bloqueado hasta el 22-jul
- Avance-Etapa1-2026-07-16.md + Excel de avance ordenado por fechas
  (con script generador y de ordenamiento)
- WhatsApp 16-jul: invitación al Git recibida, procedimientos de
  clientes enviados por correo, Erika pide avance de Etapa 1
- Actualiza PENDIENTES y REGISTRO
2026-07-19 20:05:01 -06:00
JohannVelazquez 3a66e5aee1 Actualiza cierre de Etapa 0 y control de horas 2026-07-16 09:44:21 -06:00
JohannVelazquez 8da11ea164 Prototipo: pantalla de login + ejemplo de tolerancia por fee en Edo. cuenta
- Login de demo (credenciales precargadas arturo@balam.mx) antes de entrar
  a la app; el chip de usuario en el sidebar ahora cierra sesión.
- Estado de cuenta · ACUNTIA: F-2026-0034 ilustra el caso real de la
  llamada del 7-jul (Arturo cruza pagos con Acuntia y los totales no
  cuadran por el fee) — Total/Pagado/Saldo alineados para comparar de un
  vistazo, más la alerta que traduce el residual ($180 MXN, dentro del
  umbral de $200) a lenguaje llano.
2026-07-10 01:52:51 -06:00
JohannVelazquez a2104f2a63 Prototipo: "Edo. cuenta" abre modal en vez de panel inline/toast
Antes solo la fila de ACUNTIA abría un panel embebido en la página; las
otras tres mostraban un toast aclarando que era demo. Ahora las 4 abren
el mismo modal (backdrop oscuro, cierra con click fuera o Escape),
consistente con el pedido de revisar Cobranza para la reunión de mañana.
2026-07-10 01:22:32 -06:00
JohannVelazquez 6daeeab72d Prototipo: quita la tarjeta "Otra cotización del cliente" (paso 1 del wizard)
Mostraba COT-2026-0448 (mismo cliente, proyecto de Arq. Jorge Salinas) como
alternativa seleccionable, sin indicar que pertenece a otro ticket
(FAC-0868, ya facturado) — confuso, riesgo de elegir la cotización
equivocada. El paso 1 ahora solo confirma la cotización vinculada al
ticket; se quita pickQuote() por quedar sin uso.
2026-07-10 01:05:30 -06:00
JohannVelazquez 4dca2ecc7c Prototipo: quita "Por aprobar y emitir" del sidebar (redundante)
Era equivalente a activar el filtro "Listos para facturar" en Solicitudes
(Jira) — mismos 3 tickets, sin aportar nada nuevo. El wizard de emisión
sigue accesible desde el detalle de una solicitud ("Iniciar facturación").
2026-07-10 00:58:52 -06:00
JohannVelazquez 365c99acb6 Prototipo: bandeja real para "Por aprobar y emitir"
Antes el ítem del sidebar abría directo el wizard hardcodeado de FAC-0876,
igual que "Iniciar facturación" desde la solicitud — dos accesos al mismo
destino sin explicar el badge de "3". Ahora tiene su propia bandeja con los
3 tickets "listos para facturar" (mismo criterio que el filtro en
Solicitudes); solo FAC-0876 abre el wizard completo, los otros dos
muestran un toast que deja claro que es demo. Cancelar en el paso 1 regresa
a esta bandeja en vez de saltar a Solicitudes.
2026-07-10 00:55:06 -06:00
JohannVelazquez b358570443 Prototipo Etapa 0: pulido de UI (agente de diseño) + capturas de referencia
Ajustes visuales al wizard de emisión, sidebar con logo oficial, dashboard
y componentes de dinero/atención. Se agregan capturas de cada vista en
prototipo/capturas/ para revisión de diseño.
2026-07-10 00:44:23 -06:00
JohannVelazquez 8967fa2fed Bitácora #32: validación API BIND completada (adelantada); pendientes de escalación a Pedro 2026-07-06 17:17:27 -06:00
JohannVelazquez fde0b9333b Prototipo Etapa 0: HTML navegable con el flujo real del Discovery (Jira → cotización → prefactura → CFDI → envío) 2026-07-06 17:17:27 -06:00
JohannVelazquez 9ccfbe262e Validación técnica de la API de BIND contra producción (GET-only)
Plan A del saldo CONFIRMADO (Total − Payments − CreditNotes, misma fila);
flujo MVP sostenible 100% en lectura; PDF del CFDI por API. Hallazgo duro:
sin recurso de pagos individuales ni REP (escalar a Pedro). Cliente extendido
(Quotes, Currencies, Locations, pdf/xml, GET por ID estilo REST) y tipos
reales en types.real.ts. Detalle en bind-api-sandbox/VALIDACION-API.md;
reporte crudo y token gitignoreados.
2026-07-06 17:17:27 -06:00
JohannVelazquez 12006b5fa4 Bitácora: correo de Noé pide salvaguardas sobre el token (posible reemplazo por usuario solo-lectura) 2026-07-06 16:38:50 -06:00
JohannVelazquez 231a121327 Bitácora: acuse de recibo del token enviado por Johann (correo 6-jul 3:28 pm) 2026-07-06 15:32:28 -06:00
JohannVelazquez 082a89eb05 Bitácora: correo de Pedro entrega token BIND (usuario Arturo Rosas confirmado); renumera #29-30 2026-07-06 15:07:16 -06:00
JohannVelazquez f69d6104bd Bitácora 6-jul (tarde): token de BIND entregado por correo; sesión de cobranza propuesta para el 7-jul 2026-07-06 15:05:18 -06:00
JohannVelazquez 5f500d9a78 Bitácora: precisa que el Discovery 6-jul cubrió solo facturación; cobranza pendiente (candidata para sesión del 7-jul) 2026-07-06 14:34:37 -06:00
JohannVelazquez b3e4673238 Bitácora 6-jul (mediodía): token de BIND generado, entrega por correo en curso 2026-07-06 12:22:19 -06:00
JohannVelazquez 5004269664 Bitácora 1–6 jul: kickoff, manual de marca y Discovery de facturación
- REGISTRO #22–28: kickoff (1-jul), manual de marca recibido, coordinación
  y sesión de Discovery del proceso de facturación (6-jul), envío de la
  propuesta v1.2 y seguimiento del token de BIND (solicitado por Erika).
- Cambios de reglas del 6-jul: lista blanca eliminada (recordatorios a
  todos) y cotización BIND obligatoria como inicio del flujo.
- marca/: tokens oficiales destilados del manual de imagen corporativa.
- Plan de actividades actualizado con responsables reales post-kickoff.
- Fuentes: transcripts de kickoff y Discovery, WhatsApps de Erika, manual
  de imagen corporativa (PDF).
2026-07-06 10:57:41 -06:00
JohannVelazquez 2bdf5064d7 Propuesta v1.2: factura inicial de 30 h vinculada al arranque
Actualiza la propuesta comercial (fuente MD + HTML/PDF regenerado) para
dejar explícita la facturación inicial de 30 h ($18,000 + IVA) ligada al
arranque, conforme a lo pedido por Balam en el kickoff del 1-jul. Se
mantiene el mismo archivo (Propuesta-Balam.pdf/html) como única versión
vigente en el repo.
2026-07-02 17:31:02 -06:00
JohannVelazquez 7a720ec60e Limpia repo: elimina _archivado/ y corrige enlaces del README
- Elimina _archivado/ completo (material superado; preservado en historial):
  zip redundante con su carpeta extraída, propuesta vieja, borradores y diagramas previos.
- README: corrige enlace roto a Propuesta-Balam-v1.1.pdf (inexistente) y unifica
  la descripción del único PDF + su fuente reproducible.
- README: quita la fila de _archivado/ ya sin objeto.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 15:27:35 -06:00
95 changed files with 10157 additions and 11185 deletions
+16
View File
@@ -4,6 +4,22 @@ Thumbs.db
.vscode/ .vscode/
.idea/ .idea/
# Secretos — NUNCA versionar (tokens de API de BIND y Jira, producción)
bind_token_api.txt
propuesta/token-jira.txt
*.env
# Repo de código del cliente (github.com/pedro-balam-itsm/BALAM) — clon local, tiene su propio git
balam-plataforma/
# Evidencia financiera sensible local — no subir al repositorio
Resumen de movimientos.pdf
# Respaldos de la BD local (pg_dump formato custom) — traen datos REALES de
# clientes de BIND; jamás al historial de git.
# Restaurar: docker exec -i balam-postgres-dev pg_restore -U balam -d balam --clean --if-exists < respaldos/<archivo>
respaldos/
# Python (skill proposal-pdf) # Python (skill proposal-pdf)
__pycache__/ __pycache__/
*.pyc *.pyc
+23 -12
View File
@@ -2,8 +2,8 @@
> **Fuente de la verdad del proyecto.** Este repositorio concentra todo: propuesta, comunicaciones, fuentes y prototipos. Si pasa algo (llamada, correo, mensaje, decisión), se registra en la [bitácora](bitacora/). Empieza por aquí. > **Fuente de la verdad del proyecto.** Este repositorio concentra todo: propuesta, comunicaciones, fuentes y prototipos. Si pasa algo (llamada, correo, mensaje, decisión), se registra en la [bitácora](bitacora/). Empieza por aquí.
**Estado:** 🟢 **En arranque** — contrato firmado (26-jun), **kickoff con Noé el 1-jul (7am)**, plan de actividades (4 etapas) entregado. Falta que Balam entregue los **accesos** para iniciar el Discovery (sem del 6-jul). **Estado:** 🟢 **Etapa 0 en validación + Etapa 1 iniciada en local.** Discovery de facturación, envío y cobranza completo (67 jul); prototipo entregado el 10-jul y sesión de validación confirmada para el **23-jul, 7:00 pm**. Sesión de reglas/dudas de Etapa 1 confirmada para el **22-jul** con Arturo y CEO. Token BIND validado en solo lectura; repo GitHub autorizado por Noé y pendiente de invitación para `Johann-28`; Azure programado para la semana del 21-jul. La confirmación para emitir la **factura inicial de 30 h** sigue pendiente por viaje de Noé y CEO. Control local de horas iniciado.
_Última actualización: 2026-06-30._ _Última actualización: 2026-07-15._
--- ---
@@ -17,12 +17,13 @@ Plataforma web para centralizar y automatizar **facturación y cobranza** de Bal
|---|---| |---|---|
| [`README.md`](README.md) | **Este archivo** — estado y datos clave del proyecto. | | [`README.md`](README.md) | **Este archivo** — estado y datos clave del proyecto. |
| [`bitacora/`](bitacora/) | **Registro vivo**: [REGISTRO.md](bitacora/REGISTRO.md) (cronología de comunicaciones), [PENDIENTES.md](bitacora/PENDIENTES.md) (acciones abiertas), [README.md](bitacora/README.md) (cómo registrar + plantillas). | | [`bitacora/`](bitacora/) | **Registro vivo**: [REGISTRO.md](bitacora/REGISTRO.md) (cronología de comunicaciones), [PENDIENTES.md](bitacora/PENDIENTES.md) (acciones abiertas), [README.md](bitacora/README.md) (cómo registrar + plantillas). |
| [`propuesta/`](propuesta/) | [Propuesta (MD)](propuesta/00%20-%20PROPUESTA-COMERCIAL.md) — contenido fuente v1.1. [PDF enviado](propuesta/Propuesta-Balam.pdf). [PDF regenerado con el skill](propuesta/Propuesta-Balam-v1.1.pdf) + su fuente reproducible ([HTML](propuesta/Propuesta-Balam.html) + [config](propuesta/pdf.config.json), build con el skill `proposal-pdf`). [Prototipo](propuesta/prototipo-mvp-fase1.html), [diagrama Fase 1 vs PRD](propuesta/diagrama-fase1-vs-prd.html). | | [`propuesta/`](propuesta/) | [Propuesta (MD)](propuesta/00%20-%20PROPUESTA-COMERCIAL.md) — contenido fuente v1.1. [PDF enviado](propuesta/Propuesta-Balam.pdf), regenerable desde su fuente reproducible ([HTML](propuesta/Propuesta-Balam.html) + [config](propuesta/pdf.config.json), build con el skill `proposal-pdf`). [Prototipo](propuesta/prototipo-mvp-fase1.html), [diagrama Fase 1 vs PRD](propuesta/diagrama-fase1-vs-prd.html). |
| [`fuentes/`](fuentes/) | Material crudo: PRD, transcripciones de llamadas, `.eml`. Evidencia, no se edita. | | [`fuentes/`](fuentes/) | Material crudo: PRD, transcripciones de llamadas, `.eml`. Evidencia, no se edita. |
| [`bind-api-sandbox/`](bind-api-sandbox/) | Prototipo técnico del cliente/mock de la API de BIND (TypeScript; el productivo será .NET). | | [`bind-api-sandbox/`](bind-api-sandbox/) | Prototipo técnico del cliente/mock de la API de BIND (TypeScript; el productivo será .NET). |
| [`_archivado/`](_archivado/) | Material superado (propuestas viejas, diagramas previos). Histórico. |
| [`.claude/skills/proposal-pdf/`](.claude/skills/proposal-pdf/) | **Skill** que genera el PDF de la propuesta/cotización con diseño editorial (portada full-bleed, TOC con páginas reales, footers "Confidential"). Pipeline Chromium + 2 pasos. Setup y uso en su [SKILL.md](.claude/skills/proposal-pdf/SKILL.md) (incluye nota de Windows). | | [`.claude/skills/proposal-pdf/`](.claude/skills/proposal-pdf/) | **Skill** que genera el PDF de la propuesta/cotización con diseño editorial (portada full-bleed, TOC con páginas reales, footers "Confidential"). Pipeline Chromium + 2 pasos. Setup y uso en su [SKILL.md](.claude/skills/proposal-pdf/SKILL.md) (incluye nota de Windows). |
| [`planeacion/`](planeacion/) | **Plan de ejecución:** [Plan-actividades.xlsx](planeacion/Plan-actividades.xlsx) (+ [`.md`](planeacion/Plan-actividades.md)) — actividades por etapa (03) con fechas, responsables y sesiones, para el seguimiento con Erika (Jira/Gantt). | | [`planeacion/`](planeacion/) | **Plan y seguimiento:** [Excel oficial consolidado](planeacion/Plan-actividades-avance-2026-07-10-ajustado.xlsx), [plan legible](planeacion/Plan-actividades.md), [control de horas](planeacion/Seguimiento-horas.md) ([CSV](planeacion/Seguimiento-horas.csv)) y [hallazgos/ADRs de Etapa 0](planeacion/Hallazgos-y-decisiones-Etapa0.md). |
| [`marca/`](marca/) | **Tokens de marca** ([Marca-Balam.md](marca/Marca-Balam.md)) destilados del manual de imagen corporativa: color (Amarillo `#F7BD0C`, Café `#331F0E`), tipografía (Poppins) y uso del logo, para el prototipo y la UI. Manual crudo en [`fuentes/`](fuentes/). |
| [`prototipo/`](prototipo/) | **Prototipo visual navegable (Etapa 0):** [Prototipo-Etapa0.html](prototipo/Prototipo-Etapa0.html) — HTML autocontenido (doble clic) con el flujo real del Discovery 6-jul: Jira → cotización BIND → prefactura → validación humana → CFDI → envío por cliente + cobranza y bitácora. Marca Balam (café/amarillo, Poppins), datos ficticios. Para validar con Ara, Arturo y Pedro. |
## 3. Datos clave ## 3. Datos clave
@@ -42,9 +43,9 @@ Plataforma web para centralizar y automatizar **facturación y cobranza** de Bal
**Comunicación:** canal de WhatsApp (ágil) + correo para evidencia formal. Gestión de avances en Jira. **Comunicación:** canal de WhatsApp (ágil) + correo para evidencia formal. Gestión de avances en Jira.
## 4. Alcance y comercial (propuesta v1.1) ## 4. Alcance y comercial (propuesta v1.2)
- **MVP Fase 1:** integración BIND vía API · **emisión de facturas MXN (con IVA) / USD (sin IVA)** con dry-run + confirmación humana (timbra el PAC de BIND) · catálogo de clientes + lista blanca configurable (ACUNTIA + Top 3) · cobranza operativa (aging + alertas internas) · dashboard · reportes CSV/XLSX · bitácora · multimoneda con TC DOF. - **MVP Fase 1:** integración BIND vía API · **emisión de facturas MXN (con IVA) / USD (sin IVA)** con dry-run + confirmación humana (timbra el PAC de BIND) · catálogo de clientes + lista blanca configurable _(al 6-jul: vacía — Ara decidió recordatorios a todos, sin excepciones)_ · cobranza operativa (aging + alertas internas) · dashboard · reportes CSV/XLSX · bitácora · multimoneda con TC DOF. **Flujo objetivo validado en Discovery (6-jul):** Jira (disparador) → **cotización BIND (obligatoria)** → prefactura → validación humana → CFDI → envío.
- **Inversión:** **$67,200 $81,600 MXN + IVA** · **67 semanas** (~20 h/sem) · tarifa **$600 MXN/h** · modelo Time & Materials con tope por etapa (monto final se confirma en Discovery). - **Inversión:** **$67,200 $81,600 MXN + IVA** · **67 semanas** (~20 h/sem) · tarifa **$600 MXN/h** · modelo Time & Materials con tope por etapa (monto final se confirma en Discovery).
- **Sin anticipo** (política Balam): se factura la **Etapa 0 (30 h, $18,000 + IVA)** al inicio. Arranque condicionado a **contrato firmado**. - **Sin anticipo** (política Balam): se factura la **Etapa 0 (30 h, $18,000 + IVA)** al inicio. Arranque condicionado a **contrato firmado**.
- **Pagos:** a **30 días** post-factura. Por contrato, **facturación semanal (viernes)** por horas efectivamente trabajadas (la Etapa 0 puede facturarse al inicio). - **Pagos:** a **30 días** post-factura. Por contrato, **facturación semanal (viernes)** por horas efectivamente trabajadas (la Etapa 0 puede facturarse al inicio).
@@ -67,15 +68,23 @@ Plataforma web para centralizar y automatizar **facturación y cobranza** de Bal
| 2026-06-26 | **Contrato FIRMADO** por Johann. Se agregan 2 ajustes finales: **pago de horas al terminar** y **aceptación a 10 días naturales** (correcciones sobre alcance). | | 2026-06-26 | **Contrato FIRMADO** por Johann. Se agregan 2 ajustes finales: **pago de horas al terminar** y **aceptación a 10 días naturales** (correcciones sobre alcance). |
| 2026-06-29 | **Arranque de ejecución:** Erika pide el **plan de actividades con fechas** (Etapa 0 y 1). Bloqueador: que Balam entregue los **accesos**. | | 2026-06-29 | **Arranque de ejecución:** Erika pide el **plan de actividades con fechas** (Etapa 0 y 1). Bloqueador: que Balam entregue los **accesos**. |
| 2026-06-30 | **Plan de actividades (4 etapas) entregado.** Kickoff con Noé agendado (1-jul, 7am). Erika = intermediaria de sesiones; tablero Kanban en Jira. | | 2026-06-30 | **Plan de actividades (4 etapas) entregado.** Kickoff con Noé agendado (1-jul, 7am). Erika = intermediaria de sesiones; tablero Kanban en Jira. |
| 2026-07-01 | **Kickoff realizado.** BIND: **token de Arturo** (solo consulta, se prueba primero); **Balam crea el repo** (GitHub privado) y **gestiona Azure** (Pedro+Noé); horas de Johann en **Jira** (corte lunes de Erika); Discovery **con Arturo + Araceli**. **Manual de marca recibido.** Abierto: **vincular la factura de 30 h** (contrato vs propuesta) antes de emitir — Johann espera correo de Balam. |
| 2026-07-02 | **Propuesta v1.2 enviada por correo** (30 h de facturación inicial explícitas, condiciones comerciales en §3.3). En espera de confirmación para facturar. |
| 2026-07-06 | **Discovery #1 realizado (proceso de facturación).** Flujo mapeado: Jira ITSM mandatorio → prefactura BIND → CFDI → envío por correo con particularidades por cliente. **Lista blanca ELIMINADA** (recordatorios a todos — decisión de Ara) y **cotización BIND obligatoria** como inicio del flujo. Validaciones de oro: PPD default (requerimiento SAT previo por PUE erróneo), IVA 16%/0% manual en BIND. Volumen real: ~55 facturas/mes de 46 clientes. Pendiente de Balam: Excel de particularidades de envío. |
| 2026-07-07 | **Discovery de cobranza completado.** Aging por factura, conciliación por folio, diferencias por fee y pagos registrados manualmente por el despacho. |
| 2026-07-10 | **Prototipo Etapa 0 entregado** por correo; Balam lo revisa internamente. |
| 2026-07-13 | Johann inicia trabajo local de Etapa 1 sin esperar la validación visual. La factura de 30 h sigue pendiente de visto bueno. |
| 2026-07-14 | Sesiones confirmadas: reglas/dudas Etapa 1 el 22-jul y validación del prototipo el 23-jul. |
| 2026-07-15 | Noé autoriza el repositorio privado de GitHub; invitación pendiente para `Johann-28`. Se inicia control local de horas. |
## 6. Próximos pasos ## 6. Próximos pasos
Ver detalle y responsables en [bitacora/PENDIENTES.md](bitacora/PENDIENTES.md). En corto: Ver detalle y responsables en [bitacora/PENDIENTES.md](bitacora/PENDIENTES.md). En corto:
1. **Kickoff con Noé — mié 1-jul, 7am** (arranque del proyecto). 1. **Johann:** continuar backend local y publicar en cuanto llegue la invitación al repo.
2. **Balam:** entregar los **accesos** (API BIND vía ARA, Azure con Guajardo/Erika, manual de marca de Pedro) y reglas/bancos con Arturo. **Bloqueador del arranque.** 2. **Johann:** validar el corte reconstruido de 30 h en [`Seguimiento-horas.csv`](planeacion/Seguimiento-horas.csv), capturar diariamente en adelante y conciliar con Jira cuando Pedro habilite el flujo.
3. **Johann:** cambiar régimen fiscal y confirmar permisos de Azure. 3. **Johann:** preparar la sesión del 22-jul (alta de cliente, fee, envíos y alcance Jira→BIND) y la validación del prototipo del 23-jul.
4. **Johann:** arrancar el **Discovery** (Etapa 0) la semana del 6-jul, en cuanto lleguen los accesos. 4. **Balam:** completar repo, Azure, Excel de particularidades de envío y confirmación para emitir la factura de 30 h.
5. **Erika:** coordina sesiones (Discovery, reglas con Arturo) y el tablero Kanban en Jira. 5. **Johann/Balam:** cerrar explícitamente qué pertenece al MVP: Jira automático, recordatorios externos y escritura en BIND.
## 7. Riesgos / puntos abiertos ## 7. Riesgos / puntos abiertos
@@ -83,3 +92,5 @@ Ver detalle y responsables en [bitacora/PENDIENTES.md](bitacora/PENDIENTES.md).
- **Conciliación**: depende de procesar PDFs bancarios (sin API directa) + involucrar a Arturo. - **Conciliación**: depende de procesar PDFs bancarios (sin API directa) + involucrar a Arturo.
- **Solapamiento dashboard** con el Power BI existente de Pedro. - **Solapamiento dashboard** con el Power BI existente de Pedro.
- **Límite de API BIND** (1 llave por usuario, 20K req/día) → documentar llaves y monitorear consumo. - **Límite de API BIND** (1 llave por usuario, 20K req/día) → documentar llaves y monitorear consumo.
- **Integración Jira→BIND no incluida explícitamente:** requiere decisión de alcance, cuenta técnica de Jira, mapeo de campos y escritura autorizada en BIND.
- **Horas históricas reconstruidas:** corte de 30 h distribuido por actividad; solo 3.08 h tienen duración documental directa. Johann debe validar las otras 26.92 h antes de facturar.
-722
View File
@@ -1,722 +0,0 @@
# Arquitectura Técnica — Plataforma Balam
Este documento es la decisión técnica que sostendrá el proyecto. Está pensada para:
1. Permitir entregar el MVP en **6 semanas (medio tiempo, ~120 h)**.
2. **Escalar sin re-escribir** cuando se agreguen nuevos módulos, clientes o cuando se decida comercializar como producto SaaS.
3. Ser comprensible por otro desarrollador si hay que sumar gente.
## Posicionamiento
La plataforma es una **capa de operaciones financieras encima de BIND ERP**, no un reemplazo. El sistema de verdad para emisión de CFDI y contabilidad sigue siendo BIND (que ya tiene PAC integrado). Lo que falta y aporta valor:
- Cobranza con reglas (lista blanca, recordatorios automáticos, templates)
- Conciliación bancaria sobre PDFs (Banorte/BBVA/IBC Texas)
- Dashboard consolidado de CxC
- Pagos con link (Stripe)
- Alertas y reportes programados
## Visión end-to-end (el horizonte que persigue la arquitectura)
El equipo directivo (CEO/CFO/CTO) describió un ciclo financiero completamente desconectado: nómina, facturación, cobranza, conciliación y contabilidad pasan por manos distintas y cada handoff cuesta dinero. El MVP **no resuelve todo el ciclo**, pero la arquitectura se diseña para llegar a él sin reescribir:
```
Fase 2-3 (futuro) MVP (lo que construimos en 6 semanas)
────────────────── ────────────────────────────────────
Jira (horas) ┌─ Cobranza
│ │
▼ │
BUK (nómina) ┌─ BIND (facturación) ─────┼─ Conciliación
│ │ │ (PDF + IA)
▼ │ │
Plataforma ───trigger──>│ ├─ Dashboard
(auto-factura) │ │
└─ BIND (asientos) <────────┴─ Pago con link
(Stripe)
```
**Cómo el MVP prepara la visión completa:**
| Capacidad futura | Qué construye el MVP que la habilita |
|---|---|
| Trigger de factura desde nómina (BUK) | Outbox pattern + worker — basta agregar un handler `nomina.approved` |
| Ingesta de horas desde Jira | Schema multi-fuente para facturas (origen ya tipificado) |
| Generación automática de asiento contable contra BIND | Motor de reportería con mapeo evento → asiento ya existe; falta solo conector BIND |
| Banco en vivo (Belvo / Plaid) | Schema `statement_line` agnóstico a fuente; pipeline de Claude API es reemplazable sin tocar conciliación |
| Anomalía con IA / agentes | Stream de eventos del outbox alimenta cualquier consumidor IA en Fase 2 |
| Multi-tenant comercial | `tenant_id` + RLS desde día 1 — solo falta onboarding self-service |
**Por eso el MVP, aunque acotado, es estratégico:** entrega valor operativo en 6 semanas y abre el camino al ciclo completo sin deuda técnica.
```
┌─────────────────────────────────────────────┐
│ Plataforma Balam (nueva) │
│ Cobranza · Dashboard · Conciliación · Pago │
└──────┬───────────────┬───────────────┬──────┘
│ import │ export │ webhook
│ (archivo) │ (archivo) │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ BIND │ │ BIND │ │ Stripe │
│ (facturas│ │ (asientos│ │ (pago) │
│ + PAC) │ │ + ERP) │ └──────────┘
└──────────┘ └──────────┘
┌──────────┐
│ Claude │
│ API │
│ (parsing │
│ PDFs) │
└────▲─────┘
┌────┴─────┐
│ PDFs de │
│ 3 bancos │
└──────────┘
```
## MVP vs diseño completo
El diseño descrito en este documento es la **arquitectura objetivo**, calibrada para soportar todo el roadmap (incluyendo Fase 2). El MVP de 6 semanas a medio tiempo construye los cimientos completos pero **no implementa todos los módulos**:
| Componente | MVP (6 sem · medio tiempo) | Fase 2 |
|---|---|---|
| Auth, RBAC, audit log | ✅ | — |
| Multi-tenancy en schema (`tenant_id` + RLS) | ✅ | onboarding self-service |
| Import de catálogo + facturas desde BIND (archivo) | ✅ | API en vivo |
| **Emisión de CFDI desde la plataforma** | ❌ (BIND lo hace) | sólo si se valida necesidad |
| Multimoneda visualización | ✅ MXN + USD | EUR |
| Cobranza + recordatorios + lista blanca configurable | ✅ | — |
| **Pago con link (Stripe Checkout + webhook)** | ✅ | domiciliación / recurrentes |
| Dashboard CxC | ✅ básico | cash-flow 30/60/90 |
| **Banca: import de PDFs + parsing con Claude API** | ✅ | Belvo / Plaid en vivo |
| Conciliación: match exacto + por alias | ✅ | scoring difuso completo |
| Detección de anomalías | ⚠️ solo duplicados + traspasos | z-score, vendor nuevo, horarios |
| Reporte para asientos contables (Excel para BIND) | ✅ | API en vivo |
| Outbox pattern + eventos | ✅ | — |
| Agentes IA / LLM operativos | ❌ | ✅ |
| Portal cliente / móvil | ❌ | ✅ |
| Integración BUK | ❌ | ✅ cuando exponga API |
**Por qué este recorte:** la arquitectura modular y event-driven permite agregar Fase 2 sin tocar lo entregado. El MVP demuestra valor con el mínimo viable; las decisiones de qué invertir en Fase 2 se toman con datos de uso real, no a priori.
## Constraint operativo: sin sandboxes
BIND y BUK solo cuentan con producción. Esto se mitiga así:
1. **La plataforma no escribe a BIND en MVP.** El flujo es estrictamente: BIND exporta → plataforma importa → plataforma exporta para que el contador suba manualmente. Ninguna operación tuya puede corromper BIND.
2. **Modo dry-run** disponible en cualquier acción con efecto externo (envío de correos, generación de links Stripe), con preview obligatorio antes de confirmar.
3. **Snapshots automáticos** de la base de datos antes de cualquier import masivo desde BIND.
4. **Audit log** registra el actor (humano o sistema), la acción, y el delta. Reversible en <5 min para operaciones internas.
---
## 1. Principios rectores
| Principio | Implicación |
|---|---|
| **Modular monolito > microservicios** | Empezamos con un solo despliegue, módulos con fronteras claras. Microservicios sólo si el volumen lo justifica. |
| **Boring tech** | PostgreSQL, TypeScript, Node, React. Nada exótico. |
| **Eventos internos desde día 1** | El core publica eventos (`invoice.issued`, `payment.received`); los módulos reaccionan. Eso permite agregar módulos nuevos sin tocar los existentes. |
| **Multi-tenancy desde el esquema** | `tenant_id` en todas las tablas (aunque por ahora exista un solo tenant). Cuando llegue el momento de vender el producto, no hay que rehacer la DB. |
| **Audit log universal** | Todo cambio en entidades financieras se registra (quién, qué, cuándo, antes/después). Cumple RNF-06 y es vital para fiscal. |
| **Idempotencia en integraciones** | Webhooks, jobs y endpoints externos siempre con `idempotency_key`. Evita facturas duplicadas o pagos repetidos. |
| **Failure isolation** | Un error en conciliación nunca tira la facturación. Workers separados, colas independientes. |
---
## 2. Stack recomendado
### Backend
- **Lenguaje:** TypeScript (Node.js 22 LTS)
- **Framework:** NestJS *o* Fastify + tRPC
- NestJS si esperamos sumar devs (estructura opinionada, fácil onboarding)
- Fastify + tRPC si seguiré solo (más ligero, mejor DX con frontend)
- **Recomendación: NestJS** — pensando en futura comercialización + onboarding
- **ORM:** Prisma (migraciones, tipos, ergonomía)
- **Validación:** Zod (compartida entre front y back)
- **Auth:** Better-auth o Auth.js (autohospedado, sin lock-in)
### Frontend
- **Framework:** Next.js 15 (App Router)
- **UI:** shadcn/ui + Tailwind v4
- **Data fetching:** TanStack Query
- **Tablas / data grids:** TanStack Table
- **Charts:** Recharts o Tremor (Tremor está pensado para dashboards financieros)
- **Forms:** React Hook Form + Zod
### Datos
- **Primaria:** PostgreSQL 16
- **Cache / Queue:** Redis 7 (BullMQ para jobs)
- **Object storage:** S3 / R2 (XML/PDF de facturas, estados de cuenta)
### Infra (Azure por preferencia del cliente)
- **App + Worker:** Azure App Service (Linux, plan B2 inicial)
- **Base de datos:** Azure Database for PostgreSQL Flexible Server
- **Storage:** Azure Blob Storage (PDFs bancarios cifrados en reposo)
- **Cache / Queue:** Azure Cache for Redis (Basic) o Upstash Redis serverless si el costo de Azure Redis no se justifica
- **Observabilidad:** Sentry (errores) + Application Insights (logs/métricas integrado a Azure) + uptime monitoring externo
- **CI/CD:** GitHub Actions con deploy a Azure App Service
- **Secretos:** Azure Key Vault
### Calidad
- **Tests:** Vitest (unit) + Playwright (E2E críticos)
- **Lint/Format:** Biome (rápido, reemplaza ESLint + Prettier)
- **Types:** TypeScript strict en todo
- **Pre-commit:** Lefthook
### Integraciones obligatorias en MVP
- **Import de archivos BIND** (formato CSV/Excel a confirmar en Fase 0)
- **Parsing de PDFs bancarios:** Claude API (Anthropic) — un pipeline por banco
- **Pago con link:** Stripe Checkout + Webhook
- **Tipo de cambio:** API del DOF (Banxico) + cache diario
- **Email transaccional:** Resend (DX excelente) o Postmark
### Integraciones diferidas a Fase 2
- PAC propio (solo si Balam decide emitir CFDI desde la plataforma — hoy lo hace BIND)
- Agregador bancario MX: Belvo o Finerio Connect (reemplaza upload manual de PDFs)
- Banco US: Plaid o scraping autorizado del portal IBC
- BUK API (cuando exista)
- Conector contra BIND vía API (cuando exista)
---
## 3. Estructura del repositorio (monorepo)
```
balam/
├── apps/
│ ├── web/ # Next.js (frontend)
│ ├── api/ # NestJS (backend HTTP)
│ └── worker/ # Procesos en background (BullMQ)
├── packages/
│ ├── db/ # Prisma schema + migraciones + tipos
│ ├── core/ # Lógica de dominio compartida
│ ├── contracts/ # Schemas Zod compartidos front/back
│ ├── integrations/ # Clientes para PAC, bancos, etc.
│ └── ui/ # Componentes shadcn customizados
├── docs/ # ADRs, runbooks, manuales
└── infra/ # IaC mínimo, scripts de deploy
```
Gestor: **pnpm workspaces** + **Turborepo** para caché de builds.
---
## 4. Modelo de datos (núcleo)
Diagrama lógico simplificado:
```
tenant ─┬─ user ──── role
├─ customer ─┬─ invoice ──┬─ invoice_line
│ │ └─ cfdi_xml
│ └─ contact
├─ bank_account ─┬─ bank_statement ── statement_line
│ └─ reconciliation_match
├─ payment ─── payment_allocation (M-N con invoice)
├─ exchange_rate (DOF diario)
├─ accounting_entry ─── entry_line
├─ event (event sourcing ligero / outbox)
├─ audit_log
└─ notification (recordatorios enviados, blacklist)
```
**Reglas duras del modelo:**
- Toda tabla financiera tiene: `id`, `tenant_id`, `created_at`, `updated_at`, `created_by`, `updated_by`.
- Montos siempre en **decimal(18,4)** + columna `currency` ISO 4217. **Nunca** `float`.
- Fechas en UTC en DB, presentación en CST/MX.
- Soft delete con `deleted_at` en entidades editables; **hard delete prohibido** en facturas/pagos (cancelación lógica).
- `idempotency_key` único por tenant en endpoints de creación masiva.
---
## 5. Arquitectura de capas
```
┌─────────────────────────────────────────────┐
│ Frontend Next.js (Dashboard, Forms) │
└──────────────────┬──────────────────────────┘
│ HTTPS + JWT/Session
┌──────────────────▼──────────────────────────┐
│ API NestJS (REST + tRPC opcional) │
│ ├── Auth & RBAC │
│ ├── Controllers / Resolvers │
│ └── Application Services │
└──────┬─────────────────────┬────────────────┘
│ │
│ publish events │ enqueue jobs
▼ ▼
┌──────────────┐ ┌─────────────────────────┐
│ Event Bus │ │ Worker (BullMQ) │
│ (outbox tbl) │ │ ├── invoice timbrado │
└──────┬───────┘ │ ├── bank sync (cron) │
│ │ ├── reconciliation │
▼ │ ├── reminders (cron) │
┌──────────────┐ │ └── reports │
│ Modules │ └────────┬────────────────┘
│ reaccionan │ │
└──────┬───────┘ │
│ │
▼ ▼
┌─────────────────────────────────────────────┐
│ Domain Services + Repositories (Prisma) │
└──────────────────┬──────────────────────────┘
┌─────────────────────────────────────────────┐
│ PostgreSQL + Redis + S3 │
└─────────────────────────────────────────────┘
▲ ▲ ▲
│ │ │
┌──────┴──────────────┴──────────────┴────────┐
│ Integraciones externas (clientes) │
│ BIND (archivo) · Claude API · Stripe · DOF · Email │
└─────────────────────────────────────────────┘
```
---
## 6. Patrón Event-Driven (clave para escalar)
Tabla `event` (outbox pattern):
```sql
CREATE TABLE event (
id uuid PRIMARY KEY,
tenant_id uuid NOT NULL,
type text NOT NULL, -- 'invoice.issued', 'payment.received'
payload jsonb NOT NULL,
aggregate_id uuid NOT NULL, -- id de la entidad afectada
occurred_at timestamptz NOT NULL,
processed_at timestamptz,
attempts int DEFAULT 0
);
```
**Flujo:** Cuando se emite una factura, en la misma transacción se inserta un evento `invoice.issued`. Un worker lee la tabla y dispara handlers: enviar email al cliente, generar asiento contable, programar recordatorio de cobro.
**Por qué importa:** mañana cuando agreguen "notificar a Slack al timbrar", se agrega un handler sin tocar el código de facturación. Ese es el diseño que les va a encantar — no porque lo digan, sino porque verán que pedir cambios es barato.
---
## 7. Módulos del sistema (bounded contexts)
### 7.1 Identity & Access (`identity`)
- Users, tenants, roles, permissions
- Sesiones, MFA opcional (recomendado para finanzas)
- Audit log
### 7.2 Catálogo (`catalog`)
- Customers (con flag `is_strategic`, `auto_reminder_enabled`)
- Products/Services
- Tax regimes, payment methods (catálogos SAT)
### 7.3 Sincronización con BIND (`bind-sync`)
- Importador de archivo de BIND (clientes, facturas, productos, catálogo de cuentas)
- Dedupe por id externo (UUID del CFDI o id de BIND)
- Visualización multimoneda con snapshot de TC al momento de la factura
- Modo dry-run para previsualizar deltas antes de aplicar
- Sincronización programada o manual
### 7.4 Cobranza (`collections`)
- Estados de factura derivados de BIND + pagos locales
- Motor de recordatorios (cron + templates editables)
- Lista blanca: clientes con `auto_reminder_enabled=false` jamás reciben (ACUNTIA + Top 3 — configurable)
- Tracking de comunicaciones enviadas
### 7.5 Pagos (`payments`)
- Stripe Checkout: generación de link por factura
- Webhook receiver: marca factura como pagada al confirmar
- Soporte tarjeta + SPEI
- Conciliación lista para pagos directos por banco (no via Stripe) en módulo banking
### 7.6 Banca (`banking`)
- Upload de PDFs (Banorte/BBVA/IBC) por usuario
- Pipeline de extracción con Claude API + validación de totales
- Almacenamiento de statement_lines con dedupe por hash
- (Fase 2: conexiones a Belvo / Plaid)
### 7.7 Conciliación (`reconciliation`)
- Motor de matching con scoring (exacto → alias → cola humana)
- Detección de duplicados y traspasos internos
- (Fase 2: detección avanzada de anomalías, z-score, etc.)
### 7.8 Reportería (`reporting`)
- Dashboard tiempo real (CxC, vencidas, próximas a vencer)
- Reportes programables (diario/semanal por email)
- Export para BIND: pagos conciliados + movimientos clasificados en Excel/CSV
### 7.9 Alertas (`notifications`)
- Email, en-app
- Configurables por usuario y por evento
---
## 8. Seguridad y compliance
### Obligatorio desde día 1
- TLS everywhere (Let's Encrypt vía proxy)
- Secrets en variables de entorno cifradas, nunca en el repo
- Cifrado en reposo de PostgreSQL (Railway/Fly lo proveen)
- Cifrado a nivel campo para datos sensibles (credenciales bancarias, tokens de agregadores) usando `pgcrypto`
- Bcrypt para passwords (Argon2 si Better-auth lo permite)
- Rate limiting en endpoints públicos
- CORS estricto
- Headers de seguridad (helmet)
- Validación Zod en cada entrada
- RBAC granular por módulo y acción
### Mexicano-específico
- Emisión y sello digital del CFDI: **lo maneja BIND con su PAC integrado**; la plataforma no toca el SAT en MVP
- Almacenamiento de XML/PDF de facturas en Blob Storage (referenciado por id de BIND) — por **5 años** según SAT
- Bitácora de cancelaciones espejo (motivo + UUID sustituto) sincronizada desde el export de BIND
- Tipos de cambio del DOF para reportería interna
### Texas (banco US)
- Si hay operación contable real en Texas, revisar requerimientos con contador (no asumir).
- Para el MVP, tratamos las cuentas US como cuentas bancarias normales en USD.
---
## 9. Estrategia de tipo de cambio
- Cache diario en tabla `exchange_rate` desde API de Banxico (DOF FIX)
- Al emitir factura USD, se "fija" el TC del día en la factura
- Para conciliación de pagos USD a facturas MXN: regla configurable (TC del día del pago o del día de la factura)
- Pérdidas/ganancias cambiarias se registran como asientos automáticos
---
## 10. Pipeline de extracción de PDFs bancarios
Los 3 bancos entregan estados de cuenta como PDF (Banorte, BBVA, IBC Bank Texas). No hay CSV/API disponibles. La estrategia:
```
Upload PDF ──> Almacenar en Blob ──> Job en cola ──> Pipeline por banco
┌───────────────┼───────────────┐
▼ ▼ ▼
pdfplumber/ Claude API Validación
pdftotext extracción (totales,
(texto) estructurada duplicados,
→ JSON formato)
statement_line[]
hash + dedupe + persist
```
**Decisiones clave:**
1. **Texto primero, modelo después.** Se extrae texto con `pdfplumber` (Python) o `pdf-parse` (Node) y se pasa el texto plano a Claude. Más barato y rápido que mandar el PDF binario.
2. **Un prompt por banco**, versionado. Cada prompt incluye: ejemplos few-shot, schema JSON esperado, instrucciones de manejo de saltos de página y casos borde.
3. **Validación automática post-extracción:**
- Suma de movimientos == saldo final - saldo inicial (con tolerancia mínima)
- Cantidad de movimientos == lo que el resumen del PDF indica
- Si validación falla → flag manual review, no se inserta
4. **Schema único** para `statement_line` (independiente de banco):
```
{ fecha, monto, tipo: 'cargo'|'abono', concepto, referencia, saldo_post, hash }
```
5. **Hash de dedupe:** `sha256(banco_id + fecha + monto + concepto)`. Re-upload del mismo PDF es idempotente.
6. **Costo aproximado:** 50 facturas/mes → ~3 PDFs/mes × ~20 páginas × ~1500 tokens/pág × $3/MTok input + $15/MTok output. **~$2-8 USD/mes** total. Despreciable.
7. **Privacidad:** Anthropic API por default no entrena con datos del cliente (Zero Data Retention disponible bajo enterprise agreement si se requiere). Documentado en supuesto §11 de la propuesta.
8. **Migration path:** cuando en Fase 2 se conecte Belvo, el `statement_line` schema no cambia. Solo cambia la fuente. Mismo motor de conciliación reutilizable.
**Por qué Claude API y no parsers hardcoded:**
- Los bancos cambian formato sin avisar. Un parser regex se rompe; Claude tolera variaciones.
- IBC Texas tiene formato muy diferente a los bancos MX. Reutilizar prompts es trivial; reutilizar regex no.
- Tiempo de implementación: ~3-4 h por banco con Claude vs. 8-12 h por banco con parser custom + tests.
## 11. Estrategia de conciliación (corazón del proyecto)
Algoritmo en cascada (mayor a menor confianza):
1. **Match exacto:** monto idéntico + referencia/UUID en concepto + ±3 días → auto-match
2. **Match alto:** monto idéntico + cliente identificable por patrón en concepto + ±7 días → auto-match con flag de revisión
3. **Match medio:** monto en ventana ±2% + cliente identificable → cola de revisión humana
4. **Sin match:** se guarda en `unmatched_statement_line`, dashboard de pendientes
**Cliente identificable por patrón:** usar regex / fuzzy match contra alias del cliente (`Banorte` puede llegar el pago como "BANORTE SA", "BNTE", etc. — armar tabla `customer_alias`).
**Anomalías detectables sin IA:**
- Gasto que excede 2σ del promedio mensual de esa categoría
- Cargo duplicado (mismo monto + mismo concepto + ventana 5 días)
- Cargos en horarios atípicos (madrugada, fines de semana si la empresa no opera)
- Vendor nuevo (no aparece en los últimos 6 meses)
Esto es robusto, explicable y gratis. **La IA se agrega en v2** sobre estos cimientos, no como reemplazo.
---
## 12. Multi-tenancy: ahora vs después
**Ahora (MVP):**
- `tenant_id` en todas las tablas
- Row-level security en PostgreSQL (RLS) con policies por tenant
- Un solo tenant en producción (Balam)
**Después (comercialización):**
- Onboarding self-service
- Plan/billing del SaaS
- Aislamiento de archivos por tenant en S3
Costo de incluir `tenant_id` ahora: <5% del esfuerzo. Costo de agregarlo después: rewrite parcial. **Por eso se hace desde día 1.**
---
## 13. Testing strategy
| Tipo | Cobertura objetivo | Herramienta |
|---|---|---|
| Unit (lógica de dominio: cálculos, reglas) | >90% | Vitest |
| Integration (servicios + DB) | rutas críticas | Vitest + Testcontainers |
| E2E (flujos críticos UI) | 5-8 flujos | Playwright |
| Contract (mocks de PAC, Belvo) | endpoints integrados | MSW |
**Flujos E2E obligatorios:**
1. Crear cliente → emitir factura MXN → timbrar → descargar PDF
2. Emitir factura USD a cliente extranjero (sin IVA)
3. Importar movimiento bancario → conciliar manualmente → ver pago aplicado
4. Conciliación automática end-to-end con datos sintéticos
5. Enviar recordatorio que respeta lista blanca (cliente Top 3 no recibe)
---
## 14. Plan de despliegue
- `main` → producción (deploy automático tras CI verde + aprobación manual)
- `develop` → staging (deploy automático)
- Feature branches → preview environments (Railway lo soporta)
- Rollback en <2 min vía Railway dashboard
**Migraciones:**
- Siempre backward-compatible (expand → migrate → contract)
- Backup automático antes de cada migración productiva
- Migraciones revisadas manualmente, nunca destructivas en hot-path
---
## 15. Observabilidad mínima
- **Sentry:** errores no manejados, performance de queries lentas
- **Better Stack / Axiom:** logs estructurados (cada request, cada job)
- **Métricas:** dashboard interno con (a) facturas/día, (b) pagos conciliados auto vs manual, (c) jobs fallidos, (d) latencia p95
- **Alertas a tu correo/Slack:**
- Job de timbrado falla
- Sync bancario sin éxito por >4 hrs
- >10 errores en 5 min
- Disco/memoria al 80%
---
## 16. ADRs (Architecture Decision Records)
Llevar `docs/adr/NNNN-titulo.md` con decisiones grandes:
- ADR-0001: Monorepo con pnpm + Turborepo
- ADR-0002: NestJS como framework backend
- ADR-0003: PostgreSQL como única base de datos primaria
- ADR-0004: Multi-tenancy por `tenant_id` desde día 1
- ADR-0005: BIND como fuente de verdad de facturación; plataforma como capa de operaciones
- ADR-0006: Claude API para extracción estructurada de PDFs bancarios (vs parsers hardcoded)
- ADR-0007: Stripe Checkout para pago con link (vs Conekta / MercadoPago)
- ADR-0008: Azure App Service + PostgreSQL Flexible para hosting (vs Railway/Fly)
- ADR-0009: Outbox pattern para eventos internos
Cada ADR: contexto, decisión, alternativas consideradas, consecuencias. Esto vale oro cuando entra el próximo dev (o tú dentro de 6 meses).
---
## 17. Roadmap de evolución (post-MVP)
Priorizado por **acercarse al ciclo end-to-end** que el equipo directivo describió en la llamada original (Jira → BUK → Factura → Cobranza → Conciliación → Asiento):
| Cuándo | Qué | Por qué |
|---|---|---|
| Mes 3-4 | Belvo (MX) en vivo + asientos contables auto contra BIND | Elimina dos cuellos de botella manuales que sobrevivieron al MVP |
| Mes 4-5 | Ingesta de horas Jira → input de facturación + EUR | Habilita el caso de uso #1 del PRD inicial (factura auto desde horas) |
| Mes 5-7 | Integración profunda con BUK (cuando exponga API) — trigger nómina → factura | Cierra el extremo izquierdo del ciclo |
| Mes 7-9 | Domiciliación Stripe, anomalía con IA, portal cliente | Capa de valor agregado sobre el ciclo ya cerrado |
| Mes 9-12 | Multi-tenancy comercial, onboarding self-service, billing del SaaS | Pivote a producto comercializable |
| Año 2 | Marketplace de integraciones (otros PACs, bancos, ERPs) | Crecimiento del producto |
---
## 18. Workflow de desarrollo con Claude Code
El proyecto se desarrolla con **Claude Code** como acelerador. La arquitectura, convenciones y herramientas elegidas en este documento están deliberadamente alineadas con prácticas que **maximizan la calidad del output asistido por IA**: tipos estrictos, módulos con fronteras claras, ADRs versionados, tests como contrato.
### 17.1 Estructura de soporte a la IA (en el repo)
```
.claude/
├── settings.json # permisos de herramientas, hooks
├── skills/ # workflows reutilizables (slash commands)
│ ├── new-module/ # scaffolding de un módulo nuevo
│ ├── new-integration/ # cliente de API externa con tests + retries
│ ├── new-event-handler/ # handler con outbox + tests + idempotencia
│ ├── new-cfdi-test/ # E2E de facturación
│ └── review-pr/ # checklist de revisión antes de merge
├── agents/ # sub-agentes especializados (opcional)
└── memory/ # contexto persistente (decisiones, gotchas)
CLAUDE.md # contexto raíz del proyecto (siempre cargado)
docs/
├── adr/ # decisiones arquitectónicas
├── conventions.md # cómo se nombran cosas, patrones obligatorios
├── domain-glossary.md # vocabulario fiscal/financiero (CFDI, asiento, etc.)
└── integrations/ # docs por integración (Belvo, PAC, BIND)
```
### 17.2 CLAUDE.md raíz (esqueleto)
Este archivo se carga automáticamente en cada sesión. Tiene que ser **corto y duro**:
```markdown
# Balam — Plataforma de Automatización Financiera
## Contexto crítico
Sistema financiero productivo de empresa real. Errores cuestan dinero,
relaciones con clientes y compliance fiscal. Cuidado extremo con:
- Cálculos de impuestos (decimal(18,4), nunca float)
- Idempotencia en endpoints de creación
- Lista blanca de cobranza (ACUNTIA + Top 3 jamás reciben recordatorio auto)
- Cancelación de facturas: lógica, nunca hard delete
- Multi-tenancy: tenant_id en cada query (RLS activo)
## Reglas duras
- TypeScript strict siempre. Nada de `any`.
- Toda mutación financiera escribe a audit_log en la misma transacción.
- Toda integración externa con retry + idempotency_key.
- Tests obligatorios para: cálculo de impuestos, matching de conciliación,
reglas de cobranza, generación de asientos.
- Nunca commitees secretos. Nunca pegues datos reales de Balam en prompts.
## Stack
NestJS + Prisma + PostgreSQL + Redis (BullMQ) + Next.js + shadcn/ui.
Monorepo pnpm + Turborepo. Tests con Vitest + Playwright. Lint con Biome.
## Comandos comunes
- `pnpm dev` — levanta web + api + worker
- `pnpm test` — corre toda la suite
- `pnpm db:migrate` — aplica migración (siempre backward-compatible)
- `pnpm db:seed` — datos sintéticos para desarrollo
- `pnpm typecheck` — valida tipos sin compilar
## Antes de cerrar una tarea
1. `pnpm typecheck && pnpm test && pnpm lint` debe pasar
2. Si tocaste schema, hay migración + rollback verificado
3. Si tocaste lógica financiera, hay test que la cubre
4. Si tocaste integración externa, hay mock + test contra mock
5. PR description explica el "por qué", no solo el "qué"
## Documentos vivos
- Convenciones: docs/conventions.md
- Glosario fiscal: docs/domain-glossary.md
- ADRs: docs/adr/
- Integraciones: docs/integrations/<nombre>.md
```
### 17.3 Slash commands / skills críticos
Cada uno automatiza un workflow repetitivo y enforce las convenciones del proyecto:
| Skill | Qué hace |
|---|---|
| `/new-module <nombre>` | Crea estructura del bounded context (controller, service, repository, schema Prisma, tests, evento outbox) siguiendo el template del proyecto |
| `/new-integration <api>` | Genera cliente con reintentos exponenciales, idempotency, error mapping, mock para tests, y registro en `docs/integrations/` |
| `/new-event-handler <evento>` | Crea handler que lee outbox, es idempotente, registra en audit, y tiene test de retry |
| `/new-cfdi-scenario` | Genera test E2E de Playwright para flujo de facturación específico |
| `/pre-merge-review` | Corre checklist: types + tests + lint + ADR si aplica + migration safety + no secretos |
| `/add-adr <titulo>` | Crea nuevo ADR con template estándar y lo lista en MEMORY |
### 17.4 Sub-agentes (uso disciplinado)
Útiles para tareas paralelizables o que ensucian el contexto principal:
- **`explore`** — buscar dónde se usa una entidad antes de refactorizar
- **`reviewer`** — segunda lectura sobre cambios sensibles (lógica fiscal, seguridad, queries con tenant_id)
- **`integration-debugger`** — investigar fallos contra mocks de APIs externas sin saturar contexto principal
No abuses. Cada subagente cuesta tokens y tiempo de orquestación.
### 17.5 Convenciones que multiplican la productividad de la IA
Todas viven en `docs/conventions.md`:
1. **Nombres explícitos**: `calculateInvoiceTaxesMXN()` mejor que `calc()`. La IA infiere intención del nombre.
2. **Schemas Zod compartidos** en `packages/contracts/`: una fuente de verdad para tipos front/back.
3. **Tests como spec**: cada función pública con test de happy path + edge cases. La IA usa los tests como contrato vivo.
4. **Comentarios solo para "por qué"**, nunca para "qué". Los nombres dicen el qué.
5. **Archivos cortos**: máximo ~300 líneas. Si un archivo crece más, se divide. Mejor para IA, mejor para humanos.
6. **Errores tipados** (`Result<T, DomainError>` o excepciones tipadas), nunca `throw new Error('algo')` genérico.
7. **Una responsabilidad por archivo.** Un servicio, un controller, un schema por archivo.
8. **README por package** con: propósito, entrypoints, ejemplos de uso.
### 17.6 Seguridad operativa con IA
Reglas no negociables:
- **Datos reales de Balam jamás entran a prompts.** Para pruebas se usan datos sintéticos generados con scripts (faker + patrones reales).
- **Credenciales (PAC, Belvo, Plaid, DB) viven en gestor de secretos.** Nunca pegadas en chat ni en `.env` versionado.
- **XMLs de CFDI reales, estados de cuenta, listas de clientes:** no van a IA. Para debugging se trabaja sobre versiones anonimizadas.
- **Hooks de pre-commit** que bloquean: secretos detectados (gitleaks), archivos con extensión `.cfdi` o `.statement`, datos en formato BIND real.
- **Permisos de Claude Code restrictivos** (`.claude/settings.json`): allowlist explícito para Bash; deny en comandos destructivos sin confirmación; no acceso a `/Users/johann/Desktop/Proyectos personales/BALAM/datos-reales/` si esa carpeta llega a existir.
- **Code review pre-merge obligatorio** (humano, mío): la IA propone, yo apruebo. Documentado en commit trail.
### 17.7 Ventaja en velocidad (qué pasa con el presupuesto)
Tareas que **se aceleran 40-60%** con Claude Code:
- Boilerplate de módulos, controllers, schemas
- Generación de tests (sobre todo edge cases que un humano olvidaría)
- Refactor mecánico (renombrar, mover, extraer)
- Migraciones de schema con rollback
- Documentación (ADRs, READMEs, manuales de usuario)
- Mappers y transformaciones de DTOs
- Mocks de APIs externas
Tareas que **NO se aceleran significativamente** (sigue siendo trabajo humano):
- Decisiones de arquitectura
- Discovery y conversaciones con stakeholders
- Debugging de integraciones reales (BIND, bancos)
- Validación con datos reales
- Diseño de UX
- Negociación de cambios de scope
Por eso los rangos de horas siguen incluyendo holgura: Fase 0 y debugging de integraciones no se aceleran; lo que se acelera es el 60% restante del trabajo. Espera caer cerca del **extremo bajo** de cada rango.
### 17.8 Memoria persistente del proyecto (en `.claude/memory/`)
Llevar memorias semánticas pequeñas con `[[links]]` entre ellas. Ejemplos útiles para este proyecto:
- `gotcha-belvo-paginacion.md` — Belvo pagina por cursor, no por offset (descubierto durante Fase 3)
- `gotcha-cfdi-cancelacion.md` — cancelación requiere UUID sustituto si motivo=01 (no para motivos 02-04)
- `gotcha-fxrate-dof.md` — el DOF publica TC del día siguiente a las 18:00 hrs; usar T-1 para facturas mañaneras
- `convention-tenant-id.md` — toda query nueva debe filtrar por tenant_id explícitamente o usar RLS, jamás confiar en aplicación
- `decision-bind-as-source-of-truth.md` — BIND queda como fuente de verdad para facturación y contabilidad; plataforma es capa de operaciones (ver ADR-0005)
Estas memorias hacen que la IA no repita errores y que recuerdes tú mismo las decisiones meses después.
---
## 19. Por qué este diseño les va a gustar (sin que lo digan)
1. **Pedir cambios será barato** — al ser event-driven, sumar comportamiento es un handler, no una cirugía.
2. **Auditable** — cuando finanzas pregunte "¿quién canceló esa factura?", hay respuesta exacta en 5 segundos.
3. **Sin lock-in** — el código es suyo, el hosting es portable, sin SDKs propietarios.
4. **Multi-tenant ready** — el día que decidan vender el producto, no hay rewrite.
5. **Explicable** — cualquier dev puede leer el monorepo y entender qué hace cada módulo en una tarde.
6. **Robusto** — el motor de conciliación funciona sin IA; la IA es mejora, no dependencia.
7. **Respeta lo que ya funciona** — BIND queda como sistema de verdad para facturación y contabilidad. La plataforma orquesta, no reemplaza. Esto reduce riesgo, costo y resistencia al cambio.
8. **Construido con toolchain moderno** — desarrollo asistido por IA con revisión humana, tests exhaustivos y documentación al día. Mismo resultado, menos horas facturadas, mejor mantenibilidad.
-251
View File
@@ -1,251 +0,0 @@
# Plan de Ejecución — Balam MVP (6 semanas · medio tiempo)
Documento interno (tuyo). Mapea las fases de la propuesta a tareas concretas, con desglose de horas y entregables verificables. Sirve para tu seguimiento semanal y para sustentar tus facturas.
---
## Parámetros del proyecto
- **Dedicación:** medio tiempo, ~20 h/semana (flex hasta 25 h en semanas pico)
- **Calendario:** 6 semanas
- **Budget total:** 110 140 horas
- **Tarifa:** 600 MXN/h + IVA
- **Total estimado:** $66,000 $84,000 MXN
## Cómo usar este documento
- Cada fase tiene **tareas atómicas** con estimación de horas (rango).
- Al cerrar una tarea, registra horas reales en columna `real`.
- Si una tarea excede 130% del estimado máximo, **paras y avisas** al cliente antes de continuar.
- Cada fase termina con un entregable demoable + actualización del Linear/Notion.
## Expectativa de horas con Claude Code
Los rangos están calibrados para **caer cerca del extremo bajo** trabajando con Claude Code como asistente. El rango alto es la holgura para sorpresas en:
- Formato del export de BIND (puede ser distinto a lo esperado)
- Parsing de PDFs bancarios (calibración de prompts)
- IBC Bank Texas (formato menos conocido)
- Integración Stripe con flujo de webhook
## Disciplina de scope (crítica a medio tiempo)
Como es un MVP de 6 semanas con una sola persona a medio tiempo, **decir que no es la habilidad más importante**. Default respuesta a "podríamos también...":
> "Buena idea. Lo dejo anotado para Fase 2 para no comprometer la entrega del MVP en 6 semanas."
Cualquier cambio de alcance en mitad de fase requiere Change Request escrito y aprobado.
---
## Fase 0 — Discovery + Setup (Semana 1 · 18-22 h)
| # | Tarea | Min | Max | Real |
|---|---|---|---|---|
| 0.1 | Kick-off con contacto técnico + gerente administrativo | 2 | 2 | |
| 0.2 | Inspección formato de export de BIND (clientes, facturas, catálogo) | 2 | 3 | |
| 0.3 | Recolección y análisis de 2-3 PDFs reales por banco (Banorte/BBVA/IBC) | 2 | 3 | |
| 0.4 | Validación de viabilidad de Claude API sobre los PDFs reales | 1 | 2 | |
| 0.5 | Confirmación de cuenta Stripe MX + revisión de fee structure | 1 | 1 | |
| 0.6 | Setup Azure: App Service + Postgres + Blob Storage + Key Vault | 2 | 3 | |
| 0.7 | Setup repo monorepo + CI/CD con deploy a Azure | 2 | 3 | |
| 0.8 | Setup Claude Code: CLAUDE.md, settings.json, gitleaks pre-commit, skills base | 2 | 2 | |
| 0.9 | docs/conventions.md + domain-glossary.md (vocabulario fiscal CFDI + glosario interno BIND) | 1 | 2 | |
| 0.10 | Recepción y aplicación de manual de marca a maquetas iniciales | 1 | 1 | |
| 0.11 | Documento de supuestos validados + plan refinado de Fases 1-4 + ADRs iniciales | 2 | 2 | |
| **Total Fase 0** | | **18** | **22** | |
**Entregables Fase 0:**
- `docs/discovery.md` con hallazgos
- `docs/supuestos.md` confirmado
- `docs/adr/0001-0009.md`
- Repo + CI/CD + staging Azure accesible
- `CLAUDE.md` + `.claude/` configurado
- Conventions + glosario de dominio
- Plan refinado presentado a stakeholders
---
## Fase 1 — Plataforma + Sincronización con BIND (Semanas 2-3 · 30-38 h)
### Semana 2 (15-19 h)
| # | Tarea | Min | Max | Real |
|---|---|---|---|---|
| 1.1 | Schema Prisma: tenant, user, role, audit_log, exchange_rate | 2 | 3 | |
| 1.2 | Auth (Better-auth) con login email + roles (Finanzas/Dirección/Admin) | 3 | 4 | |
| 1.3 | Layout base frontend (Next.js + shadcn): login, sidebar, branding aplicado | 3 | 4 | |
| 1.4 | Módulo Catálogo: customer + UI de gestión + bandera auto_reminder_enabled | 3 | 4 | |
| 1.5 | Audit log universal (middleware Prisma) | 2 | 2 | |
| 1.6 | Cron diario TC del DOF + cache | 2 | 2 | |
### Semana 3 (15-19 h)
| # | Tarea | Min | Max | Real |
|---|---|---|---|---|
| 1.7 | Schema invoice + invoice_line (espejo de BIND) | 2 | 2 | |
| 1.8 | Importador de archivo BIND: parser + validación + dedupe | 4 | 5 | |
| 1.9 | UI de importación: upload, preview de deltas (dry-run), confirmación | 3 | 4 | |
| 1.10 | Listado de facturas con filtros, búsqueda, drill-down a detalle | 3 | 4 | |
| 1.11 | Snapshot de TC al momento de la factura (display multimoneda MXN/USD) | 1 | 2 | |
| 1.12 | Outbox pattern + worker base (tabla event + handler skeleton) | 2 | 2 | |
| **Total Fase 1** | | **30** | **38** | |
**Entregables Fase 1:**
- Sistema autenticado con branding aplicado
- Importación funcional desde BIND con dry-run
- Listado y consulta de facturas (espejo de BIND) en MXN y USD
- Audit log activo
- Outbox pattern listo para handlers
---
## Fase 2 — Cobranza + Dashboard + Pago con link (Semana 4 · 25-32 h)
| # | Tarea | Min | Max | Real |
|---|---|---|---|---|
| 2.1 | Schema payment + payment_allocation (M-N a facturas) | 1 | 2 | |
| 2.2 | UI de registro manual de pago + asociación (totales y parciales) | 3 | 4 | |
| 2.3 | Template editor para correo de cobranza (markdown + variables) | 2 | 3 | |
| 2.4 | Motor de envío programado (cron + worker idempotente con Resend) | 3 | 4 | |
| 2.5 | UI para configurar lista blanca por cliente | 1 | 2 | |
| 2.6 | Log de comunicaciones enviadas + UI de revisión | 2 | 2 | |
| 2.7 | Stripe Checkout: cliente + generación de link por factura | 3 | 4 | |
| 2.8 | Stripe Webhook: recepción + verificación de firma + marca factura pagada | 3 | 4 | |
| 2.9 | Inclusión del link de pago dentro del email de recordatorio | 1 | 2 | |
| 2.10 | Dashboard v1: CxC total, por cliente, vencidas, próximas a vencer | 3 | 4 | |
| 2.11 | Exportación a Excel/CSV | 1 | 2 | |
| 2.12 | Test E2E: recordatorio respeta lista blanca + link de pago funciona | 2 | 3 | |
| **Total Fase 2** | | **25** | **32** | |
**Entregables Fase 2:**
- Cobranza automatizada con lista blanca
- Pago con link Stripe (tarjeta + SPEI) funcional end-to-end
- Dashboard de CxC operativo
- Exportación a Excel
---
## Fase 3 — Conciliación PDF con Claude API (Semana 5 · 22-28 h)
| # | Tarea | Min | Max | Real |
|---|---|---|---|---|
| 3.1 | Schema: bank_account, bank_statement, statement_line | 1 | 2 | |
| 3.2 | UI de upload de PDF con almacenamiento en Blob | 2 | 3 | |
| 3.3 | Extracción de texto con pdf-parse + pipeline por banco | 2 | 3 | |
| 3.4 | Prompt versionado para Banorte + validación de totales | 2 | 3 | |
| 3.5 | Prompt versionado para BBVA + validación de totales | 2 | 3 | |
| 3.6 | Prompt versionado para IBC Texas + validación de totales | 3 | 4 | |
| 3.7 | Dedupe por hash + persistencia de statement_lines | 1 | 2 | |
| 3.8 | Algoritmo de matching exacto (monto + referencia + ventana fecha) | 3 | 3 | |
| 3.9 | Tabla customer_alias + matching por alias | 2 | 3 | |
| 3.10 | UI cola de revisión humana para no conciliados | 2 | 3 | |
| 3.11 | Detección básica: duplicados + traspasos internos | 2 | 2 | |
| **Total Fase 3** | | **22** | **28** | |
**Entregables Fase 3:**
- Upload + parsing automático de los 3 PDFs bancarios
- Motor de conciliación con auto-match + cola humana
- Detección básica de duplicados y traspasos
---
## Fase 4 — Reportes + Cierre (Semana 6 · 15-20 h)
| # | Tarea | Min | Max | Real |
|---|---|---|---|---|
| 4.1 | Export de pagos conciliados a Excel en formato BIND | 2 | 3 | |
| 4.2 | Reporte mensual CxC + CxP exportable | 2 | 2 | |
| 4.3 | Reportes programados por email (diario / semanal) | 2 | 3 | |
| 4.4 | Endurecimiento seguridad: helmet, rate limit, RBAC granular, MFA opcional | 2 | 3 | |
| 4.5 | Backups automáticos Azure + plan de recuperación documentado | 1 | 2 | |
| 4.6 | Documentación técnica: README, runbook, ADRs finalizados | 2 | 2 | |
| 4.7 | Sesión de capacitación grabada (1.5 h) con contacto técnico + gerente admin | 2 | 2 | |
| 4.8 | Handoff + sesión de cierre con stakeholders | 1 | 1 | |
| 4.9 | Buffer para correcciones finales | 1 | 2 | |
| **Total Fase 4** | | **15** | **20** | |
**Entregables Fase 4:**
- Reportes operativos enviándose automáticamente
- Export para BIND validado por el contador
- Seguridad endurecida
- Documentación y capacitación entregadas
- Sistema en producción operando
---
## Resumen total
| Fase | Min | Max | MXN Min | MXN Max |
|---|---|---|---|---|
| 0 - Discovery + Setup Azure | 18 | 22 | 10,800 | 13,200 |
| 1 - Plataforma + Sync BIND | 30 | 38 | 18,000 | 22,800 |
| 2 - Cobranza + Dashboard + Pago link | 25 | 32 | 15,000 | 19,200 |
| 3 - Conciliación PDF (Claude API) | 22 | 28 | 13,200 | 16,800 |
| 4 - Reportes + Cierre | 15 | 20 | 9,000 | 12,000 |
| **TOTAL** | **110** | **140** | **$66,000** | **$84,000** |
**Tiempo calendario:** 6 semanas medio tiempo (~20 h/semana base, hasta 25 h en pico)
**Tarifa:** 600 MXN/h + IVA
**Facturación:** semanal viernes, pago a 7 días
---
## Capacidad por semana
| Semana | Horas planeadas (max) | Carga |
|---|---|---|
| 1 (Fase 0) | 22 | normal |
| 2 (Fase 1a) | 19 | normal |
| 3 (Fase 1b) | 19 | normal |
| 4 (Fase 2) | 32 | ⚠️ pico (necesita 25-30 h ese semana) |
| 5 (Fase 3) | 28 | ⚠️ alto (necesita 24-28 h ese semana) |
| 6 (Fase 4) | 20 | normal |
> **Semanas 4 y 5 son el pico.** Plan: cargar más horas (25-30/sem) y compensar con semanas 1-3 más relajadas. Si en semana 4 no puedes subir el ritmo, alarma temprana y mueves Stripe (8h) a Fase 2 / Fase 2 post-MVP.
---
## Decisiones de descope si vas tarde
Estas son las palancas, en orden de "primero soltar":
1. **Domiciliación** — ya fuera del MVP, no agregar bajo ningún motivo.
2. **Detección de duplicados/traspasos** (tarea 3.11) — push a Fase 2, ahorra ~2 h.
3. **Reportes programados por email** (tarea 4.3) — push a Fase 2, ahorra ~3 h.
4. **Stripe Webhook automático** (tarea 2.8) — fallback: registro manual de pago al confirmar Stripe en su dashboard, ahorra ~4 h.
5. **IBC Texas** (tarea 3.6) — push a Fase 2, los bancos MX cubren 70% del volumen, ahorra ~4 h.
6. **Multimoneda display** (tarea 1.11) — push a Fase 2 si solo manejan 5 facturas USD/mes, ahorra ~2 h.
Si activas las palancas 1-3 recuperas ~5 h. Si activas 1-5 recuperas ~13 h. **Más allá de eso ya es replantear contrato.**
---
## Reglas de ejecución
1. **Nunca trabajes una hora que no puedas justificar en factura.** Si una tarea está fuera de scope acordado, paras y conversas.
2. **Time-tracking obligatorio** (Toggl o Linear). Horas no registradas son horas regaladas.
3. **Demo cada viernes**, sin excepción.
4. **Loom > reunión.** Para updates de status, 3-5 min de Loom en lugar de pedir reunión.
5. **PRs con descripción larga.** Tu evidencia de trabajo y documentación viva.
6. **CHANGELOG.md** — entrada al cerrar cada fase.
7. **No deployees viernes después de las 4pm.** Bug + fin de semana = pesadilla.
8. **Backup tu propio progreso.** Cliente debe poder retomar con otro dev si te enfermas.
9. **Decir "no" es parte del trabajo.** Cada "podríamos también..." que aceptas en MVP es una hora menos para lo crítico.
10. **Producción es el único ambiente disponible.** Antes de cualquier export o sync con BIND: dry-run + confirmación explícita + snapshot DB.
---
## Señales tempranas
**Va bien:**
- Stakeholder responde dudas en <24 hrs
- Las demos generan ajustes pequeños, no replanteos
- Las horas reales caen cerca del medio del rango
- Aparecen requests de Fase 2 (señal de que confían en ti)
**Alerta (paras y conversas):**
- Stakeholder no contesta más de 3 días → bloqueador serio
- El export de BIND llega en formato distinto al esperado en Fase 0 → cotizar workaround
- Claude API no extrae con calidad suficiente algún PDF → reevaluar approach (fallback: parser híbrido para ese banco)
- Stripe rechaza la cuenta Balam o tarda en validar → bloquea Fase 2.7-2.9
- Llegas a viernes de semana 3 sin Fase 1 cerrada → renegocia scope **ese viernes**, no la semana siguiente
-359
View File
@@ -1,359 +0,0 @@
# Guía operativa — Stakeholders, llamadas y decisiones por fase
Documento de referencia personal para el proyecto **Balam · Plataforma de Automatización Financiera (MVP 6 semanas)**.
Sirve para:
1. **Antes de arrancar** — preparar la llamada con el CTO para validar supuestos críticos.
2. **Durante el proyecto** — saber a quién acercarte en cada fase y para qué decisión exacta.
3. **Detectar bloqueadores temprano** — si la persona indicada no responde, sabes qué riesgo se materializa.
> Compañeros de este documento:
> - `00 - PROPUESTA-COMERCIAL.md` — alcance comprometido y supuestos firmados
> - `01 - ARQUITECTURA-TECNICA.md` — módulos y decisiones técnicas
> - `02 - PLAN-EJECUCION.md` — tareas atómicas y horas por fase
---
## Cómo usar este documento
- **Sección 1**: lectura inicial. El mapa de stakeholders + diagrama es el modelo mental que cargas en la cabeza durante todo el proyecto.
- **Sección 2**: consulta semanal. Cada lunes de una nueva fase, revisa las tablas para confirmar que ya tienes las respuestas que vas a necesitar esa semana.
- **Sección 3**: consulta pre-llamada CTO. Antes de la llamada de pre-arranque (todavía no estás en Fase 0).
- **Sección 4**: chequeo mensual de salud — si ves anti-patrones, paras y conversas con el contacto técnico.
---
# Sección 1 · Mapa de stakeholders por fase
## 1.1 Quién decide qué
| Stakeholder | Decide / valida | Pregúntale **antes** de tocar |
|---|---|---|
| **CEO** | Visión, qué clientes son intocables, scope cuando hay conflicto entre áreas | Cualquier decisión que toque relación con cliente estratégico (lista blanca, tono de cobranza) |
| **CFO** | Reglas fiscales y contables, ciclos de cobranza, política de pagos, métricas financieras, validación de reportes | Templates de cobranza, dashboard, tolerancias de conciliación, export para contabilidad |
| **CTO** | Sistemas, APIs, infra, secretos, integraciones técnicas, seguridad | Acceso a BIND/bancos, Azure, política de datos, decisiones técnicas no triviales |
| **Gerente Administrativo** | Operación día a día: quién descarga PDFs, cómo se identifican pagos, cómo se manejan parciales | Reglas operativas: aliases de clientes, ventanas de match, comportamiento UI |
| **Contador (interno o externo)** | Formato del export para BIND, catálogo de cuentas, cierre contable | Estructura del export, mapeo de eventos a asientos contables |
> **Regla práctica:** si la decisión afecta dinero o relación con cliente → CFO/CEO. Si es técnica → CTO. Si es operativa día a día → gerente admin. Cuando dudes, escala al CFO porque típicamente es quien orquesta este tipo de proyectos en una PyME.
## 1.2 Diagrama — Stakeholders × Fases
```mermaid
flowchart TB
classDef ceo fill:#FFD93D,stroke:#666,color:#000,stroke-width:1px
classDef cfo fill:#6BCB77,stroke:#666,color:#000,stroke-width:1px
classDef cto fill:#4D96FF,stroke:#666,color:#FFF,stroke-width:1px
classDef ga fill:#FF6B6B,stroke:#666,color:#FFF,stroke-width:1px
classDef cont fill:#9D4EDD,stroke:#666,color:#FFF,stroke-width:1px
subgraph F0["FASE 0 · Semana 1 · Discovery + Setup"]
direction LR
CEO0["CEO<br/><br/>Kickoff<br/>Lista blanca definitiva"]:::ceo
CFO0["CFO<br/><br/>Reglas operativas<br/>Línea base errores y tiempo"]:::cfo
CTO0["CTO<br/><br/>Azure + Stripe MX<br/>Política de datos / Claude API"]:::cto
GA0["GERENTE ADMIN<br/><br/>PDFs reales 3 bancos<br/>Lista de usuarios"]:::ga
CONT0["CONTADOR<br/><br/>Formato export BIND"]:::cont
end
subgraph F1["FASE 1 · Semanas 2-3 · Plataforma + Sync BIND"]
direction LR
CFO1["CFO<br/><br/>Roles RBAC<br/>Política de cancelación"]:::cfo
CTO1["CTO<br/><br/>Auth y MFA<br/>Acceso para inspeccionar BIND"]:::cto
GA1["GERENTE ADMIN<br/><br/>Validación demo S2<br/>Clientes duplicados / aliases"]:::ga
CONT1["CONTADOR<br/><br/>Campos obligatorios de invoice<br/>Fuente del TC"]:::cont
end
subgraph F2["FASE 2 · Semana 4 · Cobranza + Dashboard + Pago link"]
direction LR
CEO2["CEO<br/><br/>Tono del template<br/>Clientes en zona gris"]:::ceo
CFO2["CFO<br/><br/>TEMPLATE FINAL aprobado<br/>Métricas del dashboard"]:::cfo
CTO2["CTO<br/><br/>Stripe webhook secret<br/>Email transaccional"]:::cto
GA2["GERENTE ADMIN<br/><br/>Ciclo de recordatorios<br/>UX de pagos Stripe"]:::ga
CONT2["CONTADOR<br/><br/>Asiento de pagos Stripe<br/>Manejo de duplicados"]:::cont
end
subgraph F3["FASE 3 · Semana 5 · Conciliación PDF"]
direction LR
CFO3["CFO<br/><br/>Tolerancia de match<br/>Retención PDFs 5 años"]:::cfo
CTO3["CTO<br/><br/>Cifrado Blob Storage<br/>Confirmación Claude API ok"]:::cto
GA3["GERENTE ADMIN<br/><br/>ALIASES de clientes<br/>Validación de match rate"]:::ga
CONT3["CONTADOR<br/><br/>Catálogo de cuentas<br/>Traspasos internos"]:::cont
end
subgraph F4["FASE 4 · Semana 6 · Reportes + Cierre"]
direction LR
CEO4["CEO<br/><br/>Sign-off del MVP"]:::ceo
CFO4["CFO<br/><br/>Criterios de éxito<br/>Aprobación de reportes"]:::cfo
CTO4["CTO<br/><br/>Backups<br/>Handoff técnico"]:::cto
GA4["GERENTE ADMIN<br/><br/>Capacitación grabada"]:::ga
CONT4["CONTADOR<br/><br/>VALIDACIÓN del export BIND"]:::cont
end
F0 --> F1 --> F2 --> F3 --> F4
```
### Cómo leer el diagrama
- **Filas horizontales = fases en el tiempo** (de izquierda a derecha por el flujo, de arriba a abajo en pantalla).
- **Cada bloque de fase contiene los stakeholders que necesitas** durante esa semana, con la decisión / dato concreto que aporta.
- **Códigos de color por rol:**
- 🟡 Amarillo = CEO (visión + clientes estratégicos)
- 🟢 Verde = CFO (reglas de negocio + dinero)
- 🔵 Azul = CTO (sistemas + infra)
- 🔴 Rojo = Gerente Administrativo (operación día a día)
- 🟣 Morado = Contador (contabilidad fiscal + BIND)
- **Si un stakeholder no aparece en una fase**, no significa que no exista — significa que **no es bloqueante** para esa fase. Aun así puede recibir el demo de fin de semana.
- **El CEO aparece solo 3 veces** (F0, F2, F4) — es deliberado: úsalo para kickoff, validación de tono comercial, y sign-off. No lo satures.
## 1.3 Detalle por fase
### Fase 0 — Discovery + Setup (Semana 1)
**Módulos involucrados:** ninguno todavía — es la fase de validar supuestos y dejar todo listo.
| Decisión / dato que necesitas | A quién | Cuándo | 🚩 Si no llega |
|---|---|---|---|
| Export real de BIND (anonimizado) + formato confirmado | CTO + contador | Día 1-3 | Replantear Fase 1 |
| 2-3 PDFs anonimizados por banco (Banorte, BBVA, IBC) | Gerente admin (es quien los descarga) | Día 1-3 | Replantear Fase 3 |
| Subscripción Azure + sponsor + región | CTO | Día 1-2 | No hay dónde desplegar |
| Cuenta Stripe MX verificada (RFC + bancarios) | CFO + CTO | Día 1-5 | Bloqueas Fase 2 |
| Lista blanca DEFINITIVA: ACUNTIA + Top 3 con nombre exacto + alias contables | CEO + CFO | Día 1-5 | Riesgo regulatorio comercial |
| Manual de marca | Gerente admin o quien lo guarde | Día 1-3 | Branding genérico |
| Aprobación uso Claude API con PDFs bancarios | CFO + CTO | Día 1-3 | Replantear Fase 3 |
| Línea base medible de "tiempo de conciliación actual" + "errores manuales actuales" | CFO + gerente admin | Día 1-7 | Criterios de éxito ≥70%/60% no se pueden demostrar al cierre |
| Política de manejo de datos financieros (auditoría externa, NDA, encripción) | CTO | Día 2-3 | Compliance gap |
> **Salida de F0:** un `docs/supuestos.md` firmado. Si algo no se valida, lo marcas como "asunción que se materializará en Change Request si cae".
---
### Fase 1 — Plataforma + Sync BIND (Semanas 2-3)
**Módulos:** `identity`, `catalog`, `bind-sync` + outbox base.
| Decisión / dato | A quién | Cuándo | 🚩 Si no llega |
|---|---|---|---|
| Roles exactos: ¿Finanzas, Dirección, Operaciones, Admin alcanzan? ¿Hay sub-roles? | CFO + CTO | Inicio S2 | Re-trabajo en RBAC |
| ¿Quiénes (nombres + emails) tendrán acceso por rol? | Gerente admin | Inicio S2 | No puedes poblar usuarios reales |
| Política de auth: ¿MFA obligatorio para Finanzas? ¿SSO con Google Workspace si lo usan? | CTO | Inicio S2 | Endurecimiento queda en F4 |
| Validación del schema de invoice (qué campos del export son obligatorios) | Contador + gerente admin | Mid S2 | Modelo incompleto |
| ¿Hay clientes duplicados en BIND por errores históricos? ¿Algún mecanismo de "cliente padre" / "cliente sucursal"? | Gerente admin + contador | Mid S2 | Conciliación falla en S5 |
| Política de cancelación de facturas (¿se reflejan en plataforma?) | CFO + contador | Mid S2 | Estados inconsistentes |
| TC: ¿DOF FIX está bien o usan otro para alguna cuenta específica (USD interno)? | CFO + contador | Mid S2 | Diferencias cambiarias erróneas |
| Confirmación final de fuera-de-scope: EUR + emisión CFDI desde plataforma | CFO | Inicio S2 | Scope creep en S3-S4 |
| **Demo de fin de S2** revisada por gerente admin | Gerente admin | Viernes S2 | Sorpresa en S3 |
| **Demo de fin de S3** revisada por CFO | CFO | Viernes S3 | F2 arranca sobre base no validada |
---
### Fase 2 — Cobranza + Dashboard + Pago con link (Semana 4) — pico de stakeholders
**Módulos:** `collections`, `payments`, `reporting` (dashboard), `notifications`.
> Esta es la fase con **más decisiones de negocio**. CFO y gerente admin tienen que estar disponibles. Bloquea calendario suyo con anticipación desde F0.
| Decisión / dato | A quién | Cuándo | 🚩 Si no llega |
|---|---|---|---|
| **Aprobación final del template de correo** (tono, firma, asuntos) | CFO + CEO (porque toca clientes) | Lunes S4 | No puedes activar recordatorios |
| Ciclo de recordatorios: ¿X días antes, Y días después de vencer, escalación humana al día Z? | CFO + gerente admin | Lunes S4 | Defaults arbitrarios |
| Quién puede **modificar la lista blanca en producción** (rol + segundo factor) | CFO | Lunes S4 | Riesgo de envío accidental |
| Cómo se reporta hoy un pago vía link Stripe en BIND (¿asiento manual del contador? ¿flujo separado?) | Contador + CFO | Martes S4 | Pagos Stripe quedan huérfanos contablemente |
| Política para **pagos duplicados** (cliente paga por link + por transferencia en el mismo día) | Gerente admin + CFO | Mié S4 | Conciliación contradictoria en S5 |
| ¿El gerente admin valida cada pago Stripe antes de marcarlo "aplicado", o auto? | Gerente admin | Mié S4 | UX equivocada |
| Métricas exactas del dashboard (¿qué corte usa Dirección? ¿semanal? ¿por cliente?) | CFO + CEO | Mar S4 | Dashboard no usable |
| Stripe webhook secret + cuenta de email para notificaciones | CTO | Mar S4 | Webhook no se puede recibir |
| Política de manejo cuando webhook Stripe falla (¿conciliar al día siguiente vía dashboard Stripe?) | Gerente admin | Jue S4 | Sin runbook operativo |
| **Demo viernes S4** con CFO + gerente admin + (idealmente) un cliente test | CFO + GA | Viernes S4 | Riesgo de descubrir gap en S5 cuando ya es tarde |
> **Tip:** el template de correo es donde más fricción suele haber. Pide un borrador del CFO en F0 (semana 1) para iterarlo durante F1, no improvises en S4.
---
### Fase 3 — Conciliación PDF con Claude API (Semana 5)
**Módulos:** `banking`, `reconciliation`.
| Decisión / dato | A quién | Cuándo | 🚩 Si no llega |
|---|---|---|---|
| Lista exhaustiva de **aliases por cliente** (cómo aparecen los pagos en cada banco) | Gerente admin + contador | Lunes S5 | Match por alias inútil → todo va a cola humana |
| Tolerancia aceptada: ¿centavos? ¿±0.5%? ¿±2%? ¿depende de monto? | CFO | Lunes S5 | Auto-match muy laxo o muy estricto |
| Ventana de fecha para auto-match (±3 días default, ¿es razonable para SPEI 24/7?) | Gerente admin | Lunes S5 | Auto-match pierde casos legítimos |
| Política de traspasos internos: ¿qué hacen hoy en BIND con esos movimientos? | Contador + CFO | Mar S5 | Doble registro en conciliación |
| ¿Quién aprueba un "match con flag" (medio match)? ¿Cualquiera de Finanzas, o solo CFO? | CFO | Mar S5 | Cola sin dueño |
| Política de **retención de PDFs bancarios** (¿5 años SAT, indefinido, otra?) | CFO + contador | Mar S5 | Compliance fiscal |
| Cifrado en reposo de PDFs en Azure Blob — confirmar política de Balam | CTO | Mar S5 | Hardening incompleto |
| Catálogo de cuentas / clasificaciones de gasto que el contador usa hoy | Contador | Mié S5 | Anomalías por categoría no se pueden detectar |
| Validación con datos reales: subir un mes completo de un banco y revisar match rate con gerente admin | Gerente admin | Jue S5 | Sales del rango y no te enteras |
> **Tip:** los aliases son oro y suelen vivir solo en la cabeza del gerente admin / contador. Pide una hora bloqueada con ellos en S5 para vaciar ese conocimiento a una tabla.
---
### Fase 4 — Reportes + Cierre (Semana 6)
**Módulos:** `reporting` (export BIND), `notifications` (reportes programados), seguridad final, capacitación.
| Decisión / dato | A quién | Cuándo | 🚩 Si no llega |
|---|---|---|---|
| **Validación del export para BIND** (que efectivamente cargue sin error en BIND real) | Contador | Lunes S6 | Entregable inservible |
| Catálogo de cuentas final + mapeo evento → asiento que el contador necesita | Contador + CFO | Lunes S6 | Export incompleto |
| Qué reportes quiere automáticos: ¿diario CxC? ¿semanal de movimientos no conciliados? ¿quién los recibe? | CFO + Dirección | Mar S6 | Reportes que nadie lee |
| Validación de criterios de éxito (≥70% reducción errores, ≥60% reducción tiempo conciliación) | CFO | Mié S6 | No puedes cerrar el contrato |
| Plan de quién opera el sistema post-MVP (gerente admin solo, o también el CTO interviene) | CTO + CFO | Mié S6 | Sin owner operativo |
| Backups: confirmar política (frecuencia, retención, dónde se guardan, plan de recuperación) | CTO | Jue S6 | Compliance + riesgo operativo |
| Sesión de capacitación grabada — quiénes asisten (contacto técnico + gerente admin obligatorios, contador deseable) | Todos los anteriores | Jue S6 | Capacitación no replicable |
| Sign-off formal del MVP | CFO (o CEO) | Viernes S6 | Disputa de horas / scope |
## 1.4 Cadencia recomendada de contacto
| Persona | Cadencia base | Cuándo aumentar |
|---|---|---|
| **CTO (contacto técnico día a día)** | Daily async (1-2 mensajes) + sesión técnica quincenal de 1 h | F0 (acceso), F1 (BIND), inicio F2 (Stripe), F3 (seguridad PDF) |
| **Gerente administrativo** | Demo semanal viernes + ad-hoc por bloqueadores | F2 completa (reglas operativas), F3 completa (aliases, validación) |
| **CFO** | Demo semanal viernes + sesión validación al cierre de cada fase | F2 (templates + dashboard), F4 (export + criterios de éxito) |
| **CEO** | Solo en kickoff + demo final F4 (+ ad-hoc si hay decisión de scope conflicto) | Si surge fricción con cliente estratégico |
| **Contador** | Bloqueado para F0 (formato BIND), F3 (catálogo + aliases), F4 (export final) | Cuando toques cualquier flujo que termine en BIND |
## 1.5 Anti-patrones que cuestan caro
1. **Esperar al CFO/CEO solo en F4** — descubres en S6 que el template de correo no les gusta y replantear el motor de cobranza queda fuera de presupuesto. Inclúyelos desde F2.
2. **Hablar solo con el CTO** — vas a tener un sistema técnicamente correcto que no refleja las reglas de negocio reales. El gerente admin sabe la operación que ni el CTO ni el CFO conocen al detalle.
3. **Pedir lista blanca "en algún momento"** — si llegas a S4 sin tenerla formalizada, el riesgo regulatorio comercial es tuyo. Pídela el día 1.
4. **No bloquear calendario de CFO/gerente admin con anticipación para S4 y S5** — son las semanas pico de decisión de negocio. Si están de viaje o saturados, F2/F3 se atrasan.
5. **Asumir que el contador es interno** — muchas PyMEs en MX tienen contador externo que va una vez por semana. Si es el caso, agéndalo en F0 para que esté disponible en F4.
---
# Sección 2 · Preparación llamada CTO (pre-Fase 0)
> Esta es la llamada **antes de firmar** o antes del kickoff de Fase 0. El objetivo no es vender ni planear todavía; es validar que los 11 supuestos de la propuesta se sostienen.
## 2.1 Objetivo de la llamada
Salir con **decisión clara sobre si algún supuesto crítico de la propuesta ya hoy sabemos que no se cumple**. Es 10× más barato descubrirlo aquí que en semana 2.
Duración recomendada: **60-75 min**. Si solo hay 30, prioriza Bloque 1.
## 2.2 Bloque 1 — Sistemas y datos (25-30 min, el corazón de la llamada)
### BIND ERP
| Pregunta | Por qué importa | 🚩 Bandera roja |
|---|---|---|
| ¿BIND expone alguna API documentada o solo es UI + export? ¿Han hablado con BIND sobre roadmap de API? | Define si Fase 2 es realista en 3 meses o 1 año | No hay API ni planes |
| ¿Cómo exportan hoy facturas y catálogo de clientes? ¿Formato (CSV, Excel, XML SAT)? ¿Frecuencia? ¿Manual o programado? | Es el input principal del MVP | Solo se puede descargar a mano factura por factura |
| ¿Puedes mandarme un export real (anonimizado) en la próxima semana? | El parsing real es la diferencia entre 18 y 30 h en Fase 0 | "Tengo que pedirlo, no sé cuándo lo tengamos" |
| ¿Tienen sandbox de BIND o solo producción? | Define si podemos probar contra datos reales sin riesgo | Solo producción |
| ¿Quién es el admin de BIND internamente? ¿Tiene tiempo para apoyar dudas técnicas? | Necesitas a alguien que valide formatos de export | Ningún dueño técnico claro |
| ¿BIND timbra las facturas (CFDI 4.0) sin costo adicional según el volumen actual? ¿Manejará el crecimiento? | Confirma el supuesto #4 — si no, hay que sumar PAC | No tienen claro el límite |
### Bancos (3 cuentas — 2 MX + IBC Texas)
| Pregunta | Por qué importa | 🚩 Bandera roja |
|---|---|---|
| ¿Cuáles 2 bancos MX exactamente? ¿BBVA, Banorte, Banamex, Santander? | Cada uno tiene formato de PDF distinto | Banco regional poco común |
| ¿Tienen PDFs históricos (últimos 3-6 meses) de los 3 bancos para validar parsing? | Necesitamos muestras reales en Fase 0 | No tienen históricos digitales |
| ¿IBC Bank Texas permite descargar PDFs estructurados o solo print del web? | IBC es el riesgo mayor del MVP | Solo "imprimir como PDF" del portal |
| ¿Quién descarga hoy los estados de cuenta? ¿Cada cuándo? ¿Lo siguen haciendo manual durante el MVP? | El flujo de upload manual depende de esto | "No sabemos quién lo hace consistente" |
| ¿Hay traspasos internos frecuentes entre las 3 cuentas? ¿Cuál es el patrón? | Define complejidad del motor de conciliación | Traspasos diarios sin patrón claro |
| ¿Algún banco ya integrado con Belvo/Plaid o ya tienen credenciales API en algún lado? | Atajo potencial para Fase 2 | — |
### BUK y Jira (para validar que Fase 2 sea creíble, no para MVP)
| Pregunta | Por qué importa |
|---|---|
| ¿BUK expone API? ¿Han pedido roadmap? | El caso de uso #1 del PRD original depende de esto |
| ¿Jira es Cloud o Server? | Cloud tiene API limpia; Server es más complicado |
| ¿Hay registro de horas por colaborador-cliente en Jira hoy, o eso vive en otro lado? | Define si Jira→Factura es viable en Fase 2 |
### Stripe
| Pregunta | Por qué importa | 🚩 Bandera roja |
|---|---|---|
| ¿Ya tienen cuenta Stripe MX verificada (RFC + bancarios) o hay que crearla? | Verificación de Stripe MX toma 1-3 semanas | No la tienen y la necesitamos para semana 4 |
| ¿Algún convenio o pricing especial con Stripe? | Ajuste a la sección de costos operativos | — |
## 2.3 Bloque 2 — Infra y compliance (15 min)
| Pregunta | Por qué importa |
|---|---|
| ¿Tienen subscripción Azure activa? ¿Quién la administra? ¿Centro de costos? | Si no, hay que crearla en Fase 0 |
| ¿Preferencia de región Azure? (mexicocentral, southcentralus, eastus) | Latencia y compliance — IBC Texas puede sugerir US |
| ¿Cómo manejan secretos hoy? (Key Vault, .env, 1Password, nada) | Define el estándar a aplicar |
| ¿Tienen política interna de manejo de datos financieros / PII? ¿Auditoría externa? | Compliance — afecta cómo se modela el audit log y backups |
| ¿NDA — usan el suyo o el mío? ¿Hay restricciones de portafolio? | Cierre legal antes de iniciar |
| Para el manejo de **datos reales** en Fase 3 con Claude API, ¿hay alguna política interna que choque con enviar PDFs bancarios a un LLM (aunque sea Anthropic con no-training)? | El supuesto #11 de la propuesta — si choca, replanteamos |
| ¿Quién recibe el handoff técnico al final del MVP? ¿Tienen DevOps interno o lo opera el contador? | Define qué tan robusta debe ser la operación + capacitación |
## 2.4 Bloque 3 — Realidades operativas (10 min)
| Pregunta | Por qué importa |
|---|---|
| De las ~50 facturas/mes: ¿distribución? ¿2-3 grandes y 47 chicas, o uniforme? | Define dónde concentrar esfuerzo de cobranza |
| ¿Cuántos clientes activos hay hoy? ¿Cuántos están "siempre en cobranza"? | Tamaño del catálogo y reglas de cobranza |
| ¿Cuánto tiempo toma conciliar **hoy** los 3 estados de cuenta del mes? ¿Quién lo hace? | Línea base del criterio de éxito ≥60% — **pide medirlo formalmente las próximas 2 semanas si no está medido** |
| ¿Qué % de facturas requiere re-trabajo por error contable hoy? | Línea base del criterio de éxito ≥70% |
| Pagos parciales: ¿qué tan frecuentes? ¿Cómo los registran hoy? | Define la UX del módulo de cobranza |
## 2.5 Bloque 4 — Reglas de negocio que el CTO sabe pero no están escritas (10 min)
| Pregunta | Por qué importa |
|---|---|
| Lista blanca ACUNTIA + Top 3: ¿quiénes son los Top 3 exactos? ¿Hay clientes "grises" (importantes pero no Top)? | Necesitas esto en Fase 0, no en Fase 2 |
| ¿Hay clientes con condiciones de pago no-estándar? (90 días, retenciones, factoring) | Afecta el motor de recordatorios |
| ¿Cuál es el ciclo de cobranza actual? (1er recordatorio a los X días, 2do a los Y, escalación humana cuándo) | Define defaults del motor |
| ¿Qué hacen hoy cuando entra un pago no identificado? | Necesitas la cola humana clara |
## 2.6 Bloque 5 — Personas, proceso y riesgo (10 min)
| Pregunta | Por qué importa |
|---|---|
| ¿Quién es el **contacto técnico día a día** durante el MVP? ¿Tú directamente o alguien de tu equipo? | Define velocidad de bloqueo |
| ¿Quién es el **gerente administrativo** que validará reglas de cobranza/conciliación? ¿SLA de respuesta? | El otro stakeholder del supuesto #9 |
| ¿Ya intentaron antes este proyecto internamente o con otro proveedor? ¿Qué pasó? | Lecciones gratis + por qué llegaron a ti |
| ¿Cuál es el **peor escenario** que les preocupa con esto? | Te dice dónde están las heridas reales |
| Si tuviéramos que cortar alcance en semana 5 por un imprevisto, ¿qué sacrificas primero entre cobranza, conciliación y dashboard? | Te da el orden de prioridad real, no el oficial |
| ¿Hay cambios fiscales conocidos en pipeline (SAT, Texas) en los próximos 6 meses? | Riesgo de re-trabajo |
## 2.7 Lo que pides cerrar antes de colgar
1. **Compromiso de envío** en 5-7 días hábiles de:
- 1 export real anonimizado de BIND (facturas + clientes)
- 1 PDF de estado de cuenta por cada uno de los 3 bancos (3 archivos)
- Lista de clientes en lista blanca (ACUNTIA + Top 3 con nombre exacto)
2. **Acceso o creación de subscripción Azure** con un sponsor identificado
3. **Borrador de NDA** si aplica
4. **Cadencia confirmada**: 2-3 standups async/semana + demo viernes + sesión técnica quincenal
5. **Próxima sesión técnica agendada** (idealmente día 1 de Fase 0)
## 2.8 Lo que NO conviene hacer en esta llamada
- **No prometer fechas exactas** antes de ver el export real de BIND y los PDFs
- **No entrar en debate de stack** (Next.js vs. lo que sea) — eso es tuyo
- **No discutir tarifa** — ya está en la propuesta, si lo abren responde corto
- **No ofrecer scope creep** aunque suene tentador (ej. "¿también podrías hacer X?") → "Lo agendamos para Fase 2"
## 2.9 Una pregunta-trampa-útil al final
> *"Si dentro de 6 meses esta plataforma está funcionando exactamente como esperan, ¿qué métrica concreta tendría que estar moviéndose para que sintieras que valió la pena?"*
Te da el norte real del proyecto y suele revelar prioridades que no están en el PRD.
---
# Apéndice · Artefactos críticos a recibir antes de iniciar Fase 0
Checklist para confirmar antes de facturar el anticipo:
- [ ] Export real anonimizado de BIND (clientes + facturas)
- [ ] 2-3 PDFs anonimizados de cada uno de los 3 bancos
- [ ] Subscripción Azure con sponsor identificado
- [ ] Cuenta Stripe MX verificada (o compromiso de tenerla en 2 semanas)
- [ ] Lista definitiva: ACUNTIA + Top 3 con nombre legal + aliases bancarios conocidos
- [ ] Manual de marca
- [ ] NDA firmado (si aplica) + acuerdo Claude API
- [ ] Línea base medida: tiempo de conciliación + % errores actuales (para los criterios de éxito ≥70%/60%)
- [ ] Contacto técnico día a día designado con disponibilidad confirmada
- [ ] Gerente administrativo identificado con SLA de respuesta <48 h
- [ ] Contador identificado, interno o externo, con disponibilidad para F0, F3 y F4
-256
View File
@@ -1,256 +0,0 @@
# Agenda · Llamada CTO (martes 19 mayo 2026)
> Documento de preparación personal para la **llamada de pre-arranque** del proyecto Balam.
> Complementa `03 - GUIA-STAKEHOLDERS.md` (Sección 2). La Guía tiene la lista exhaustiva de preguntas; este documento tiene **lo que ya investigué para no llegar en cero**, las preguntas concretas que se derivan de esa investigación, y el orden para los 60-75 min.
>
> Hallazgo principal: **BIND ERP sí tiene API documentada**. Esto cambia el tono de la llamada — la pregunta deja de ser "¿hay API?" y pasa a ser "¿qué módulos están expuestos, cuál es el plan de uso?".
---
## 0. Mentalidad para entrar a la llamada
- **No vendas, valida.** La propuesta ya está firmada (o por firmar); esta llamada existe para detectar si algún supuesto crítico hoy no se cumple. Mejor descubrirlo aquí que en semana 2.
- **No prometas fechas exactas** antes de ver el export real de BIND y los PDFs.
- **No discutas tarifa ni stack.**
- **Apunta hacia los artefactos** del cierre (Sección 7) — todo lo que NO sea uno de esos 5 entregables es ruido.
---
## 1. Estado de lo investigado (lo que YA sé antes de entrar)
Esta sección es para que entres a la llamada con contexto real, no asunciones. Cada hallazgo viene con la pregunta que se le deriva.
### 1.1 BIND ERP — **tiene API pública** ⚡ (cambia el supuesto #2)
| Hecho confirmado | Fuente | Implicación |
|---|---|---|
| API documentada en `developers.bind.com.mx` | [Portal BIND](https://developers.bind.com.mx/) · [Ayuda BIND](https://ayuda.bind.com.mx/hc/es/articles/360007437754-api-de-bind-erp) | Fase 1 puede ir vía API en vez de export, **si** los módulos que necesitamos están expuestos |
| Auth: Bearer Token (API Key) | Ayuda BIND | API Key se saca desde Perfil → Integraciones |
| Rate limit: 20,000 req/día | Ayuda BIND | Más que suficiente para ~50 facturas/mes |
| Endpoints confirmados: `/api/Invoices`, `/api/Invoices/{idOrNumber}` con UUID/folio fiscal · `/api/inventory` · módulo Customers (consultar, agregar, actualizar) | API tracker / Ayuda BIND | Cubre **facturación + clientes**, que es exactamente Fase 1 |
| **NO confirmado**: webhooks, endpoint de pagos, endpoint de asientos contables, sandbox, timbrado CFDI 4.0 vía API | — | Son las 5 preguntas clave de la llamada para BIND |
**Preguntas concretas al CTO sobre BIND** (en orden de prioridad):
1. ¿Han usado la API de BIND antes, o solo el export? ¿Tienen ya un API Key activo?
2. ¿Saben si BIND expone **webhooks** (factura creada, factura pagada, factura cancelada)? Si no, voy a tener que hacer polling — afecta cadencia y costo de Fase 1.
3. ¿Hay endpoint en BIND para **registrar pagos** y para **subir/generar asientos contables**? Si sí, Fase 4 cambia (en lugar de export Excel para el contador, escribimos directo). Si no, mantenemos el plan actual.
4. ¿BIND ofrece **sandbox**, o solo producción? — Define cómo trabajamos en Fase 0/1 sin tocar datos reales.
5. ¿El **timbrado CFDI 4.0** está expuesto vía API o sigue siendo solo botón en la UI? — Importa para visión Fase 2 (que la plataforma emita directo en lugar de "trigger humano en BIND").
> **Si NO conoce la API o nunca la han usado:** no es bandera roja por sí solo, pero pídele acceso ese mismo día para inspeccionarla yo.
### 1.2 BUK — tiene API REST documentada ✅ (supuesto #6 sostiene)
| Hecho confirmado | Implicación |
|---|---|
| BUK ofrece API RESTful para exportación de datos | Visión Fase 2 (BUK → factura automática) es viable |
| Plataforma BUK México activa (`buk.mx`) | No hay riesgo de no-cobertura geográfica |
| 30+ integraciones nativas + flujos configurables | Hay precedente, no es greenfield |
**Preguntas concretas al CTO sobre BUK:**
1. ¿Quién administra BUK internamente? ¿Tienen ya credenciales API o hay que solicitarlas?
2. ¿Qué disparador de BUK marcaría "nómina aprobada lista para facturar al cliente"? (Es el caso de uso #1 del PRD original — viable solo si ese evento existe en BUK.)
3. ¿Cómo registran hoy en BUK las horas por colaborador-cliente? ¿Lo hace BUK, Jira, o vive en una hoja aparte?
### 1.3 IBC Bank Texas — sin API, pero hay 2 alternativas a PDF ⚠️
Esto es el riesgo más alto del MVP según la propuesta. Lo que ya sé:
| Hecho confirmado | Fuente | Implicación |
|---|---|---|
| IBC ofrece eStatements PDF/PNG, retención 18 meses online | [IBC Online Banking](https://www.ibc.com/online-banking/online-banking-services) | Lo que asumimos en la propuesta |
| IBC permite **export a Quicken/QuickBooks** (formato `.QBO`/`.QFX`/`.OFX`) | [IBC Online Banking](https://www.ibc.com/online-banking/online-banking-services) | **Esto es enorme** — parsear `.QBO` (XML estructurado) es 10× más barato y robusto que parsear PDF con Claude |
| Plaid cubre marginalmente bancos MX, pero **sí cubre la mayoría de US banks** — IBC posiblemente sí esté en Plaid | [Plaid Docs](https://plaid.com/docs/institutions/) | Plan B si `.QBO` no funciona y si están dispuestos a compartir credenciales |
**Preguntas concretas al CTO sobre IBC:**
1.**¿Hoy descargan estado de cuenta IBC en PDF, o también en formato `.QBO`/Quicken?** Si pueden descargar `.QBO`, **eliminamos el riesgo de parsing con Claude para IBC**. Cambia el alcance de Fase 3 significativamente.
2. ¿IBC ofrece "Direct Connect" para QuickBooks (vía OFX server) o solo "Web Connect" (descarga manual del archivo)? — Direct Connect = automatizable. Web Connect = sigue siendo descarga manual pero con archivo bueno.
3. ¿Estarían dispuestos a compartir credenciales IBC con un agregador tipo Plaid? (Si la respuesta es no, no insistir — política de seguridad típica.)
### 1.4 Bancos MX — Belvo cubre el universo posible ✅
| Hecho confirmado | Fuente |
|---|---|
| Belvo cubre **32 instituciones MX** para data + payments, incluyendo BBVA, Banorte, Citibanamex, Santander, HSBC, Scotiabank, Banregio, Inbursa, Banco del Bajío, Mifel | [Belvo Direct Debit Institutions](https://developers.belvo.com/products/payments_mexico/direct-debit-institutions) |
**Preguntas concretas al CTO sobre bancos MX:**
1. ¿**Cuáles 2 bancos MX exactos** son? (Si están en la lista de Belvo arriba, hay plan B viable.)
2. ¿Conocen Belvo o han evaluado integración bancaria previamente? — Posicionarlo como Fase 2 (no MVP), pero útil saber si hay apertura. La objeción típica es "no compartimos credenciales con terceros".
3. ¿Tienen PDFs históricos de los últimos 3-6 meses de los 3 bancos para validar parsing en Fase 0?
### 1.5 Stripe MX — timeline manejable, pero hay que arrancar ya ✅
| Hecho confirmado | Fuente | Implicación |
|---|---|---|
| Aprobación típica: **horas a 2 días**, máximo **2 semanas** en casos complejos | [Stripe MX requisitos](https://support.stripe.com/questions/required-information-to-open-your-stripe-account-in-mexico) | Si arrancan el trámite hoy, semana 4 (cobranza + pago link) está cubierta |
| Requisitos: entidad mexicana + RFC + CLABE + representante legal | Stripe Support | Si **falta uno solo**, Stripe MX no opera |
| Comisión: 3.6% + $3 MXN, sin IVA sobre la comisión | [Stripe pricing](https://stripe.com/pricing) | — |
| Alternativas si Stripe no aprueba: **Conekta** (100% MX, OXXO/SPEI nativo, 3.4% + $3 + IVA) o **Mercado Pago** | [Comparativa Stripe vs Conekta vs MP 2026](https://atempora.studio/blog/stripe-vs-mercado-pago-vs-conekta) | Plan B documentado |
**Preguntas concretas al CTO sobre Stripe:**
1. ¿La empresa ya tiene **RFC + CLABE + representante legal con CURP** listos? Si sí, abrimos cuenta esta semana y empezamos verificación.
2. ¿Algún convenio o pricing especial con Stripe? ¿O ya tienen cuenta?
3. Si Stripe MX rechaza o se tarda más de 2 semanas, ¿hay apertura a Conekta como Plan B?
### 1.6 Jira — variable crítica es Cloud vs Server
No requiere research técnico (Jira es estándar), pero confirmar:
1. ¿Jira es **Cloud o Server**? (Cloud = API limpia OAuth 2.0; Server = más complicado, depende de versión.)
2. ¿Hay registro de horas por colaborador-cliente en Jira hoy, o eso vive en otro lado (hoja de cálculo, BUK)?
---
## 2. Estructura de los 60-75 min (orden propuesto)
Asume que el CTO da máximo 60 min reales. Si te dan más, expandes Bloques 4 y 5.
### Min 0-5 · Apertura
- Saludo, agradecimiento por el tiempo.
- **Encuadre claro** (en menos de 60 segundos): *"El objetivo de hoy no es vender ni planear el proyecto — eso ya está en la propuesta. El objetivo es validar conmigo, sistema por sistema, que los supuestos de la propuesta se sostienen. Cada minuto que invertimos aquí me ahorra 10 minutos en semana 2."*
- Permiso para tomar nota / grabar (siempre pídelo).
### Min 5-30 · Bloque 1 — Sistemas y datos (el corazón)
Orden interno (no negociable, va de menor a mayor riesgo):
1. **BIND ERP** (8-10 min) — usa las 5 preguntas de 1.1
2. **Bancos MX** (5 min) — qué bancos exactos, PDFs históricos, posición sobre Belvo
3. **IBC Texas** (5 min) — la pregunta del `.QBO` es la más importante de toda la llamada
4. **BUK + Jira** (3-5 min) — son Fase 2, no MVP, no profundices
5. **Stripe** (3 min) — RFC/CLABE/representante listos sí/no
### Min 30-45 · Bloque 2 — Infra, compliance, seguridad
Usa la tabla de Sección 2.3 de `03 - GUIA-STAKEHOLDERS.md`. Los críticos:
- ¿Azure activa? ¿Quién la administra? ¿Centro de costos?
- ¿Política interna sobre enviar PDFs bancarios a un LLM externo (Claude API)? — **supuesto #11 de la propuesta**.
- ¿Cómo manejan secretos hoy?
- ¿NDA — el suyo o el mío?
### Min 45-55 · Bloque 3 — Realidades operativas y reglas no escritas
Lo mínimo crítico (ver Sección 2.4 y 2.5 de la Guía):
- Distribución de las ~50 facturas: ¿concentradas o uniformes?
- Tiempo actual de conciliación + % retrabajo (línea base para criterios de éxito 60%/70%).
- **Lista blanca: ¿Top 3 exactos?**
- ¿Cuál es el peor escenario que les preocupa? (Esta pregunta abre cosas no escritas.)
### Min 55-65 · Bloque 4 — Cierre operativo
Pide explícitamente los 5 entregables de Sección 7. **No salgas de la llamada sin esto.**
### Min 65-70 · Pregunta-trampa
> *"Si dentro de 6 meses esta plataforma está funcionando exactamente como esperan, ¿qué métrica concreta tendría que estar moviéndose para que sintieras que valió la pena?"*
Esta pregunta revela la prioridad real. A veces sale algo que no está en el PRD.
---
## 3. Banderas rojas a escuchar activamente
Si oyes cualquiera de estas, **no las negocies en la llamada** — anótalas y replantea después.
| Si escuchas... | Significa | Acción |
|---|---|---|
| "BIND no, eso lo administra el contador externo" | No tienes acceso técnico real | Pedir contacto del contador antes de Fase 0 |
| "No sabemos quién descarga los PDFs hoy" | No hay dueño operativo | Bloqueador para Fase 0 — necesitas dueño |
| "No podemos compartir PDFs reales todavía" | Supuesto #1 en riesgo | Posponer fecha de arranque hasta tenerlos |
| "Azure la administra otro proveedor" | Latencia + permisos | Pedir sponsor interno antes de Fase 0 |
| "Tenemos que consultar con legal sobre enviar datos a Claude API" | Supuesto #11 en riesgo | Plan B: extracción local (Tesseract + reglas) — replantear costos |
| "No tenemos RFC todavía / lo está tramitando la contadora" | Stripe MX no opera | Bloqueador para Fase 2 — Conekta Plan B inmediato |
| "IBC solo lo veo cuando entro al portal y le doy print" | El peor caso | Confirma `.QBO` antes de aceptar este peor caso |
| "Ya intentamos esto antes con otro proveedor" | Hay historia | Pregunta qué pasó — lecciones gratis |
---
## 4. Banderas verdes (señales de que el proyecto va a fluir)
| Si escuchas... | Significa |
|---|---|
| "El admin de BIND es Juanito y le digo que te ayude esta semana" | Dueño técnico claro |
| "Aquí tienes mi API Key de BIND, úsala" | Velocidad máxima en Fase 0/1 |
| "Tenemos sandbox de BIND" | Reduce 50% el riesgo de Fase 1 |
| "IBC sí permite descargar `.QBO`" | Fase 3 se simplifica 30-40% |
| "Stripe ya está creada y verificada" | Fase 2 sin bloqueador |
| "El gerente admin se llama X y está disponible miércoles y viernes" | Cadencia de validación realista |
| "Hay un Slack/Teams con el equipo que te van a meter" | Comunicación async funcionando |
---
## 5. Demostraciones de preparación (cosas que dices para mostrar que sí investigaste)
Úsalas cuando aplique. **No las metas todas a fuerza** — son munición, no checklist.
- *"Vi que BIND tiene un portal en `developers.bind.com.mx` con auth Bearer y rate limit de 20K req/día. ¿Ya tienen API Key o lo sacamos juntos esta semana?"*
- *"Belvo cubre BBVA, Banorte, Santander, Citibanamex, HSBC y Scotiabank en MX. ¿Cuáles son los 2 que ustedes usan? Si están en la lista, hay plan B para Fase 2."*
- *"IBC ofrece export a Quicken/QuickBooks en `.QBO`. Si me confirmas que sí está disponible para su cuenta business, **eliminamos el mayor riesgo del MVP** — ya no dependemos de OCR sobre PDF para Texas."*
- *"Stripe MX típicamente aprueba en 1-2 días si los datos están limpios. Conekta es el Plan B si hay algún tema con RFC/CLABE."*
> **Cuidado:** decir demasiado puede sonar a "ya tengo todo resuelto" → puede bajarles la urgencia de mandarte artefactos. Equilibrar.
---
## 6. Lo que NO conviene hacer (recordatorios)
- **No prometer fechas exactas** antes de ver el export real de BIND y los PDFs.
- **No entrar en debate de stack** (Next.js vs. otra cosa) — eso es decisión tuya.
- **No discutir tarifa** — está en la propuesta. Si lo abren, respondes corto y rediriges.
- **No aceptar scope creep** ("¿también podrías hacer X?") → *"Lo agendamos para Fase 2."*
- **No dar opinión técnica fuerte** sobre cómo operan hoy — vienes a entender, no a juzgar.
---
## 7. Lo que pides cerrar antes de colgar (entregables de la llamada)
Estas son las **5 promesas concretas** que necesitas salir con ellas en mano (idealmente con dueño y fecha):
1. **Compromiso de envío en 5-7 días hábiles:**
- [ ] 1 export real anonimizado de BIND (facturas + clientes), o acceso vía API Key
- [ ] 1 PDF de estado de cuenta por cada uno de los 3 bancos (3 archivos) — preferentemente últimos 3 meses
- [ ] **Si aplica:** 1 archivo `.QBO` de IBC Texas para validar formato
- [ ] Lista de clientes en lista blanca (ACUNTIA + Top 3 con nombre exacto)
2. **Acceso o creación de subscripción Azure** con un sponsor identificado.
3. **Borrador de NDA** (si aplica) + posición sobre el uso de Claude API.
4. **Cadencia confirmada**: 2-3 standups async/semana + demo viernes + sesión técnica quincenal.
5. **Próxima sesión técnica agendada** (idealmente día 1 de Fase 0) **con el contacto técnico día a día designado**.
---
## 8. Cosas a hacer YO antes de la llamada (mañana antes de entrar)
- [ ] Revisar la propuesta firmada (00 - PROPUESTA-COMERCIAL.md) para tener los 11 supuestos frescos.
- [ ] Tener `03 - GUIA-STAKEHOLDERS.md` abierto en otra pestaña por si necesito profundizar una pregunta.
- [ ] Tener este documento abierto en otra pestaña.
- [ ] Crear un Postman collection mínimo apuntando a `developers.bind.com.mx` para mostrarlo en pantalla si la conversación lo amerita. (Opcional, pero impresiona.)
- [ ] Confirmar el link de la videollamada y prueba audio/cámara 10 min antes.
- [ ] Tener una hoja en blanco a mano para anotar nombres, fechas, números.
---
## 9. Post-llamada (mismo día, antes de dormir)
- [ ] Mandar correo de **resumen + compromisos** al CTO en menos de 4 horas — formato: 5 bullets de lo que acordamos + 5 bullets de lo que cada uno entrega y para cuándo.
- [ ] Actualizar `00 - PROPUESTA-COMERCIAL.md` con cualquier supuesto que haya cambiado.
- [ ] Si cambian supuestos críticos (BIND con API rica, IBC con `.QBO`, política contra Claude API, etc.), abrir `02 - PLAN-EJECUCION.md` y ajustar Fase 0/1/3 según corresponda.
- [ ] Anotar en una sección de "riesgos abiertos" del proyecto las banderas rojas que escuchaste.
---
## Apéndice · Fuentes investigadas
- BIND ERP API: [Ayuda BIND](https://ayuda.bind.com.mx/hc/es/articles/360007437754-api-de-bind-erp) · [Portal Devs](https://developers.bind.com.mx/) · [API Tracker](https://apitracker.io/a/bind-erp)
- BUK: [buk.mx](https://www.buk.mx/) · [Plataforma RRHH](https://www.buk.co/productos/plataforma-de-rrhh)
- IBC Bank: [Online Banking Services](https://www.ibc.com/online-banking/online-banking-services) · [Business Banking](https://www.ibc.com/business/treasury-management/online-business-banking)
- Belvo: [Direct Debit Institutions MX](https://developers.belvo.com/products/payments_mexico/direct-debit-institutions) · [Banking Product](https://belvo.com/products/banking/)
- Plaid: [Institutions Coverage](https://plaid.com/docs/institutions/)
- Stripe MX: [Required Info](https://support.stripe.com/questions/required-information-to-open-your-stripe-account-in-mexico) · [Pricing](https://stripe.com/pricing) · [Comparativa MX 2026](https://atempora.studio/blog/stripe-vs-mercado-pago-vs-conekta)
-223
View File
@@ -1,223 +0,0 @@
# Checklist · Preguntas para CTO (19 mayo 2026)
> Lista en orden. Cada pregunta tiene un espacio para anotar la respuesta. Después de la llamada, regreso a la conversación con Claude y pego las respuestas para que actualicemos la propuesta.
>
> Tiempo objetivo: 60-75 min. Si solo dan 30, llegar hasta la pregunta 14 (Bloque 1 completo).
---
## Bloque 0 · Apertura (min 0-5)
**Encuadre que digo yo, no pregunta:**
> "El objetivo de hoy es validar contigo, sistema por sistema, que los supuestos de la propuesta se sostienen. Cada minuto aquí me ahorra 10 minutos en semana 2. Voy a tomar nota — ¿te parece?"
---
## Bloque 1 · Sistemas y datos (min 5-30, núcleo de la llamada)
### BIND ERP (min 5-15)
**1.** ¿Han usado la **API de BIND** antes, o solo el export manual? ¿Tienen ya un API Key activo?
> _Respuesta:_
**2.** ¿Saben si BIND expone **webhooks** (factura creada / pagada / cancelada)?
> _Respuesta:_
**3.** ¿BIND tiene endpoint para **registrar pagos** y para **subir asientos contables**? Si sí, ¿quieren que el MVP escriba directo o nos quedamos en export Excel para el contador?
> _Respuesta:_
**4.** ¿BIND ofrece **sandbox**, o solo producción?
> _Respuesta:_
**5.** ¿El **timbrado CFDI 4.0** está expuesto vía API o sigue siendo solo botón en la UI?
> _Respuesta:_
**6.** ¿Cómo exportan **hoy** facturas y catálogo de clientes? ¿Formato (CSV, Excel, XML SAT)? ¿Frecuencia?
> _Respuesta:_
**7.** ¿Pueden mandarme un **export real anonimizado** de BIND en los próximos 5-7 días?
> _Respuesta:_
**8.** ¿Quién es el **admin de BIND** internamente? ¿Tiene tiempo para apoyar dudas técnicas durante el MVP?
> _Respuesta:_
**9.** ¿BIND timbra las facturas (CFDI 4.0) **sin costo adicional** según el volumen actual? ¿Cubrirá el crecimiento esperado?
> _Respuesta:_
---
### Bancos — los 2 MX (min 15-20)
**10.** ¿**Cuáles 2 bancos MX exactamente**? (BBVA, Banorte, Banamex, Santander, HSBC, Scotiabank…)
> _Respuesta:_
**11.** ¿Tienen **PDFs históricos (últimos 3-6 meses)** de los 2 bancos MX que puedan enviarme la próxima semana?
> _Respuesta:_
**12.** ¿Hay traspasos internos frecuentes entre las 3 cuentas? ¿Cuál es el patrón?
> _Respuesta:_
---
### Banco — IBC Texas (min 20-25) ⚡ CRÍTICO
**13.** ⚡ ¿Hoy descargan el estado de cuenta IBC en **PDF, o también en formato `.QBO`/Quicken**?
> _Respuesta:_
**14.** ¿IBC ofrece **"Direct Connect" para QuickBooks** (vía OFX server) o solo "Web Connect" (descarga manual del archivo)?
> _Respuesta:_
**15.** ¿Tienen apertura a evaluar un agregador (Belvo MX, Plaid US para IBC) en Fase 2, o hay política contra compartir credenciales con terceros?
> _Respuesta:_
**16.** ¿Quién descarga **hoy** los estados de cuenta? ¿Con qué frecuencia? ¿Lo seguirá haciendo durante el MVP?
> _Respuesta:_
---
### BUK + Jira (min 25-28, no profundizar — son Fase 2)
**17.** ¿Quién administra BUK internamente? ¿Tienen credenciales API o hay que solicitarlas?
> _Respuesta:_
**18.** ¿Qué evento en BUK marcaría **"nómina aprobada lista para facturar al cliente"**? (¿Existe ese trigger?)
> _Respuesta:_
**19.** ¿Jira es **Cloud o Server**? ¿Hay registro de horas por colaborador-cliente hoy en Jira?
> _Respuesta:_
---
### Stripe (min 28-30)
**20.** ¿Ya tienen cuenta Stripe MX verificada, o hay que crearla? ¿RFC + CLABE + representante legal con CURP están listos?
> _Respuesta:_
**21.** Si Stripe MX rechaza o tarda más de 2 semanas, ¿hay apertura a **Conekta** como Plan B?
> _Respuesta:_
---
## Bloque 2 · Infraestructura, compliance, seguridad (min 30-45)
**22.** ¿Tienen subscripción **Azure** activa? ¿Quién la administra? ¿Centro de costos asignado?
> _Respuesta:_
**23.** ¿Preferencia de **región Azure** (mexicocentral, southcentralus, eastus)?
> _Respuesta:_
**24.** ¿Cómo manejan **secretos** hoy? (Key Vault, .env, 1Password, ninguno)
> _Respuesta:_
**25.** ¿Hay **política interna** que choque con enviar PDFs bancarios a Claude API (Anthropic, sin entrenamiento)?
> _Respuesta:_
**26.** ¿**NDA** — usan el suyo o el mío?
> _Respuesta:_
**27.** ¿Quién recibe el **handoff técnico** al final del MVP? ¿Hay DevOps interno o lo opera otra persona?
> _Respuesta:_
---
## Bloque 3 · Realidad operativa (min 45-55)
**28.** De las ~50 facturas/mes: ¿distribución? (¿2-3 grandes y 47 chicas, o uniforme?)
> _Respuesta:_
**29.** ¿Cuántos **clientes activos** hay hoy? ¿Cuántos están "siempre en cobranza"?
> _Respuesta:_
**30.** ¿Cuánto tiempo toma conciliar **hoy** los 3 estados de cuenta del mes? ¿Quién lo hace?
> _Respuesta:_
**31.** ¿Qué % de facturas requiere **re-trabajo por error contable** hoy?
> _Respuesta:_
**32.** **Pagos parciales**: ¿qué tan frecuentes? ¿Cómo los registran hoy?
> _Respuesta:_
---
### Reglas de negocio no escritas
**33.** **Lista blanca: ¿quiénes son los Top 3 exactos** además de ACUNTIA? ¿Hay clientes "grises"?
> _Respuesta:_
**34.** ¿Hay clientes con **condiciones de pago no-estándar** (90 días, retenciones, factoring)?
> _Respuesta:_
**35.** ¿Cuál es el **ciclo de cobranza actual**? (1er recordatorio a los X días, 2do a los Y, escalación humana cuándo)
> _Respuesta:_
**36.** ¿Qué hacen hoy cuando entra un **pago no identificado**?
> _Respuesta:_
---
## Bloque 4 · Personas, proceso, riesgo (min 55-65)
**37.** ¿Quién es el **contacto técnico día a día** durante el MVP? ¿Tú directamente o alguien de tu equipo?
> _Respuesta:_
**38.** ¿Quién es el **gerente administrativo** que validará reglas de cobranza/conciliación? ¿SLA de respuesta esperado?
> _Respuesta:_
**39.** ¿Ya intentaron este proyecto antes (internamente o con otro proveedor)? ¿Qué pasó?
> _Respuesta:_
**40.** Si tuviéramos que cortar alcance en semana 5 por un imprevisto, ¿qué **sacrificas primero** entre cobranza, conciliación y dashboard?
> _Respuesta:_
**41.** ¿Hay cambios fiscales conocidos en pipeline (SAT, Texas) en los próximos 6 meses?
> _Respuesta:_
---
## Bloque 5 · Pregunta-trampa final (min 65-68)
**42.** *"Si dentro de 6 meses esta plataforma está funcionando exactamente como esperan, ¿qué métrica concreta tendría que estar moviéndose para que sintieras que valió la pena?"*
> _Respuesta:_
---
## Cierre · Compromisos que necesito salir con ellos (min 68-75)
Antes de colgar, **confirmar los 5 entregables**. No salgo sin esto:
**C1.** ¿Cuándo me envían el **export real anonimizado de BIND** (facturas + clientes), o me dan acceso API?
> _Compromiso (fecha + dueño):_
**C2.** ¿Cuándo me envían **1 PDF por banco** (3 archivos)? ¿Y un **`.QBO` de IBC** si aplica?
> _Compromiso (fecha + dueño):_
**C3.** ¿Cuándo me dan **acceso o creación de subscripción Azure** con sponsor identificado?
> _Compromiso (fecha + dueño):_
**C4.** ¿Cuándo me llega el **borrador de NDA** + posición sobre Claude API?
> _Compromiso (fecha + dueño):_
**C5.** ¿Cuándo es la **próxima sesión técnica** (idealmente día 1 de Fase 0) y con quién?
> _Compromiso (fecha + dueño):_
**C6.** **Lista blanca**: ¿cuándo me mandan ACUNTIA + Top 3 con nombre legal + aliases bancarios?
> _Compromiso (fecha + dueño):_
**C7.** **Cadencia**: ¿confirmamos 2-3 standups async/semana + demo viernes + sesión técnica quincenal?
> _Compromiso (fecha + dueño):_
---
## Notas adicionales (cualquier cosa que surja)
> _Anota aquí cosas que no encajan en las preguntas pero importan: nombres mencionados, sistemas adicionales, sentimientos del CTO sobre alcance, etc._
---
## Post-llamada — lo que mando de regreso a Claude
1. Las respuestas de las 42 preguntas + 7 compromisos
2. Cualquier sorpresa o señal que percibí (banderas rojas/verdes)
3. Mi nivel de confianza con el proyecto (1-10) después de la llamada
Con eso actualizamos `00 - PROPUESTA-COMERCIAL.md` y `02 - PLAN-EJECUCION.md` para reflejar la realidad.
@@ -1,82 +0,0 @@
MENSAJES LISTOS PARA ENVIAR · BALAM
"
"1) WhatsApp para Pedro
"
"Hola Pedro, ¿cómo estás?
"
"Sí, con la información que nos compartieron y la confirmación de que BUK cuenta con API, ya puedo preparar una propuesta inicial.
"
"Mi recomendación es plantearla por fases: una primera etapa enfocada en BIND ERP para facturación, seguimiento de cobranza, alertas, reportes y trazabilidad; y dejar bancos, conciliación avanzada, BUK e IA/anomalías como fases posteriores para no inflar el MVP ni depender de todas las integraciones desde el día uno.
"
"Les compartiré la propuesta con alcance, fases, entregables, supuestos técnicos, dependencias y timeline estimado. También incluiré un checklist de accesos e información para que podamos iniciar rápido una vez aprobada.
"
"Gracias por el seguimiento. Quedo atento.
"
"---
"
"2) Correo de respuesta a la actualización de BUK
"
"Asunto: Re: Actualización API BUK / Propuesta Balam
"
"Buenos días, Pedro / equipo Balam,
"
"Muchas gracias por la actualización. La confirmación de que BUK cuenta con soporte API nos ayuda a dejar preparada la arquitectura para una integración posterior, aunque entiendo que no es la prioridad inmediata.
"
"Con la información del PRD, la llamada con Noe y la actualización de BIND/BUK, ya puedo estructurar una propuesta inicial realista. La plantearé en fases, iniciando con un MVP enfocado en BIND ERP para facturación, seguimiento de cobranza, alertas, reportes y trazabilidad.
"
"La intención es que la primera etapa les entregue valor operativo sin depender desde el inicio de bancos, BUK, Book, Jira o automatizaciones de IA más avanzadas. Esas integraciones quedarían consideradas dentro del roadmap y se cotizarían/validarían conforme avancemos en discovery técnico.
"
"Les comparto la propuesta para revisión. Quedo atento a comentarios y a la disponibilidad para una sesión corta de revisión técnica/comercial.
"
"Saludos,
Johann Velazquez
"
"---
"
"3) Correo para enviar la propuesta
"
"Asunto: Propuesta inicial · Plataforma de automatización financiera Balam
"
"Hola Noe, Erika, Ara y Pedro,
"
"Les comparto la propuesta inicial para el desarrollo de la plataforma de automatización financiera de Balam.
"
"Tomando como base el PRD, la llamada de seguimiento y los últimos comentarios sobre BIND y BUK, propongo iniciar con un MVP BIND-first enfocado en facturación, seguimiento de cobranza, alertas, reportes y trazabilidad. Este enfoque permite avanzar de forma realista y reducir riesgo técnico, dejando preparada la arquitectura para integrar bancos, BUK, conciliación bancaria, contabilidad e IA/agentes en fases posteriores.
"
"El documento incluye:
- alcance funcional y técnico del MVP;
- fases sugeridas;
- entregables;
- supuestos y dependencias;
- criterios de aceptación;
- elementos fuera de alcance de la primera fase;
- checklist de información y accesos necesarios.
"
"Quedo atento a sus comentarios. Si lo consideran conveniente, podemos agendar una sesión corta para revisar el alcance y ajustar la propuesta antes de pasar a aprobación.
"
"Saludos,
Johann Velazquez
@@ -1,11 +0,0 @@
Paquete de documentos Balam - MVP BIND-first
Contenido:
00_Resumen_Ejecutivo_Requerimiento_Balam.docx - Lectura ejecutiva y narrativa de alcance.
01_Propuesta_Tecnica_Comercial_Balam_MVP_BIND_First.docx - Documento principal para enviar al cliente.
02_SOW_Alcance_MVP_BIND_First_Balam.docx - Alcance formal/SOW para controlar expectativas.
03_Anexo_Tecnico_Integraciones_Discovery_Balam.docx - Detalle técnico para Noe/Pedro.
04_Checklist_Accesos_Datos_Dependencias_Balam.docx - Checklist operativo para iniciar discovery.
05_Mensajes_Listos_Para_Enviar_Balam.docx/.txt - Copys de WhatsApp y correos.
Nota: Completar montos comerciales antes de enviar la propuesta final.
File diff suppressed because it is too large Load Diff
-740
View File
@@ -1,740 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Balam · Plan de construcción por fases</title>
<style>
:root{
--bg:#ffffff;
--ink:#0f172a;
--muted:#64748b;
--line:#e2e8f0;
--soft:#f8fafc;
--navy:#1e293b;
--peach:#fed7aa;
--peach-ink:#9a3412;
--lavender:#ddd6fe;
--lavender-ink:#5b21b6;
--amber:#fde68a;
--amber-ink:#92400e;
--mint:#bbf7d0;
--mint-ink:#14532d;
--rose:#fecaca;
--rose-ink:#991b1b;
--sky:#bae6fd;
--sky-ink:#075985;
--slate:#e2e8f0;
--slate-ink:#334155;
}
*{box-sizing:border-box}
html,body{background:var(--bg)}
body{
margin:0 auto; padding:48px 56px; max-width:1280px;
font-family:-apple-system,BlinkMacSystemFont,"Inter","Segoe UI",Roboto,sans-serif;
color:var(--ink);
}
h1{font-size:38px; font-weight:800; margin:0 0 6px; letter-spacing:-0.02em}
.lede{color:var(--muted); font-size:16px; margin:0 0 28px; max-width:820px; line-height:1.5}
.section-label{
font-size:11px; font-weight:600; color:var(--muted);
letter-spacing:2px; text-transform:uppercase;
margin:0 0 10px;
}
.block-title{
font-size:22px; font-weight:700; margin:0 0 4px;
display:flex; align-items:center; gap:12px; letter-spacing:-0.01em;
}
.block-sub{color:var(--muted); font-size:14px; margin:0 0 26px; max-width:760px; line-height:1.5}
/* ---- color utilities (lectura / escritura / no-toca / futuro) ---- */
.t-read {background:#ecfdf5; border-color:#bbf7d0; color:#14532d}
.t-write {background:#fff7ed; border-color:#fed7aa; color:#9a3412}
.t-none {background:#f8fafc; border-color:#e2e8f0; color:#64748b}
.t-future{background:#f5f3ff; border-color:#ddd6fe; color:#5b21b6}
/* ---- leyenda ---- */
.legend{display:flex; gap:10px; flex-wrap:wrap; margin:0 0 44px}
.legend .item{
display:inline-flex; align-items:center; gap:8px; font-size:13px;
color:var(--slate-ink); border:1px solid var(--line); background:var(--soft);
padding:8px 14px; border-radius:10px; font-weight:600;
}
.legend .ic{font-size:15px}
/* ---- tile base (reutilizado) ---- */
.tile{
width:88px; height:88px; border-radius:20px;
display:flex; align-items:center; justify-content:center;
font-size:38px; flex:0 0 auto;
box-shadow:0 1px 2px rgba(15,23,42,.06), 0 4px 12px rgba(15,23,42,.04);
}
.tile.navy {background:var(--navy); color:#fff}
.tile.peach {background:var(--peach); color:var(--peach-ink)}
.tile.lavender{background:var(--lavender); color:var(--lavender-ink)}
.tile.amber {background:var(--amber); color:var(--amber-ink)}
.tile.mint {background:var(--mint); color:var(--mint-ink)}
.tile.rose {background:var(--rose); color:var(--rose-ink)}
.tile.sky {background:var(--sky); color:var(--sky-ink)}
.tile.slate {background:var(--slate); color:var(--slate-ink)}
/* ================= LÍNEA DE TIEMPO VERTICAL ================= */
.timeline{margin:0 0 56px}
.phase{
position:relative;
display:grid; grid-template-columns:88px 1fr; gap:28px;
padding-bottom:28px;
}
.phase::before{ /* riel vertical de la línea de tiempo */
content:""; position:absolute; left:43px; top:100px; bottom:-6px;
width:2px; background:var(--line); z-index:0;
}
.phase:last-child::before{display:none}
.phase.lead-roadmap::before{ /* tramo punteado hacia el roadmap */
background:transparent; width:0; border-left:2px dashed #cbd5e1; left:42px;
}
.phase .tile{position:relative; z-index:1}
.phase-card{
border:1px solid var(--line); border-radius:18px;
padding:20px 24px 22px;
box-shadow:0 1px 2px rgba(15,23,42,.06), 0 4px 12px rgba(15,23,42,.04);
}
.ph-kicker{
font-size:11px; font-weight:700; letter-spacing:1.6px; text-transform:uppercase;
color:var(--muted); margin:0 0 3px;
}
.ph-title{font-size:19px; font-weight:700; margin:0 0 12px; letter-spacing:-0.01em}
.ph-card-list{margin:0; padding-left:18px; font-size:13.5px; color:var(--slate-ink); line-height:1.55}
.ph-card-list li{margin:4px 0}
.ph-card-list b{color:var(--ink); font-weight:600}
.ph-status{display:flex; flex-wrap:wrap; gap:10px; margin-top:16px}
.status{
display:inline-flex; align-items:center; gap:8px;
padding:8px 13px; border-radius:11px; font-size:12.5px;
border:1px solid var(--line); line-height:1.3;
}
.status .ic{font-size:14px; flex:0 0 auto}
.status b{font-weight:700}
/* ---- variante Roadmap (post-MVP) ---- */
.phase.roadmap .phase-card{
border:1.5px dashed #cbd5e1; background:#fcfcfd; box-shadow:none;
}
.phase.roadmap .tile{opacity:.9}
.rm-badge{
display:inline-flex; align-items:center; gap:7px;
background:#f5f3ff; border:1px solid #ddd6fe; color:#5b21b6;
font-size:11px; font-weight:700; letter-spacing:.4px;
padding:5px 11px; border-radius:999px; margin:0 0 12px;
}
/* ================= SWIMLANE INTEGRACIÓN EN EL TIEMPO ================= */
.swim-wrap{overflow-x:auto; margin:0 0 12px; padding-bottom:6px}
.swim{
display:grid;
grid-template-columns:118px repeat(6, minmax(140px,1fr));
gap:10px; min-width:920px;
}
.swim .corner{}
.swim .ch{
text-align:center; font-size:13px; font-weight:700; color:var(--ink);
padding:4px 4px 2px; align-self:end;
}
.swim .ch small{
display:block; color:var(--muted); font-weight:600; font-size:10px;
text-transform:uppercase; letter-spacing:1px; margin-top:2px;
}
.swim .ch.rm{color:var(--lavender-ink)}
.swim .lane{
display:flex; align-items:center; gap:9px;
font-weight:700; font-size:14px; color:var(--ink);
}
.swim .lane .dot{
width:26px; height:26px; border-radius:8px; flex:0 0 auto;
display:flex; align-items:center; justify-content:center; font-size:15px;
}
.swim .cell{
border:1px solid var(--line); border-radius:11px;
padding:11px 13px; font-size:12.5px; font-weight:700;
display:flex; flex-direction:column; justify-content:center; min-height:58px;
}
.swim .cell small{display:block; font-weight:600; opacity:.78; font-size:10.5px; margin-top:3px}
.swim .cell.rm{border-style:dashed}
/* ================= DIAGRAMA ESTADO FINAL ================= */
.group{
border:1.5px dashed #cbd5e1; border-radius:18px;
padding:30px 20px 22px; position:relative; margin-top:6px;
}
.group::before{
content:attr(data-label);
position:absolute; top:-9px; left:18px;
background:#fff; padding:0 8px;
font-size:10px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase;
color:var(--lavender-ink);
}
.flow{
display:flex; align-items:flex-start; gap:6px;
overflow-x:auto; padding:4px 4px 8px;
}
.node{flex:0 0 auto; width:120px; text-align:center}
.node .tile{margin:0 auto 12px}
.node .label{font-size:13px; font-weight:700; line-height:1.25}
.node .sub{font-size:11px; color:var(--muted); margin-top:3px; line-height:1.3}
.arrow{
flex:0 0 auto; display:flex; flex-direction:column; align-items:center; gap:5px;
padding-top:30px; user-select:none;
}
.arrow .gly{color:#cbd5e1; font-size:22px; line-height:1}
.arrow .cap{font-size:9.5px; color:var(--muted); max-width:78px; text-align:center; line-height:1.25; font-weight:600}
/* ================= TARJETAS NARRATIVAS (dolor / visión / enfoque) ================= */
.divider{height:1px; background:var(--line); margin:48px 0}
.cards{display:grid; grid-template-columns:repeat(auto-fit,minmax(232px,1fr)); gap:16px}
.info-card{
border:1px solid var(--line); border-radius:16px; padding:18px 20px; background:#fff;
box-shadow:0 1px 2px rgba(15,23,42,.06), 0 4px 12px rgba(15,23,42,.04);
}
.info-card .ic-head{display:flex; align-items:center; gap:11px; margin-bottom:9px}
.info-card .ic-emoji{
width:40px; height:40px; border-radius:12px; flex:0 0 auto;
display:flex; align-items:center; justify-content:center; font-size:20px;
}
.info-card h4{margin:0; font-size:14px; font-weight:700; line-height:1.25}
.info-card p{margin:0; font-size:12.5px; color:var(--slate-ink); line-height:1.5}
/* ---- flow compacto (cadena manual del dolor) ---- */
.flow.compact{gap:2px}
.flow.compact .node{width:104px}
.flow.compact .node .tile{width:72px; height:72px; font-size:30px; border-radius:16px}
.flow.compact .arrow{padding-top:22px}
/* ================= ARQUITECTURA ================= */
.arch{margin-top:4px}
.band-label{
font-size:10px; font-weight:700; letter-spacing:1.4px; text-transform:uppercase;
color:var(--muted); margin:0 0 11px;
}
.arch-row{display:flex; gap:14px; flex-wrap:wrap}
.arch-row + .band-label{margin-top:20px}
.arch-card{
flex:1 1 210px; min-width:200px;
border:1px solid var(--line); border-radius:14px; padding:14px 16px; background:#fff;
display:flex; align-items:center; gap:13px;
box-shadow:0 1px 2px rgba(15,23,42,.06), 0 4px 12px rgba(15,23,42,.04);
}
.arch-card .ico{
width:46px; height:46px; border-radius:12px; flex:0 0 auto;
display:flex; align-items:center; justify-content:center; font-size:23px;
box-shadow:0 1px 2px rgba(15,23,42,.06);
}
.ico.navy {background:var(--navy); color:#fff}
.ico.peach {background:var(--peach); color:var(--peach-ink)}
.ico.lavender{background:var(--lavender); color:var(--lavender-ink)}
.ico.amber {background:var(--amber); color:var(--amber-ink)}
.ico.mint {background:var(--mint); color:var(--mint-ink)}
.ico.sky {background:var(--sky); color:var(--sky-ink)}
.ico.slate {background:var(--slate); color:var(--slate-ink)}
.arch-card .ac-t{font-weight:700; font-size:13.5px; line-height:1.2}
.arch-card .ac-s{font-size:11px; color:var(--muted); margin-top:3px; line-height:1.3}
.arch-card.rm{border-style:dashed; background:#fcfcfd}
.arch-card.rm .ico{opacity:.9}
.arch-down{text-align:center; color:#cbd5e1; font-size:22px; margin:8px 0; user-select:none; line-height:1.1}
.arch-down small{display:block; font-size:10px; color:var(--muted); letter-spacing:1px; text-transform:uppercase; font-weight:700}
.arch .group{padding:26px 20px 20px; margin-top:0}
.arch .group::before{color:var(--slate-ink)}
.mini-pills{display:flex; gap:5px; margin-top:6px; flex-wrap:wrap}
.mini-pill{font-size:9.5px; font-weight:700; padding:2px 8px; border-radius:999px; border:1px solid; white-space:nowrap}
/* ================= RESPONSIVE ================= */
@media (max-width:1100px){
body{padding:36px 30px}
h1{font-size:32px}
.swim{grid-template-columns:108px repeat(6, minmax(132px,1fr))}
}
@media (max-width:700px){
body{padding:26px 18px}
h1{font-size:26px}
.lede{font-size:14px}
.block-title{font-size:19px}
.phase{grid-template-columns:56px 1fr; gap:16px}
.phase .tile{width:56px; height:56px; font-size:25px; border-radius:16px}
.phase::before{left:27px; top:66px}
.phase.lead-roadmap::before{left:26px}
.phase-card{padding:16px 17px 18px}
.ph-title{font-size:17px}
.node{width:108px}
.arch-card{flex-basis:100%; min-width:0}
}
</style>
</head>
<body>
<h1>Balam · Del dolor actual a la plataforma orquestada</h1>
<p class="lede">La historia completa de un vistazo: <b>por qué duele hoy</b>, <b>a qué queremos llegar</b>, <b>cómo lo solucionamos</b>, con <b>qué arquitectura</b> y <b>en qué orden</b> lo construimos. El MVP son las Fases&nbsp;04 (6 semanas, medio tiempo); la fase Post-MVP es roadmap futuro, no incluido en la cotización.</p>
<!-- ====== LEYENDA ====== -->
<div class="legend">
<span class="item"><span class="ic"></span> Lectura (consumir datos)</span>
<span class="item"><span class="ic">✍️</span> Escritura (escribir vía API)</span>
<span class="item"><span class="ic">⏸️</span> No se toca / fuera de scope</span>
<span class="item"><span class="ic">🔮</span> Visión futura (roadmap)</span>
</div>
<!-- ====================================================== -->
<!-- ====== EL DOLOR (HOY) ====== -->
<!-- ====================================================== -->
<p class="section-label">El dolor · hoy</p>
<h2 class="block-title">Todo el ciclo financiero se mueve a mano</h2>
<p class="block-sub">Ocho pasos encadenados, todos dependientes de una persona moviendo datos entre sistemas que no se hablan. Cada eslabón es una oportunidad de error y de retraso.</p>
<div class="flow compact">
<div class="node"><div class="tile slate">🕐</div><div class="label">Jira</div><div class="sub">Horas por cliente</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile slate">👥</div><div class="label">BUK</div><div class="sub">Nómina aprobada</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile rose">✍️</div><div class="label">Captura factura</div><div class="sub">Manual en BIND</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile rose">📧</div><div class="label">Cobranza</div><div class="sub">Correo a mano</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile rose">⬇️</div><div class="label">PDFs banco</div><div class="sub">Descarga manual</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile rose">📊</div><div class="label">Excel</div><div class="sub">Conciliación</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile rose">📒</div><div class="label">Contador</div><div class="sub">Captura asientos</div></div>
<div class="arrow"><span class="gly"></span></div>
<div class="node"><div class="tile rose">📈</div><div class="label">Reporte CxC</div><div class="sub">Llega tarde</div></div>
</div>
<div class="cards" style="margin-top:22px">
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-write">🎯</span><h4>Error humano caro</h4></div>
<p>Un recordatorio de cobranza enviado por equivocación a ACUNTIA o al Top 3 daña la relación con el cliente más importante.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-write"></span><h4>Horas a mano cada mes</h4></div>
<p>Conciliar 3 estados de cuenta bancarios en PDF, línea por línea, contra las facturas que viven en BIND.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-write">🐢</span><h4>Información que llega tarde</h4></div>
<p>Dirección no ve el estado real de la cobranza del día; el reporte llega cuando la decisión ya pasó.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-write">🧵</span><h4>Proceso frágil</h4></div>
<p>Todo depende de que una persona recuerde capturar, cobrar y descargar a tiempo. Si falta, el ciclo se detiene.</p>
</div>
</div>
<div class="divider"></div>
<!-- ====================================================== -->
<!-- ====== A QUÉ QUEREMOS LLEGAR (VISIÓN) ====== -->
<!-- ====================================================== -->
<p class="section-label">A qué queremos llegar · la visión</p>
<h2 class="block-title">Una plataforma que absorbe lo repetitivo</h2>
<p class="block-sub">Las personas dejan de mover datos y solo tocan las excepciones. El resultado: cobranza segura, conciliación automática y visibilidad en tiempo real.</p>
<div class="cards">
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-read"></span><h4>Cobranza con candado</h4></div>
<p>Lista blanca dura: ACUNTIA y el Top 3 nunca reciben un recordatorio automático, por diseño.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-read"></span><h4>Cobro más rápido</h4></div>
<p>Link de pago Stripe directo en el correo; el webhook marca la factura como pagada sin intervención.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-read">🤖</span><h4>Conciliación automática</h4></div>
<p>El match exacto se resuelve solo; el equipo solo revisa lo que no cuadra, en una cola dedicada.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-read">📊</span><h4>Visibilidad en vivo</h4></div>
<p>Dashboard de CxC y CxP en tiempo real para CEO, CFO y CTO, con multimoneda MXN + USD.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-read">🧾</span><h4>Asientos sin captura</h4></div>
<p>En el roadmap, BIND recibe pagos y asientos vía API y se elimina el export a Excel.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-read">🔒</span><h4>Todo trazable</h4></div>
<p>Audit log de quién hizo qué y cuándo, con roles y permisos granulares (RBAC).</p>
</div>
</div>
<div class="divider"></div>
<!-- ====================================================== -->
<!-- ====== CÓMO LO SOLUCIONAMOS (ENFOQUE) ====== -->
<!-- ====================================================== -->
<p class="section-label">Cómo lo solucionamos · el enfoque</p>
<h2 class="block-title">Una capa de orquestación sobre BIND</h2>
<p class="block-sub">No reemplazamos nada: BIND sigue siendo la fuente de verdad y el único que emite CFDI. La plataforma coordina el flujo, automatiza lo repetitivo y usa IA para lo difícil.</p>
<div class="cards">
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-future">🧩</span><h4>Capa sobre BIND, no reemplazo</h4></div>
<p>La plataforma orquesta el flujo; BIND conserva facturación, timbrado CFDI y contabilidad.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-future">🤖</span><h4>IA para lo difícil</h4></div>
<p>Claude extrae los movimientos de cada PDF bancario (1 pipeline por banco) y valida totales.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-future">⚙️</span><h4>Automatizar lo repetitivo</h4></div>
<p>Sync de facturas, recordatorios y match corren solos con un motor de cron + worker.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-future">🙋</span><h4>Humano solo en excepciones</h4></div>
<p>Lo que no hace match cae en una cola de revisión: nada se pierde y nada se cobra a ciegas.</p>
</div>
<div class="info-card">
<div class="ic-head"><span class="ic-emoji t-future">🛡️</span><h4>Control y trazabilidad</h4></div>
<p>RBAC, audit log universal y lista blanca dura protegen el proceso de errores costosos.</p>
</div>
</div>
<div class="divider"></div>
<!-- ====================================================== -->
<!-- ====== LA ARQUITECTURA ====== -->
<!-- ====================================================== -->
<p class="section-label">La arquitectura</p>
<h2 class="block-title">Con qué se construye, por capas</h2>
<p class="block-sub">Una sola plataforma desplegada en Azure, organizada en tres capas: las personas que la usan, la aplicación que orquesta, y los sistemas externos a los que se conecta.</p>
<div class="arch">
<!-- Capa 1: Usuarios -->
<p class="band-label">① Usuarios · acceso por rol</p>
<div class="arch-row">
<div class="arch-card">
<span class="ico peach">💰</span>
<div><div class="ac-t">Finanzas</div><div class="ac-s">Cobranza, pagos y conciliación</div></div>
</div>
<div class="arch-card">
<span class="ico amber">🏢</span>
<div><div class="ac-t">Dirección</div><div class="ac-s">Dashboard CxC / CxP en vivo</div></div>
</div>
<div class="arch-card">
<span class="ico slate">🛠️</span>
<div><div class="ac-t">Operaciones</div><div class="ac-s">Carga de PDFs y revisión</div></div>
</div>
</div>
<div class="arch-down"><small>RBAC + autenticación</small></div>
<!-- Capa 2: Plataforma -->
<div class="group" data-label="② Plataforma Balam · desplegada en Azure">
<p class="band-label">Aplicación</p>
<div class="arch-row">
<div class="arch-card">
<span class="ico sky">🖥️</span>
<div><div class="ac-t">UI Web</div><div class="ac-s">Facturas, dashboard, cobranza, conciliación</div></div>
</div>
<div class="arch-card">
<span class="ico lavender">🔌</span>
<div><div class="ac-t">API core</div><div class="ac-s">Auth, roles, reglas de negocio</div></div>
</div>
<div class="arch-card">
<span class="ico lavender"></span>
<div><div class="ac-t">Worker + Cron</div><div class="ac-s">Sync, recordatorios, motor de match</div></div>
</div>
</div>
<p class="band-label">Datos &amp; almacenamiento</p>
<div class="arch-row">
<div class="arch-card">
<span class="ico mint">🗄️</span>
<div><div class="ac-t">PostgreSQL</div><div class="ac-s">Facturas, pagos, conciliación, audit log</div></div>
</div>
<div class="arch-card">
<span class="ico mint">📦</span>
<div><div class="ac-t">Blob Storage</div><div class="ac-s">PDFs bancarios y respaldos</div></div>
</div>
</div>
</div>
<div class="arch-down"><small>APIs · webhooks · archivos</small></div>
<!-- Capa 3: Integraciones -->
<div class="group" data-label="③ Servicios e integraciones externas">
<p class="band-label">Activas en el MVP</p>
<div class="arch-row">
<div class="arch-card">
<span class="ico navy">📘</span>
<div>
<div class="ac-t">BIND ERP · API</div>
<div class="ac-s">Facturas, clientes, catálogo · fuente de verdad</div>
<div class="mini-pills">
<span class="mini-pill t-read">✅ Lectura</span>
<span class="mini-pill t-write">✍️ Escritura (roadmap)</span>
</div>
</div>
</div>
<div class="arch-card">
<span class="ico peach">🤖</span>
<div><div class="ac-t">Claude API</div><div class="ac-s">Parsing de PDFs bancarios</div></div>
</div>
<div class="arch-card">
<span class="ico mint">💳</span>
<div><div class="ac-t">Stripe</div><div class="ac-s">Pago con link + webhook de pagado</div></div>
</div>
<div class="arch-card">
<span class="ico sky">💱</span>
<div><div class="ac-t">DOF</div><div class="ac-s">Tipo de cambio MXN / USD</div></div>
</div>
</div>
<p class="band-label">Roadmap futuro 🔮</p>
<div class="arch-row">
<div class="arch-card rm">
<span class="ico slate">👥</span>
<div><div class="ac-t">BUK · API</div><div class="ac-s">Nómina aprobada → factura automática</div></div>
</div>
<div class="arch-card rm">
<span class="ico slate">🕐</span>
<div><div class="ac-t">Jira</div><div class="ac-s">Horas por colaborador-cliente</div></div>
</div>
<div class="arch-card rm">
<span class="ico slate">🏦</span>
<div><div class="ac-t">Belvo / Plaid</div><div class="ac-s">Banca en vivo (elimina PDFs)</div></div>
</div>
</div>
</div>
</div>
<div class="divider"></div>
<!-- ====================================================== -->
<!-- ====== LÍNEA DE TIEMPO ====== -->
<!-- ====================================================== -->
<p class="section-label">El plan · cómo se construye · 6 fases</p>
<h2 class="block-title">En qué orden lo entregamos</h2>
<p class="block-sub">Cada fase entrega algo usable. BIND arranca solo como exploración, pasa a lectura activa y, ya en el roadmap, a escritura. BUK queda fuera hasta que exponga una API estable.</p>
<div class="timeline">
<!-- FASE 0 -->
<div class="phase">
<div class="tile slate">🔍</div>
<div class="phase-card">
<p class="ph-kicker">Fase 0 · Semana 1</p>
<h3 class="ph-title">Discovery</h3>
<ul class="ph-card-list">
<li>Validar <b>BIND API</b>: auth, sandbox, webhooks y endpoints de escritura.</li>
<li>Recolectar <b>3 PDFs bancarios</b> reales anonimizados (Banorte, Intercam, IBC Texas).</li>
<li>Validar parsing con <b>Claude API</b> sobre los PDFs.</li>
<li>Setup de <b>Azure + repositorio + CI/CD</b>.</li>
</ul>
<div class="ph-status">
<span class="status t-none"><span class="ic">⏸️</span><span><b>BIND</b> · Solo exploración, sin integración</span></span>
<span class="status t-none"><span class="ic">⏸️</span><span><b>BUK</b> · Fuera de scope</span></span>
</div>
</div>
</div>
<!-- FASE 1 -->
<div class="phase">
<div class="tile sky">🔄</div>
<div class="phase-card">
<p class="ph-kicker">Fase 1 · Semanas 23</p>
<h3 class="ph-title">Sync BIND + plataforma base</h3>
<ul class="ph-card-list">
<li><b>Conector BIND API (lectura)</b>: facturas, clientes y catálogo.</li>
<li>Modelo central de facturas con estados.</li>
<li>Multimoneda <b>MXN + USD</b> (tipo de cambio del DOF).</li>
<li>Auth, roles y audit log · UI: listado, filtros y detalle de facturas.</li>
</ul>
<div class="ph-status">
<span class="status t-read"><span class="ic"></span><span><b>BIND</b> · Lectura activa vía API (sync programado)</span></span>
<span class="status t-none"><span class="ic">⏸️</span><span><b>BUK</b> · Fuera de scope</span></span>
</div>
</div>
</div>
<!-- FASE 2 -->
<div class="phase">
<div class="tile lavender">📬</div>
<div class="phase-card">
<p class="ph-kicker">Fase 2 · Semana 4</p>
<h3 class="ph-title">Cobranza + Dashboard + Pago link</h3>
<ul class="ph-card-list">
<li>Registro manual de pagos asociados a facturas + editor de template de cobranza.</li>
<li>Motor de recordatorios automáticos (<b>cron + worker</b>).</li>
<li><b>Lista blanca dura</b>: ACUNTIA + Top 3 nunca reciben auto-recordatorio.</li>
<li>Pago con link <b>Stripe (Checkout)</b> + webhook que marca pagado · Dashboard CxC en vivo.</li>
</ul>
<div class="ph-status">
<span class="status t-read"><span class="ic"></span><span><b>BIND</b> · Fuente de verdad (lectura)</span></span>
<span class="status t-none"><span class="ic">⏸️</span><span><b>BUK</b> · Fuera de scope</span></span>
</div>
</div>
</div>
<!-- FASE 3 -->
<div class="phase">
<div class="tile peach">🔗</div>
<div class="phase-card">
<p class="ph-kicker">Fase 3 · Semana 5</p>
<h3 class="ph-title">Conciliación bancaria (PDF)</h3>
<ul class="ph-card-list">
<li>Upload manual de PDFs + extracción estructurada con <b>Claude API</b> (1 pipeline por banco).</li>
<li>Validación de totales (sumatoria vs. resumen del PDF).</li>
<li>Motor de conciliación: <b>match exacto auto</b> · alias semi-auto · no-match → cola humana.</li>
<li>Detección de duplicados y traspasos internos.</li>
</ul>
<div class="ph-status">
<span class="status t-read"><span class="ic"></span><span><b>BIND</b> · Lectura para hacer match contra facturas</span></span>
<span class="status t-none"><span class="ic">⏸️</span><span><b>BUK</b> · Fuera de scope</span></span>
</div>
</div>
</div>
<!-- FASE 4 -->
<div class="phase lead-roadmap">
<div class="tile mint">📈</div>
<div class="phase-card">
<p class="ph-kicker">Fase 4 · Semana 6</p>
<h3 class="ph-title">Reportes + cierre del MVP</h3>
<ul class="ph-card-list">
<li>Export <b>Excel/CSV compatible con BIND</b> (el contador sube los asientos manualmente).</li>
<li>Reportes mensuales de <b>CxC y CxP</b>.</li>
<li>Backups + hardening + <b>RBAC granular</b>.</li>
<li>Documentación + capacitación.</li>
</ul>
<div class="ph-status">
<span class="status t-read"><span class="ic"></span><span><b>BIND</b> · Lectura + export Excel hacia BIND (manual por contador)</span></span>
<span class="status t-none"><span class="ic">⏸️</span><span><b>BUK</b> · Fuera de scope</span></span>
</div>
</div>
</div>
<!-- POST-MVP -->
<div class="phase roadmap">
<div class="tile amber">🔮</div>
<div class="phase-card">
<p class="ph-kicker">Post-MVP · Roadmap futuro</p>
<span class="rm-badge">🔮 Roadmap · no incluido en el MVP / cotización</span>
<h3 class="ph-title">Cierre del ciclo end-to-end</h3>
<ul class="ph-card-list">
<li><b>BIND escritura vía API</b>: registra pagos y genera asientos contables automáticos (elimina el export Excel).</li>
<li><b>BUK</b>: cuando exponga API, la nómina aprobada dispara la factura automática en BIND vía la plataforma.</li>
<li><b>Jira</b>: horas por colaborador-cliente como input de facturación.</li>
<li><b>Belvo/Plaid</b>: integración bancaria en vivo (elimina el upload de PDFs).</li>
</ul>
<div class="ph-status">
<span class="status t-write"><span class="ic">✍️</span><span><b>BIND</b> · Escritura vía API (pagos + asientos automáticos)</span></span>
<span class="status t-future"><span class="ic">🔮</span><span><b>BUK</b> · Integración end-to-end (Jira → BUK → factura)</span></span>
</div>
</div>
</div>
</div>
<!-- ====================================================== -->
<!-- ====== SWIMLANE: INTEGRACIÓN A LO LARGO DEL TIEMPO ====== -->
<!-- ====================================================== -->
<p class="section-label">Integración a lo largo del tiempo</p>
<h2 class="block-title">Cómo evoluciona el rol de BIND y BUK</h2>
<p class="block-sub">De un vistazo: BIND pasa de exploración → lectura → escritura. BUK permanece fuera de scope durante todo el MVP y solo entra en el roadmap.</p>
<div class="swim-wrap">
<div class="swim">
<!-- fila encabezados -->
<div class="corner"></div>
<div class="ch">Fase 0<small>Sem 1</small></div>
<div class="ch">Fase 1<small>Sem 23</small></div>
<div class="ch">Fase 2<small>Sem 4</small></div>
<div class="ch">Fase 3<small>Sem 5</small></div>
<div class="ch">Fase 4<small>Sem 6</small></div>
<div class="ch rm">Post-MVP<small>Roadmap</small></div>
<!-- fila BIND -->
<div class="lane"><span class="dot" style="background:var(--navy);color:#fff">📘</span> BIND</div>
<div class="cell t-none">⏸️ Exploración<small>validar API</small></div>
<div class="cell t-read">✅ Lectura<small>sync programado</small></div>
<div class="cell t-read">✅ Lectura<small>fuente de verdad</small></div>
<div class="cell t-read">✅ Lectura<small>match facturas</small></div>
<div class="cell t-read">✅ Lectura<small>+ export Excel</small></div>
<div class="cell t-write rm">✍️ Escritura<small>pagos + asientos</small></div>
<!-- fila BUK -->
<div class="lane"><span class="dot" style="background:var(--sky);color:var(--sky-ink)">👥</span> BUK</div>
<div class="cell t-none">⏸️ Fuera de scope<small></small></div>
<div class="cell t-none">⏸️ Fuera de scope<small></small></div>
<div class="cell t-none">⏸️ Fuera de scope<small></small></div>
<div class="cell t-none">⏸️ Fuera de scope<small></small></div>
<div class="cell t-none">⏸️ Fuera de scope<small></small></div>
<div class="cell t-future rm">🔮 Integración<small>nómina → factura</small></div>
</div>
</div>
<!-- ====================================================== -->
<!-- ====== DIAGRAMA ESTADO FINAL POST-MVP ====== -->
<!-- ====================================================== -->
<p class="section-label" style="margin-top:52px">Estado final · Roadmap post-MVP</p>
<h2 class="block-title">El ciclo cerrado end-to-end</h2>
<p class="block-sub">Visión objetivo una vez completado el roadmap: cada sistema dispara al siguiente sin intervención manual. Las flechas indican quién dispara a quién.</p>
<div class="group" data-label="🔮 Estado objetivo post-MVP">
<div class="flow">
<div class="node">
<div class="tile slate">🕐</div>
<div class="label">Jira</div>
<div class="sub">Horas por colaborador-cliente</div>
</div>
<div class="arrow"><span class="gly"></span><span class="cap">horas aprobadas</span></div>
<div class="node">
<div class="tile sky">👥</div>
<div class="label">BUK</div>
<div class="sub">Nómina aprobada</div>
</div>
<div class="arrow"><span class="gly"></span><span class="cap">nómina aprobada</span></div>
<div class="node">
<div class="tile lavender">⚙️</div>
<div class="label">Plataforma</div>
<div class="sub">Orquesta y genera factura</div>
</div>
<div class="arrow"><span class="gly"></span><span class="cap">factura vía API</span></div>
<div class="node">
<div class="tile navy">📘</div>
<div class="label">BIND ERP</div>
<div class="sub">Timbra CFDI + asiento</div>
</div>
<div class="arrow"><span class="gly"></span><span class="cap">CFDI / cobro</span></div>
<div class="node">
<div class="tile mint">🏦</div>
<div class="label">Banco</div>
<div class="sub">Cobro / movimientos</div>
</div>
<div class="arrow"><span class="gly"></span><span class="cap">mov. en vivo · Belvo/Plaid</span></div>
<div class="node">
<div class="tile peach">🔗</div>
<div class="label">Conciliación</div>
<div class="sub">Match automático</div>
</div>
<div class="arrow"><span class="gly"></span><span class="cap">asiento automático</span></div>
<div class="node">
<div class="tile amber">📈</div>
<div class="label">Reporte</div>
<div class="sub">CxC / CxP + asiento</div>
</div>
</div>
</div>
</body>
</html>
@@ -1,372 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<title>Balam · Flujo financiero</title>
<style>
:root{
--bg:#ffffff;
--ink:#0f172a;
--muted:#64748b;
--line:#e2e8f0;
--soft:#f8fafc;
--navy:#1e293b;
--peach:#fed7aa;
--peach-ink:#9a3412;
--lavender:#ddd6fe;
--lavender-ink:#5b21b6;
--amber:#fde68a;
--amber-ink:#92400e;
--mint:#bbf7d0;
--mint-ink:#14532d;
--rose:#fecaca;
--rose-ink:#991b1b;
--sky:#bae6fd;
--sky-ink:#075985;
--slate:#e2e8f0;
--slate-ink:#334155;
}
*{box-sizing:border-box}
html,body{background:var(--bg)}
body{
margin:0; padding:48px 56px;
font-family:-apple-system,BlinkMacSystemFont,"Inter","Segoe UI",Roboto,sans-serif;
color:var(--ink);
}
h1{font-size:38px; font-weight:800; margin:0 0 6px; letter-spacing:-0.02em}
.lede{color:var(--muted); font-size:16px; margin:0 0 48px; max-width:780px}
.section-label{
font-size:11px; font-weight:600; color:var(--muted);
letter-spacing:2px; text-transform:uppercase;
margin:0 0 24px;
}
.flow-block{margin-bottom:56px}
.flow-title{
font-size:22px; font-weight:700; margin:0 0 4px;
display:flex; align-items:center; gap:12px;
}
.flow-title .pill{
font-size:11px; font-weight:600; letter-spacing:1px; text-transform:uppercase;
padding:4px 10px; border-radius:999px;
}
.pill.bad{background:#fee2e2; color:#991b1b}
.pill.ok{background:#dcfce7; color:#14532d}
.flow-sub{color:var(--muted); font-size:14px; margin:0 0 28px}
.flow{
display:flex; align-items:flex-start; gap:8px;
overflow-x:auto; padding:8px 4px 24px;
}
.node{
flex:0 0 auto; width:108px; text-align:center;
}
.tile{
width:88px; height:88px; border-radius:20px;
margin:0 auto 12px;
display:flex; align-items:center; justify-content:center;
font-size:38px;
box-shadow:0 1px 2px rgba(15,23,42,.06), 0 4px 12px rgba(15,23,42,.04);
}
.tile.navy {background:var(--navy); color:#fff}
.tile.peach {background:var(--peach); color:var(--peach-ink)}
.tile.lavender{background:var(--lavender); color:var(--lavender-ink)}
.tile.amber {background:var(--amber); color:var(--amber-ink)}
.tile.mint {background:var(--mint); color:var(--mint-ink)}
.tile.rose {background:var(--rose); color:var(--rose-ink)}
.tile.sky {background:var(--sky); color:var(--sky-ink)}
.tile.slate {background:var(--slate); color:var(--slate-ink)}
.label{font-size:13px; font-weight:600; line-height:1.25}
.sub{font-size:11px; color:var(--muted); margin-top:3px; line-height:1.3}
.arrow{
flex:0 0 auto; align-self:center;
color:#cbd5e1; font-size:22px; padding:0 2px; margin-top:-36px;
user-select:none;
}
.group{
border:1.5px dashed #cbd5e1; border-radius:18px;
padding:18px 14px 14px; position:relative;
margin-top:14px;
display:flex; align-items:flex-start; gap:4px;
}
.group::before{
content:attr(data-label);
position:absolute; top:-9px; left:18px;
background:#fff; padding:0 8px;
font-size:10px; font-weight:700; letter-spacing:1.5px; text-transform:uppercase;
color:var(--muted);
}
.divider{
height:1px; background:var(--line);
margin:32px 0;
}
/* metrics */
.metrics{
display:grid; grid-template-columns:repeat(4,1fr); gap:16px;
margin-top:8px;
}
.metric{
background:var(--soft); border:1px solid var(--line); border-radius:14px;
padding:18px;
}
.metric .m-label{font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:1.2px; font-weight:600}
.metric .m-row{display:flex; align-items:baseline; gap:10px; margin-top:8px}
.metric .m-before{font-size:14px; color:#94a3b8; text-decoration:line-through}
.metric .m-after{font-size:22px; font-weight:700; color:var(--ink)}
.metric .m-arrow{color:#cbd5e1; font-size:14px}
/* footer two-column */
.twocol{display:grid; grid-template-columns:1fr 1fr; gap:20px; margin-top:32px}
.card{
border:1px solid var(--line); border-radius:14px; padding:20px;
}
.card h3{margin:0 0 10px; font-size:14px; display:flex; align-items:center; gap:8px}
.card ul{margin:0; padding-left:18px; font-size:13px; color:var(--slate-ink); line-height:1.6}
.card .dot{width:8px; height:8px; border-radius:50%; display:inline-block}
.dot.red{background:#ef4444} .dot.green{background:#10b981}
@media (max-width:1100px){
.metrics{grid-template-columns:1fr 1fr}
.twocol{grid-template-columns:1fr}
body{padding:32px 24px}
}
</style>
</head>
<body>
<h1>Balam · Flujo financiero</h1>
<p class="lede">Cómo opera el ciclo de facturación, cobranza y conciliación hoy, y cómo operará después del MVP.</p>
<!-- ====== HOY ====== -->
<div class="flow-block">
<div class="flow-title">Hoy <span class="pill bad">Manual</span></div>
<p class="flow-sub">Ocho pasos, todos dependientes de una persona moviendo datos entre sistemas que no se hablan.</p>
<p class="section-label">Flujo actual</p>
<div class="flow">
<div class="node">
<div class="tile slate">🕐</div>
<div class="label">Jira</div>
<div class="sub">Horas por cliente</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile slate">👥</div>
<div class="label">BUK</div>
<div class="sub">Nómina aprobada</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile rose">✍️</div>
<div class="label">Captura factura</div>
<div class="sub">Manual en BIND</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile rose">📧</div>
<div class="label">Cobranza</div>
<div class="sub">Correo a mano</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile rose">⬇️</div>
<div class="label">PDFs banco</div>
<div class="sub">Descarga manual</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile rose">📊</div>
<div class="label">Excel</div>
<div class="sub">Conciliación</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile rose">📒</div>
<div class="label">Contador</div>
<div class="sub">Captura asientos</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile rose">📈</div>
<div class="label">Reporte CxC</div>
<div class="sub">Llega tarde</div>
</div>
</div>
</div>
<div class="divider"></div>
<!-- ====== DESPUÉS ====== -->
<div class="flow-block">
<div class="flow-title">Después del MVP <span class="pill ok">Orquestado</span></div>
<p class="flow-sub">La plataforma absorbe los pasos repetitivos. Las personas solo tocan excepciones.</p>
<p class="section-label">Diagrama de flujo completo</p>
<div class="flow">
<div class="node">
<div class="tile navy">📘</div>
<div class="label">BIND ERP</div>
<div class="sub">Fuente de verdad</div>
</div>
<div class="arrow"></div>
<!-- Plataforma group -->
<div class="group" data-label="Plataforma de operaciones financieras">
<div class="node">
<div class="tile peach">🔄</div>
<div class="label">Sync API</div>
<div class="sub">Facturas + clientes</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile lavender">⚙️</div>
<div class="label">Motor</div>
<div class="sub">Reglas + match</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile lavender">📬</div>
<div class="label">Cobranza</div>
<div class="sub">Auto + lista blanca</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile amber">📊</div>
<div class="label">Dashboard</div>
<div class="sub">CxC en vivo</div>
</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile mint">💳</div>
<div class="label">Pago link</div>
<div class="sub">Stripe · opcional</div>
</div>
</div>
<p class="section-label" style="margin-top:32px">Ramal de conciliación bancaria</p>
<div class="flow">
<div class="node">
<div class="tile slate">📄</div>
<div class="label">PDF banco</div>
<div class="sub">Upload mensual</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile peach">🤖</div>
<div class="label">Claude</div>
<div class="sub">Extrae movimientos</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile lavender">🔗</div>
<div class="label">Match</div>
<div class="sub">Auto · monto + ref</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile amber">👁️</div>
<div class="label">Revisión</div>
<div class="sub">Solo excepciones</div>
</div>
<div class="arrow"></div>
<div class="node">
<div class="tile mint">📥</div>
<div class="label">Export BIND</div>
<div class="sub">Asientos al contador</div>
</div>
</div>
</div>
<div class="divider"></div>
<!-- ====== MÉTRICAS ====== -->
<p class="section-label">Impacto medible</p>
<div class="metrics">
<div class="metric">
<div class="m-label">Pasos manuales</div>
<div class="m-row">
<span class="m-before">8</span>
<span class="m-arrow"></span>
<span class="m-after">2</span>
</div>
</div>
<div class="metric">
<div class="m-label">Tiempo de conciliación</div>
<div class="m-row">
<span class="m-before">Horas / mes</span>
<span class="m-arrow"></span>
<span class="m-after">60%</span>
</div>
</div>
<div class="metric">
<div class="m-label">Errores contables</div>
<div class="m-row">
<span class="m-before">Recurrentes</span>
<span class="m-arrow"></span>
<span class="m-after">70%</span>
</div>
</div>
<div class="metric">
<div class="m-label">Visibilidad dirección</div>
<div class="m-row">
<span class="m-before">Reporte</span>
<span class="m-arrow"></span>
<span class="m-after">Tiempo real</span>
</div>
</div>
</div>
<!-- ====== DOLOR / GANANCIA ====== -->
<div class="twocol">
<div class="card">
<h3><span class="dot red"></span> Dolor que se elimina</h3>
<ul>
<li>Riesgo de mandar recordatorio a ACUNTIA o Top 3 por error humano.</li>
<li>Horas perdidas conciliando 3 PDFs bancarios a mano.</li>
<li>Errores contables que llegan tarde al contador.</li>
<li>Dirección sin visibilidad real del CxC del día.</li>
<li>Cobranza dependiendo de que alguien recuerde mandar el correo.</li>
</ul>
</div>
<div class="card">
<h3><span class="dot green"></span> Lo que se gana</h3>
<ul>
<li>Cobro más rápido con link de pago directo en el correo.</li>
<li>Conciliación automática + cola humana solo para excepciones.</li>
<li>Dashboard en tiempo real accesible para CEO / CFO / CTO.</li>
<li>Audit log completo de quién hizo qué y cuándo.</li>
<li>Base preparada para Fase 2: Jira → BUK → Factura end-to-end.</li>
</ul>
</div>
</div>
</body>
</html>
@@ -1,315 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<title>Balam — Flujo HOY vs DESPUÉS del MVP</title>
<style>
:root{
--bg:#0f172a;
--text:#e2e8f0; --muted:#94a3b8;
--bad:#ef4444; --bad-bg:rgba(239,68,68,.12);
--ok:#10b981; --ok-bg:rgba(16,185,129,.12);
--warn:#f59e0b;
--info:#3b82f6;
--accent:#a78bfa;
--border:#475569;
}
*{box-sizing:border-box}
body{
margin:0; padding:32px;
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
background:linear-gradient(135deg,#0f172a 0%,#1e1b4b 100%);
color:var(--text); min-height:100vh;
}
h1{margin:0 0 4px; font-size:28px}
.subtitle{color:var(--muted); margin-bottom:24px; font-size:14px}
.legend{
display:flex; gap:16px; flex-wrap:wrap; margin-bottom:24px;
padding:10px 14px; background:rgba(0,0,0,.25); border-radius:8px;
font-size:12px;
}
.legend-item{display:flex; align-items:center; gap:6px}
.icon{font-size:14px}
.columns{display:grid; grid-template-columns:1fr 1fr; gap:24px}
@media (max-width:1100px){ .columns{grid-template-columns:1fr} }
.panel{
background:#1e293b; border:1px solid var(--border);
border-radius:14px; padding:20px;
box-shadow:0 4px 16px rgba(0,0,0,.3);
}
.panel.before{border-top:4px solid var(--bad)}
.panel.after{border-top:4px solid var(--ok)}
.panel h2{
margin:0 0 4px; font-size:18px; display:flex; align-items:center; gap:10px;
}
.panel .tag{
font-size:11px; font-weight:700; padding:3px 10px; border-radius:10px;
text-transform:uppercase; letter-spacing:1px;
}
.tag.bad{background:var(--bad-bg); color:#fca5a5}
.tag.ok{background:var(--ok-bg); color:#6ee7b7}
.panel .lead{color:var(--muted); font-size:13px; margin-bottom:16px}
/* flow */
.flow{display:flex; flex-direction:column; gap:6px}
.step{
background:#334155; border:1px solid var(--border); border-radius:10px;
padding:10px 14px; font-size:13px; line-height:1.4;
display:flex; gap:10px; align-items:flex-start;
}
.step .num{
flex-shrink:0; width:24px; height:24px; border-radius:50%;
background:#475569; color:#fff; font-weight:700; font-size:12px;
display:flex; align-items:center; justify-content:center;
}
.step .body{flex:1}
.step .who{display:block; font-size:10px; color:var(--muted); text-transform:uppercase; letter-spacing:1px; margin-bottom:2px}
.step .what{color:var(--text)}
.step .note{display:block; font-size:11px; color:var(--muted); margin-top:4px; font-style:italic}
.step.manual .num{background:var(--bad)}
.step.manual{border-left:3px solid var(--bad)}
.step.auto .num{background:var(--ok)}
.step.auto{border-left:3px solid var(--ok)}
.step.semi .num{background:var(--warn)}
.step.semi{border-left:3px solid var(--warn)}
.arrow-down{
text-align:center; color:var(--muted); font-size:18px; line-height:1;
margin:-2px 0;
}
/* metrics */
.metrics{
display:grid; grid-template-columns:repeat(4,1fr); gap:12px;
margin-top:24px;
}
.metric{
background:#1e293b; border:1px solid var(--border); border-radius:12px;
padding:14px; text-align:center;
}
.metric .label{font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:1px}
.metric .before-val{font-size:18px; color:#fca5a5; margin-top:4px; text-decoration:line-through; opacity:.7}
.metric .arrow{font-size:14px; color:var(--accent); margin:2px 0}
.metric .after-val{font-size:20px; color:#6ee7b7; font-weight:700}
/* pain & gain box */
.summary{
display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-top:24px;
}
.summary .box{
border-radius:12px; padding:16px;
}
.summary .pain{background:var(--bad-bg); border-left:4px solid var(--bad)}
.summary .gain{background:var(--ok-bg); border-left:4px solid var(--ok)}
.summary h3{margin:0 0 10px; font-size:14px}
.summary ul{margin:0; padding-left:20px; font-size:13px; line-height:1.6; color:var(--text)}
@media (max-width:700px){
.metrics{grid-template-columns:1fr 1fr}
.summary{grid-template-columns:1fr}
}
</style>
</head>
<body>
<h1>Balam · Flujo Financiero</h1>
<div class="subtitle">Cómo opera HOY vs cómo operará DESPUÉS del MVP</div>
<div class="legend">
<div class="legend-item"><span class="icon">🔴</span> Paso manual / handoff humano</div>
<div class="legend-item"><span class="icon">🟡</span> Semi-automático (humano valida)</div>
<div class="legend-item"><span class="icon">🟢</span> Automático</div>
</div>
<div class="columns">
<!-- ================= HOY ================= -->
<div class="panel before">
<h2>🕰️ HOY <span class="tag bad">Manual y desconectado</span></h2>
<div class="lead">Cada paso depende de una persona moviendo datos entre sistemas que no se hablan.</div>
<div class="flow">
<div class="step manual"><div class="num">1</div><div class="body">
<span class="who">Jira · Operaciones</span>
<span class="what">Registro de horas por colaborador y cliente.</span>
<span class="note">Sin visibilidad consolidada para facturación.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">2</div><div class="body">
<span class="who">BUK · RH</span>
<span class="what">Nómina aprobada de los 45 colaboradores + 5 freelancers.</span>
<span class="note">Sin trigger automático hacia facturación.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">3</div><div class="body">
<span class="who">Persona · Admin</span>
<span class="what">Genera factura manualmente en BIND ERP por cada cliente (~50/mes).</span>
<span class="note">Riesgo de error en monto, RFC, concepto.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">4</div><div class="body">
<span class="who">Persona · Cobranza</span>
<span class="what">Recordatorios manuales por correo a cada cliente vencido.</span>
<span class="note">Riesgo de enviar accidentalmente a ACUNTIA / Top 3 → daño de relación.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">5</div><div class="body">
<span class="who">Persona · Finanzas</span>
<span class="what">Descarga 3 PDFs bancarios (2 MX + IBC Texas) desde portales web.</span>
<span class="note">Producción únicamente, sin API.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">6</div><div class="body">
<span class="who">Persona · Finanzas</span>
<span class="what">Concilia movimiento por movimiento contra facturas en Excel.</span>
<span class="note">Horas de trabajo / mes · errores recurrentes.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">7</div><div class="body">
<span class="who">Contador</span>
<span class="what">Captura asientos contables en BIND a partir del Excel conciliado.</span>
<span class="note">Retrabajo si la conciliación previa tuvo errores.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">8</div><div class="body">
<span class="who">Dirección</span>
<span class="what">Pide reporte de CxC al área. Llega tarde y desactualizado.</span>
<span class="note">Sin visibilidad en tiempo real.</span>
</div></div>
</div>
</div>
<!-- ================= DESPUÉS ================= -->
<div class="panel after">
<h2>🚀 DESPUÉS del MVP <span class="tag ok">Orquestado y visible</span></h2>
<div class="lead">La plataforma absorbe los pasos repetitivos. Las personas solo deciden en excepciones.</div>
<div class="flow">
<div class="step semi"><div class="num">1</div><div class="body">
<span class="who">BIND ERP (API) → Plataforma</span>
<span class="what">Sync automático de facturas, clientes y catálogo.</span>
<span class="note">BIND sigue siendo fuente de verdad y emite CFDI.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step auto"><div class="num">2</div><div class="body">
<span class="who">Plataforma · Dashboard</span>
<span class="what">CxC en tiempo real: vencidas, próximas, por cliente, multimoneda (MXN/USD).</span>
<span class="note">Dirección entra al dashboard cuando quiera, sin pedir reporte.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step auto"><div class="num">3</div><div class="body">
<span class="who">Plataforma · Cobranza</span>
<span class="what">Recordatorios automáticos por correo 5 días antes del vencimiento.</span>
<span class="note"><strong>Lista blanca dura:</strong> ACUNTIA + Top 3 NUNCA reciben automático.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step auto"><div class="num">4</div><div class="body">
<span class="who">Plataforma · Pago (opcional)</span>
<span class="what">Link de pago Stripe en el correo → tarjeta o SPEI.</span>
<span class="note">Webhook marca factura como pagada al recibir confirmación.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step manual"><div class="num">5</div><div class="body">
<span class="who">Persona · Finanzas (mínimo)</span>
<span class="what">Sube 3 PDFs bancarios a la plataforma (mensual).</span>
<span class="note">Único paso manual que sigue. Se elimina en Fase 2 con Belvo/Plaid.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step auto"><div class="num">6</div><div class="body">
<span class="who">Plataforma · IA (Claude)</span>
<span class="what">Extrae movimientos de los PDFs y valida totales.</span>
<span class="note">Una pipeline por banco · datos no se usan para entrenamiento.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step semi"><div class="num">7</div><div class="body">
<span class="who">Plataforma · Motor conciliación</span>
<span class="what">Match automático monto+referencia+fecha. No-match → cola de revisión humana.</span>
<span class="note">Persona solo toca las excepciones, no todo.</span>
</div></div>
<div class="arrow-down"></div>
<div class="step semi"><div class="num">8</div><div class="body">
<span class="who">Contador · BIND</span>
<span class="what">Sube a BIND el export Excel ya conciliado y clasificado.</span>
<span class="note">Asientos automáticos contra BIND API → Fase 2.</span>
</div></div>
</div>
</div>
</div>
<!-- ================= MÉTRICAS ================= -->
<div class="metrics">
<div class="metric">
<div class="label">Pasos manuales</div>
<div class="before-val">8 de 8</div>
<div class="arrow"></div>
<div class="after-val">2 de 8</div>
</div>
<div class="metric">
<div class="label">Tiempo conciliación bancaria</div>
<div class="before-val">Horas / mes</div>
<div class="arrow"></div>
<div class="after-val">60% mín.</div>
</div>
<div class="metric">
<div class="label">Errores contables</div>
<div class="before-val">Recurrentes</div>
<div class="arrow"></div>
<div class="after-val">70% mín.</div>
</div>
<div class="metric">
<div class="label">Visibilidad para dirección</div>
<div class="before-val">Reporte pedido</div>
<div class="arrow"></div>
<div class="after-val">Tiempo real</div>
</div>
</div>
<!-- ================= DOLOR / GANANCIA ================= -->
<div class="summary">
<div class="box pain">
<h3>🔴 Dolor que se elimina</h3>
<ul>
<li>Riesgo de enviar recordatorio a ACUNTIA o Top 3 por error humano.</li>
<li>Horas perdidas conciliando 3 PDFs bancarios a mano.</li>
<li>Errores contables que llegan tarde al contador.</li>
<li>Dirección sin visibilidad real del CxC del día.</li>
<li>Cobranza dependiendo de que alguien recuerde mandar el correo.</li>
</ul>
</div>
<div class="box gain">
<h3>🟢 Lo que se gana</h3>
<ul>
<li>Cobro más rápido con link Stripe directo en el correo.</li>
<li>Conciliación automática + cola humana solo para excepciones.</li>
<li>Dashboard en tiempo real accesible para CEO/CFO/CTO.</li>
<li>Audit log completo de quién hizo qué, cuándo.</li>
<li>Base preparada para Fase 2: Jira→BUK→Factura end-to-end.</li>
</ul>
</div>
</div>
</body>
</html>
-293
View File
@@ -1,293 +0,0 @@
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8" />
<title>Balam — Qué se necesita para construir la plataforma</title>
<style>
:root{
--bg:#0f172a; --panel:#1e293b; --panel2:#334155;
--ok:#10b981; --warn:#f59e0b; --bad:#ef4444; --info:#3b82f6;
--text:#e2e8f0; --muted:#94a3b8; --accent:#a78bfa;
--border:#475569;
}
*{box-sizing:border-box}
body{
margin:0; padding:32px;
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
background:linear-gradient(135deg,#0f172a 0%,#1e1b4b 100%);
color:var(--text); min-height:100vh;
}
h1{font-size:28px; margin:0 0 4px}
.subtitle{color:var(--muted); margin-bottom:32px; font-size:14px}
.legend{
display:flex; gap:16px; flex-wrap:wrap; margin-bottom:24px;
padding:12px 16px; background:rgba(0,0,0,.25); border-radius:8px;
font-size:13px;
}
.legend-item{display:flex; align-items:center; gap:6px}
.dot{width:12px; height:12px; border-radius:50%}
.dot.ok{background:var(--ok)} .dot.warn{background:var(--warn)}
.dot.bad{background:var(--bad)} .dot.info{background:var(--info)}
.dot.accent{background:var(--accent)}
.grid{
display:grid; grid-template-columns:1fr 1fr 1fr; gap:24px;
margin-bottom:24px;
}
.row{
display:grid; grid-template-columns:1fr 2fr 1fr; gap:24px;
align-items:stretch; margin-bottom:24px;
}
.col{display:flex; flex-direction:column; gap:16px}
.card{
background:var(--panel); border:1px solid var(--border);
border-radius:12px; padding:16px;
box-shadow:0 4px 12px rgba(0,0,0,.3);
}
.card h3{margin:0 0 8px; font-size:14px; display:flex; align-items:center; gap:8px}
.card .badge{
font-size:10px; padding:2px 8px; border-radius:10px;
background:var(--panel2); color:var(--muted); font-weight:600;
text-transform:uppercase; letter-spacing:.5px;
}
.badge.ok{background:rgba(16,185,129,.2); color:#6ee7b7}
.badge.warn{background:rgba(245,158,11,.2); color:#fcd34d}
.badge.bad{background:rgba(239,68,68,.2); color:#fca5a5}
.badge.info{background:rgba(59,130,246,.2); color:#93c5fd}
.badge.accent{background:rgba(167,139,250,.2); color:#c4b5fd}
.card ul{margin:6px 0 0; padding-left:18px; font-size:12px; color:var(--muted)}
.card li{margin:3px 0; line-height:1.4}
.section-title{
font-size:11px; font-weight:700; text-transform:uppercase;
letter-spacing:1.5px; color:var(--muted); margin:32px 0 12px;
padding-bottom:8px; border-bottom:1px solid var(--border);
}
.core-card{
background:linear-gradient(135deg,#4c1d95 0%,#7c3aed 100%);
border:2px solid var(--accent);
text-align:center; padding:24px;
}
.core-card h2{margin:0 0 8px; font-size:18px}
.core-card p{margin:0; font-size:13px; color:#ddd6fe}
.arrow{
display:flex; align-items:center; justify-content:center;
font-size:24px; color:var(--accent);
}
.checklist{
background:rgba(0,0,0,.3); border-left:4px solid var(--warn);
padding:16px 20px; border-radius:8px; margin-top:16px;
}
.checklist h3{margin:0 0 12px; font-size:14px; color:var(--warn)}
.checklist ol{margin:0; padding-left:20px; font-size:13px; line-height:1.7}
.checklist li strong{color:#fcd34d}
.footer-grid{display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-top:16px}
.footer-card{background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:16px}
.footer-card h4{margin:0 0 8px; font-size:13px}
.footer-card p, .footer-card ul{font-size:12px; color:var(--muted); margin:0; line-height:1.5}
.footer-card ul{padding-left:18px}
.pill{
display:inline-block; padding:2px 8px; border-radius:6px;
background:var(--panel2); font-size:11px; margin-right:4px;
}
@media (max-width:900px){
.grid,.row{grid-template-columns:1fr}
.arrow{transform:rotate(90deg)}
}
</style>
</head>
<body>
<h1>Balam · Plataforma de Automatización Financiera</h1>
<div class="subtitle">¿Qué se necesita para construirla? — vista de un solo vistazo</div>
<div class="legend">
<div class="legend-item"><span class="dot ok"></span> Ya existe / disponible</div>
<div class="legend-item"><span class="dot warn"></span> Por confirmar con Balam</div>
<div class="legend-item"><span class="dot bad"></span> Bloqueador si falta</div>
<div class="legend-item"><span class="dot info"></span> Lo construyo yo</div>
<div class="legend-item"><span class="dot accent"></span> Servicio externo (costo Balam)</div>
</div>
<!-- ============ FILA 1: FUENTES DE DATOS ============ -->
<div class="section-title">1 · Fuentes de datos (de dónde sale la información)</div>
<div class="grid">
<div class="card">
<h3>BIND ERP <span class="badge ok">API confirmada</span></h3>
<ul>
<li>Facturas, clientes, catálogo</li>
<li>Timbrado CFDI con PAC integrado</li>
<li>Límite 20K req/día (suficiente)</li>
<li><strong>Falta confirmar:</strong> sandbox, webhooks, endpoints de escritura</li>
</ul>
</div>
<div class="card">
<h3>3 Bancos (PDFs) <span class="badge warn">Solo PDF hoy</span></h3>
<ul>
<li>2 bancos MX (Banorte + Intercam?)</li>
<li>1 banco US: IBC Bank Texas</li>
<li>Sin API en MVP, sin sandbox</li>
<li><strong>Falta:</strong> muestras reales anonimizadas</li>
</ul>
</div>
<div class="card">
<h3>BUK / Jira <span class="badge bad">Diferido Fase 2</span></h3>
<ul>
<li>Nómina (BUK) y horas (Jira)</li>
<li>BUK: servicio problemático, API por confirmar</li>
<li>NO entran en MVP</li>
<li>Habilitan flujo end-to-end más adelante</li>
</ul>
</div>
</div>
<!-- ============ FILA 2: LA PLATAFORMA ============ -->
<div class="section-title">2 · La plataforma que construyo (capa sobre BIND, no reemplazo)</div>
<div class="card core-card">
<h2>⚙️ Plataforma de Operaciones Financieras</h2>
<p>Orquesta el flujo entre BIND, bancos y el equipo · No emite CFDI · No reemplaza contabilidad</p>
</div>
<div class="grid" style="margin-top:16px">
<div class="card">
<h3>📥 Ingesta &amp; Sync <span class="badge info">Construir</span></h3>
<ul>
<li>Conector BIND API (lectura)</li>
<li>Upload de PDFs bancarios</li>
<li>Parser IA (Claude) para PDFs</li>
<li>Validación de totales</li>
</ul>
</div>
<div class="card">
<h3>🔁 Motor de negocio <span class="badge info">Construir</span></h3>
<ul>
<li>Conciliación pagos ↔ facturas</li>
<li>Cobranza con lista blanca dura</li>
<li>Templates de correo + recordatorios</li>
<li>Audit log universal</li>
</ul>
</div>
<div class="card">
<h3>📊 UI &amp; Reportes <span class="badge info">Construir</span></h3>
<ul>
<li>Dashboard CxC / vencidas / próximas</li>
<li>RBAC: Finanzas / Dirección / Ops</li>
<li>Export Excel para BIND</li>
<li>Multimoneda MXN + USD (TC DOF)</li>
</ul>
</div>
</div>
<!-- ============ FILA 3: SERVICIOS EXTERNOS ============ -->
<div class="section-title">3 · Servicios externos (Balam los paga directo)</div>
<div class="grid">
<div class="card">
<h3>☁️ Azure <span class="badge accent">$45$140 USD/mes</span></h3>
<ul>
<li>App Service + worker</li>
<li>PostgreSQL administrado</li>
<li>Blob Storage para PDFs</li>
<li><strong>Falta:</strong> ¿subscripción existe?</li>
</ul>
</div>
<div class="card">
<h3>🤖 Claude API <span class="badge accent">$5$20 USD/mes</span></h3>
<ul>
<li>Parsing de PDFs bancarios</li>
<li>Sin entrenamiento sobre datos del cliente</li>
<li>Costo por página procesada</li>
</ul>
</div>
<div class="card">
<h3>💳 Stripe MX <span class="badge accent">% por transacción</span></h3>
<ul>
<li>Solo si confirman pago con link</li>
<li>RFC + CLABE + rep. legal requeridos</li>
<li><strong>Falta confirmar:</strong> ¿lo quieren?</li>
</ul>
</div>
</div>
<!-- ============ FILA 4: LO QUE NECESITO DE BALAM ============ -->
<div class="section-title">4 · Lo que Balam debe entregar antes / durante Fase 0</div>
<div class="grid">
<div class="card">
<h3>👥 Personas <span class="badge warn">Por nombrar</span></h3>
<ul>
<li>1 contacto técnico (día a día)</li>
<li>1 gerente administrativo (reglas)</li>
<li>Admin de BIND para resolver dudas</li>
<li>SLA respuesta &lt;48 h en bloqueadores</li>
</ul>
</div>
<div class="card">
<h3>🔑 Accesos <span class="badge warn">Crítico</span></h3>
<ul>
<li>API Key de BIND (o gestionarlo)</li>
<li>Subscripción Azure</li>
<li>Acceso a portal IBC para descarga PDFs</li>
<li>Cuenta Stripe MX (si aplica)</li>
</ul>
</div>
<div class="card">
<h3>📄 Datos &amp; reglas <span class="badge warn">Inicio Fase 0</span></h3>
<ul>
<li>3 PDFs reales (1 por banco) anonimizados</li>
<li>Lista blanca: ACUNTIA + Top 3 con nombres legales</li>
<li>Manual de marca</li>
<li>NDA (suyo o mío)</li>
<li>Ciclo de cobranza actual (días, escalación)</li>
</ul>
</div>
</div>
<!-- ============ DECISIÓN PENDIENTE ============ -->
<div class="checklist">
<h3>⚠️ Decisión pendiente del CTO antes de cotizar firme</h3>
<ol>
<li><strong>Alcance del MVP:</strong> ¿Opción A "BIND-first" (34 semanas, ~$3645K MXN) o Opción B "MVP completo con conciliación bancaria" (6 semanas, ~$6684K MXN)?</li>
<li><strong>BIND API:</strong> sandbox disponible (aunque sea pagado), webhooks expuestos, endpoints de escritura (registrar pagos / asientos).</li>
<li><strong>Pago con link Stripe:</strong> ¿es requerimiento real o se difiere a Fase 2?</li>
<li><strong>Operación:</strong> nombres de contacto técnico y gerente administrativo + cuenta Azure.</li>
</ol>
</div>
<!-- ============ FOOTER: PARÁMETROS ============ -->
<div class="footer-grid">
<div class="footer-card">
<h4>💰 Modelo comercial</h4>
<ul>
<li><span class="pill">600 MXN/h</span> + IVA, facturación semanal</li>
<li>Time &amp; Materials con soft cap por fase</li>
<li>Pago a 7 días, anticipo de 30 h Fase 0</li>
<li>Dedicación medio tiempo (~20 h/semana)</li>
</ul>
</div>
<div class="footer-card">
<h4>⏱️ Tiempo &amp; entrega</h4>
<ul>
<li>MVP B completo: 6 semanas esfuerzo · 8 semanas calendario</li>
<li>MVP A BIND-first: 34 semanas esfuerzo</li>
<li>Soporte post-launch: 2 semanas incluidas</li>
<li>Demo semanal viernes + standup async 2-3/sem</li>
</ul>
</div>
</div>
</body>
</html>
Binary file not shown.
+14 -4
View File
@@ -1,16 +1,23 @@
# --- Configuración del sandbox de BIND --- # --- Configuración del sandbox de BIND ---
# #
# Por default el cliente apunta al mock local (puerto 4010). # Por default el cliente apunta al mock local (puerto 4010).
# Cuando Pedro entregue el API key real, copia este archivo a .env y # Para apuntar al API REAL: BIND_BASE_URL=https://api.bind.com.mx y pon el
# cambia BIND_BASE_URL a https://api.bind.com.mx + llena las credenciales. # token en BIND_API_TOKEN (así lo nombra el correo de entrega de Pedro, 6-jul).
# #
# Recuerda: BIND solo tiene PRODUCCIÓN. Cualquier llamada con base URL real # Recuerda: BIND solo tiene PRODUCCIÓN. Cualquier llamada con base URL real
# afecta datos reales de Balam. Mantén MODE=read-only mientras no haya # afecta datos reales de Balam. Mantén MODE=read-only mientras no haya
# autorización explícita para escribir. # autorización explícita para escribir. El token NUNCA se versiona ni se
# imprime (este archivo .env está en .gitignore).
#
# Validado 6-jul-2026 (ver VALIDACION-API.md): la auth real es SOLO
# Authorization: Bearer <token> — la subscription key no se requiere.
BIND_BASE_URL=http://localhost:4010 BIND_BASE_URL=http://localhost:4010
# Token del API real (entregado por Pedro; usuario BIND de Arturo Rosas):
BIND_API_TOKEN=
# Credencial para el mock local (cualquier string no vacío funciona):
BIND_API_KEY=mock-bearer-token BIND_API_KEY=mock-bearer-token
BIND_SUBSCRIPTION_KEY=mock-subscription-key BIND_SUBSCRIPTION_KEY=
# read-only | dry-run | write # read-only | dry-run | write
# - read-only: solo GET. Bloquea POST/PUT/PATCH/DELETE en el cliente. # - read-only: solo GET. Bloquea POST/PUT/PATCH/DELETE en el cliente.
@@ -20,3 +27,6 @@ BIND_MODE=read-only
# Puerto del mock server # Puerto del mock server
MOCK_PORT=4010 MOCK_PORT=4010
# Presupuesto de peticiones del script de validación (src/validate-real-api.ts)
VALIDATION_BUDGET=120
+1
View File
@@ -2,3 +2,4 @@ node_modules/
dist/ dist/
.env .env
*.log *.log
validation-output/
+41 -18
View File
@@ -7,21 +7,31 @@ Está pensado para que tú (Johann), Pedro (Balam) o un futuro dev puedan:
2. Probar el cliente tipado contra un mock que replica los headers, el formato OData y el rate-limit observable de BIND. 2. Probar el cliente tipado contra un mock que replica los headers, el formato OData y el rate-limit observable de BIND.
3. Cuando Pedro entregue las credenciales reales, **cambiar dos variables de entorno** y apuntar el mismo código a `https://api.bind.com.mx` sin reescribir nada. 3. Cuando Pedro entregue las credenciales reales, **cambiar dos variables de entorno** y apuntar el mismo código a `https://api.bind.com.mx` sin reescribir nada.
> ✅ **ACTUALIZACIÓN 6-jul-2026 — validación contra el API real EJECUTADA.**
> Con el token entregado por Pedro (usuario de Arturo Rosas) se corrió la validación
> técnica de solo lectura (117 peticiones GET). Resultados completos, tabla de
> cobertura de endpoints, inventario de campos y veredicto del saldo en
> **[VALIDACION-API.md](VALIDACION-API.md)**. Los hallazgos clave ya están
> reconciliados en el cliente (`types.real.ts`, `BindClient` con `idStyle`).
> El mock conserva el schema aproximado previo — sigue siendo útil para CI/demo,
> pero el contrato real es el de `types.real.ts`.
--- ---
## TL;DR del API de BIND (lo que descubrí del discovery) ## TL;DR del API de BIND (reconciliado con la validación del 6-jul)
| Tema | Hallazgo | | Tema | Hallazgo |
|---|---| |---|---|
| **Base URL** | `https://api.bind.com.mx` | | **Base URL** | `https://api.bind.com.mx` ✅ confirmado |
| **Estilo** | REST con sintaxis **OData v3** (filtros `$filter`, `$top`, `$skip`, `$orderby`, `$count`, IDs como `guid'...'`) | | **Estilo** | REST con filtros OData v3 (`$filter`, `$top`≤100, `$skip`, `$orderby`). ⚠️ `$select` NO funciona (500); conteo total inaccesible; **GET por ID es REST `/{id}`, no `(guid'...')`** |
| **Auth** | Dos headers: `Authorization: Bearer <API_KEY>` + `Ocp-Apim-Subscription-Key: <SUBSCRIPTION_KEY>` (este último cuando aplica) | | **Auth** | **Solo** `Authorization: Bearer <token>` — la `Ocp-Apim-Subscription-Key` no se requiere. ⚠️ Token inválido → **500** (no 401) |
| **Origen del API key** | Cuenta BIND → Perfil de usuario → pestaña *Integraciones* | | **Origen del API key** | Cuenta BIND → Perfil de usuario → pestaña *Integraciones* (el de Balam salió del usuario de **Arturo Rosas**) |
| **Rate limit** | **20,000 peticiones / día** (confirmado por Noe, 25-may-2026) | | **Rate limit** | **20,000 peticiones / día** — no observable en headers; llevar contador local |
| **Sandbox oficial** | **No existe.** BIND recomienda Postman contra producción → razón #1 de este sandbox | | **Sandbox oficial** | **No existe.** Este mock local sigue siendo la única red de pruebas sin efecto fiscal |
| **Portal dev** | [developers.bind.com.mx](https://developers.bind.com.mx) (login requerido para ver schemas detallados) | | **PAC para CFDI** | Integrado en BIND; el PDF del CFDI se descarga vía `GET /api/Invoices/{id}/pdf` |
| **PAC para CFDI** | Integrado dentro del propio BIND — la plataforma de Balam **no toca el SAT**, solo orquesta | | **Recursos confirmados (200)** | `Invoices`, **`Clients`** (no Customers), **`Quotes`**, `Products`, `Currencies`, `Warehouses`, `Locations`, `Activities`, `PriceLists`, `Orders`, `Providers`, `Banks`, `BankAccounts`, `Users` |
| **Recursos confirmados** | `Activities`, `Customers`, `Products` (y según el discovery doc: `Invoices`, `Payments`, `Quotes` muy probables) | | **Recursos que NO existen** | **`Payments`** (≈20 nombres probados → 404 — el acumulado pagado viene DENTRO de cada factura), `Customers`, `Series`, `CreditNotes`, `Companies` |
| **Saldo por factura** | ✅ **Plan A operativo:** `Total Payments CreditNotes` en la misma fila de `/api/Invoices` (verificado aritméticamente) |
### Por qué un sandbox propio y no Postman ### Por qué un sandbox propio y no Postman
@@ -75,18 +85,26 @@ Stats del cliente
{ requestsToday: 6, quota: 20000, remaining: 19994, mode: 'read-only' } { requestsToday: 6, quota: 20000, remaining: 19994, mode: 'read-only' }
``` ```
### Apuntar a producción (cuando llegue el API key) ### Apuntar a producción (token real)
Solo cambiar variables de entorno — el código no se modifica: Solo cambiar variables de entorno — el código no se modifica (el cliente detecta
el estilo de ID; contra el API real usa `/{id}`):
```powershell ```powershell
$env:BIND_BASE_URL = "https://api.bind.com.mx" $env:BIND_BASE_URL = "https://api.bind.com.mx"
$env:BIND_API_KEY = "<key del perfil de usuario de Balam>" $env:BIND_API_TOKEN = "<token del perfil de Arturo — NUNCA versionarlo>"
$env:BIND_SUBSCRIPTION_KEY = "<si aplica>"
$env:BIND_MODE = "read-only" # mantenlo así hasta tener autorización para escribir $env:BIND_MODE = "read-only" # mantenlo así hasta tener autorización para escribir
npm run demo npm run demo
``` ```
> ⚠️ La demo fue escrita contra el schema del mock (`types.ts` aproximados);
> contra producción algunos escenarios no aplican (p. ej. `Customers` → 404 real).
> Para explorar el API real usa el script de validación:
>
> ```powershell
> npm run validate:real # solo GET, presupuesto de peticiones, reporte sanitizado
> ```
--- ---
## Mapeo a la arquitectura de Balam ## Mapeo a la arquitectura de Balam
@@ -151,9 +169,14 @@ Estos son los puntos del `03_Anexo_Tecnico_Integraciones_Discovery_Balam.docx` y
## Limitaciones honestas de este sandbox ## Limitaciones honestas de este sandbox
- **El schema de `Invoice`, `Customer`, etc. es una aproximación** — está modelado a partir de la doc pública y del flujo que necesita Balam, no del SDK oficial. Cuando salga el primer `GET` real contra producción, hay que reconciliar nombres de campos (especialmente capitalización y campos opcionales). - **El schema del MOCK (`types.ts`) sigue siendo la aproximación previa** — el contrato
- **El mock acepta cualquier Bearer**, solo valida que exista. No es un servidor de auth real, es un placeholder. confirmado contra producción vive en **`src/client/types.real.ts`** y en
- **El parser de OData del mock solo cubre lo que el cliente genera** (`eq, ne, gt, lt, ge, le, and, or`, paréntesis). No soporta `contains`, `startswith`, funciones, lambdas. Suficiente para el MVP. [VALIDACION-API.md](VALIDACION-API.md). Pendiente (opcional): regenerar el seed del
- **No reproduce la lógica de `$expand`** — si BIND lo soporta para traer `Lines` o `Customer` embebidos, hay que extender. mock con los shapes reales para que la demo ejercite el contrato confirmado.
- **El mock acepta cualquier Bearer**, solo valida que exista. No es un servidor de auth real.
- **El mock implementa el GET por ID estilo OData `(guid'...')`** — el API real usa `/{id}`;
el cliente lo resuelve con `idStyle`, el mock quedó intacto.
- **El parser de OData del mock solo cubre lo que el cliente genera** (`eq, ne, gt, lt, ge, le, and, or`, paréntesis).
- **No reproduce la lógica de `$expand`** — y el API real ni siquiera soporta `$select`, así que el payload completo es la norma.
Cuando alguno de estos límites se vuelva una piedra en el zapato, se extiende. Hoy es deliberadamente mínimo. Cuando alguno de estos límites se vuelva una piedra en el zapato, se extiende. Hoy es deliberadamente mínimo.
+357
View File
@@ -0,0 +1,357 @@
# Validación técnica de la API de BIND ERP — cuenta real (Balam)
> **Actividad:** "Validación técnica de la API de BIND" · Etapa 0 (Discovery)
> **Fecha de ejecución:** 6-jul-2026 · **Base URL:** `https://api.bind.com.mx`
> **Token:** entregado por Pedro el 6-jul (correo, [REGISTRO #29]) — generado con el usuario de **Arturo Rosas**, conforme al acuerdo del kickoff ([REGISTRO #22]). Vive en `bind-api-sandbox/.env` (`BIND_API_TOKEN`), fuera de git.
> **Método:** script [`src/validate-real-api.ts`](src/validate-real-api.ts) — **exclusivamente GET** (no existe código de escritura en el script), **117 de 120 peticiones** presupuestadas (límite real: 20K/día). Reporte crudo sanitizado en `validation-output/report.json` (gitignoreado).
> **Política de datos:** este documento contiene **solo estructura** — nombres de campos, tipos, formatos, conteos y códigos de estatus. Ningún valor real de Balam (nombres, RFCs, montos, folios, correos). Los ejemplos son inventados con el mismo shape.
---
## Resumen ejecutivo
| Pregunta | Veredicto |
|---|---|
| ¿El token autentica? | ✅ Sí — `Authorization: Bearer` como único header. Sin subscription key. |
| ¿Alcance del token? | ✅ Cubre todos los recursos existentes que probamos (ningún 401/403 por recurso) — coherente con "cuenta mayor, todos los permisos" del kickoff. |
| ¿Se distingue prefactura de factura timbrada? | ✅ Sí — `UUID eq null` / `IsFiscalInvoice eq false` devuelven filas. |
| ¿PPD/PUE visible? | ✅ Sí, en el **detalle** por factura (`CFDIPaymentTerm`) — no en la lista. |
| **¿Saldo abierto por factura?** | ✅ **Plan A operativo:** `Total Payments CreditNotes`, todos campos de la **misma fila** de `/api/Invoices`. Verificado aritméticamente. |
| ¿Pagos individuales listables? | ❌ **No** — no existe recurso de pagos consultable (19 nombres probados → 404). El acumulado sí (`Invoices.Payments`). |
| ¿Cotizaciones consultables? | ✅ Sí (`/api/Quotes` + detalle) — pero **sin relación visible** cotización→factura. |
| ¿OData? | ⚠️ Parcial — `$filter/$top/$skip/$orderby` sí (sintaxis v3); `$select` y conteo total **no**. |
| ¿Multi-empresa? | ✅ Acotado a **una** empresa (la del usuario del token). Sin recurso `Companies` ni campo de empresa. |
| ¿PDF del CFDI por API? | ✅ `GET /api/Invoices/{id}/pdf``application/pdf`. |
---
## 1 · Autenticación
Esquema confirmado: **un solo header**.
```
GET https://api.bind.com.mx/api/{Recurso}
Authorization: Bearer <token>
Accept: application/json
```
- El `Ocp-Apim-Subscription-Key` que el sandbox contemplaba como posible **no es necesario** — no se envió en ninguna petición y todo funcionó.
| Escenario | Estatus | Cuerpo (estructura) |
|---|---|---|
| Token válido | `200` | Colección OData `{ value: [...] }` |
| Sin header Authorization | `401` | `{ "Message": "Authorization has been denied for this request." }` |
| Token corrupto/inválido | ⚠️ **`500`** | `{ "message": "API Key es inválida. \| Your API Key is invalid.", "code": "0" }` |
> **Hallazgo importante:** un token inválido responde **500, no 401/403**. El monitoreo de la plataforma **no puede fiarse del código HTTP** para distinguir "token revocado" de "error del servidor de BIND" — hay que inspeccionar el mensaje del body (`API Key es inválida`).
---
## 2 · Cobertura de endpoints (inventario)
Todos con `GET {recurso}?$top=1`. **No apareció ningún 401/403 por recurso**: con este token todo existe (200) o no existe (404) — no hay recursos "prohibidos" visibles.
### Responden 200
| Recurso | Método probado | Estatus | Notas |
|---|---|---|---|
| `Invoices` | GET lista / GET `/{id}` / GET `/{id}/pdf` / GET `/{id}/xml` | 200 | Colección OData. Detalle trae más campos que la lista (50 vs 32). |
| `Clients` | GET lista / GET `/{id}` | 200 | **Así se llaman los clientes** (no `Customers`). Detalle 28 campos vs 10 de lista. |
| `Quotes` | GET lista / GET `/{id}` | 200 | Cotizaciones. Detalle 45 campos con partidas `Items[]`. |
| `Products` | GET lista | 200 | 30 campos. Incluye `ChargeVAT`, `CurrencyCode`, unidad. |
| `Currencies` | GET lista | 200 | Catálogo: `ID`, `Name`, `Code` (3 letras), `ExchangeRate`. |
| `Warehouses` | GET lista | 200 | `ID`, `Name`, `LocationID`, `AvailableInOtherLoc`. 1 fila (Matriz). |
| `Locations` | GET lista | 200 | Sucursales/domicilios: `Name`, `Street`, `ZipCode`, `City`, `State`… 1 fila. |
| `Activities` | GET lista | 200 | Devuelve colección **vacía** en esta cuenta (0 filas). |
| `PriceLists` | GET lista | 200 | Listas de precios. |
| `Orders` | GET lista | 200 | Pedidos (no se profundizó — fuera del flujo MVP). |
| `Providers` | GET lista | 200 | Proveedores (fuera del flujo MVP). |
| `Banks` | GET lista | 200 | Catálogo bancario (relevante futuro: conciliación). |
| `BankAccounts` | GET lista | 200 | Cuentas bancarias de la empresa (ídem). |
| `Users` | GET lista | 200 | Usuarios BIND. No se analizó su shape (contiene datos personales, no prioritario). |
### Responden 404 (no existen con ese nombre)
| Grupo | Nombres probados → 404 |
|---|---|
| Clientes (alias) | `Customers` |
| **Pagos** | `Payments`, `Payment`, `ClientPayments`, `CustomerPayments`, `Incomes`, `Income`, `Deposits`, `Collections`, `PaymentComplements`, `Complements`, `CashReceipts`, `AccountsReceivable`, `Receivables`, `Cobros`, `Pagos`, `InvoicePayments`, `PaymentsReceived` |
| Pagos (sub-recurso) | `Invoices/{id}/Payments`, `Invoices/{id}/payments`, `Invoices/{id}/CreditNotes` |
| Cotizaciones (alias) | `Quotations`, `Cotizaciones` |
| Series | `Series`, `InvoiceSeries`, `Folios`, `DocumentSeries` (la serie es **campo** de la factura, no recurso) |
| Sucursales (alias) | `Branches`, `Sucursales` (lo real es `Locations`) |
| Otros | `CreditNotes`, `Taxes`, `Prices`, `SalesOrders`, `PurchaseOrders`, `Suppliers`, `Sellers`, `Employees`, `Companies`, `Expenses`, `Inventory`, `CFDI`, `CFDIs` |
---
## 3 · Inventario de campos por recurso
Solo nombres, tipos y formatos observados (muestras de `$top=5`). `(≈corto/medio/largo)` = longitud aproximada del string; los valores reales nunca se persistieron.
### 3.1 `Invoices` — lista (32 campos)
| Campo | Tipo/formato | Nota |
|---|---|---|
| `ID` | guid | Clave para `GET /api/Invoices/{id}`. |
| `Serie` | string corto (a veces vacío) | ⚠️ En el detalle se llama **`Series`** (inconsistencia del API). |
| `Number` | integer | Folio interno. |
| `UUID` | guid | Folio fiscal del CFDI. **`null` en prefacturas.** |
| `Date` | datetime ISO | Fecha del documento. |
| `ExpirationDate` | datetime ISO | **Fecha de vencimiento** (esto alimenta el aging). No existe campo `DueDate`. |
| `ClientID` / `ClientName` | guid / string | Denormalizado en la propia fila. |
| `RFC` | string formato RFC | Del receptor. |
| `Cost`, `Subtotal`, `Discount`, `Total` | decimal | |
| `VAT`, `IEPS`, `ISRRet`, `VATRet` | decimal | Impuestos y retenciones. |
| `VATRate`, `VATRetRate` | decimal | Tasas (p. ej. `0.16`). |
| **`Payments`** | decimal | **Acumulado pagado de la factura** (ver §4). |
| **`CreditNotes`** | decimal | Acumulado de notas de crédito aplicadas. |
| `CurrencyID` | guid | FK a `Currencies` (la lista no trae el código — el detalle sí). |
| `ExchangeRate` | decimal | TC fijado al emitir. |
| `LocationID`, `WarehouseID`, `PriceListID` | guid | |
| `CFDIUse` | integer | ⚠️ Código **interno** (se observaron `3`, `23`), no la clave SAT (`G03`…). Falta tabla de mapeo. |
| `Comments` | string | Aquí ponen hoy el nº de ticket Jira (Discovery #27). |
| `PurchaseOrder` | string | Orden de compra. |
| `IsFiscalInvoice` | boolean | **`false` = prefactura** (sin timbrar). |
| `ShowIEPS` | boolean | |
| `Status` | integer | Ver semántica abajo. |
**Semántica de `Status` (mapeada contra el propio API, lista→detalle):**
| Código | Etiqueta (campo `Status` del detalle) |
|---|---|
| `0` | Activa |
| `1` | Pagada |
| `2` | Cancelada |
Se probaron códigos 35: sin filas (o no existen o no hay ejemplares). ⚠️ `Status` **no distingue** prefactura de timbrada — el discriminador fiable es `UUID eq null` / `IsFiscalInvoice eq false` (ambos filtros devuelven filas: **las prefacturas sí son visibles por API**).
### 3.2 `Invoices/{id}` — detalle (50 campos; los adicionales)
| Campo | Tipo/formato | Nota |
|---|---|---|
| `Series` | string | La lista lo llama `Serie`. |
| `Status` / `StatusCode` | string / integer | Etiqueta + código (p. ej. "Pagada" / `1`). |
| **`PaymentTerms`** | integer | **Días de crédito** de la factura. Solo en detalle. |
| **`CFDIPaymentTerm`** | string | ⚠️ **El método de pago SAT (PPD/PUE)** — se observó el literal "PAGO EN UNA SOLA EXHIBICIÓN" (=PUE). Puede venir vacío. Solo en detalle. |
| **`CFDIPaymentMethod`** | string | ⚠️ **La forma de pago SAT** (se observaron "Transferencia Electrónica de Fondos", "Por Definir"). Nomenclatura **invertida** respecto al SAT — ver hallazgos. |
| `CFDIAccountNumber` | string | Nº de cuenta (últimos dígitos), puede venir vacío. |
| `CurrencyName` | string 3 letras | Código de moneda (`MXN`/`USD`) — en el detalle es el código, no el nombre. |
| `ClientPhoneNumber`, `ClientContact` | string \| null | |
| `CreatedByID` / `CreatedByName` | guid / string | Quién creó el documento (auditoría). |
| `CreationDate` / `ApplicationDate` | datetime ISO | |
| `PriceListName`, `LocationName`, `WarehouseName` | string | Denormalizados. |
| `FiscalID` | guid | |
| `Address` | string largo | Dirección fiscal del receptor. |
| `Products` | array | Partidas de productos (vacío en la muestra — Balam factura servicios). |
| `Services` | array | **Partidas de servicios.** |
| `Services[].ID`, `Services[].ServiceID` | guid | |
| `Services[].IndexNumber` | integer | Orden de la partida. |
| `Services[].Name`, `Services[].Code` | string | Concepto (p. ej. el 029 "consultoría y servicios" del Discovery). |
| `Services[].Qty`, `Services[].Price` | decimal | |
| `Services[].VATRate` | decimal | **Tasa de IVA por partida** — habilita la validación 16 % / 0 %. |
| `Services[].Discount` | decimal | |
> El detalle **no** trae `CFDIUse` (solo la lista) ni un campo de saldo precalculado.
### 3.3 `Quotes` — lista (11 campos) y detalle (45)
**Lista:** `ID` (guid), `Number` (string), `CreationDate` (datetime), `ClientName`, `Locations` (string), `Comments`, `TotalOriginalCurrency` (decimal), `Currency` (nombre, p. ej. "Peso mexicano"), `Total` (decimal), `Status` (integer), `StatusText` (string).
**Semántica de `Quotes.Status`** (mapeada vía `$filter` + `StatusText` de la misma fila):
| Código | `StatusText` |
|---|---|
| `0` | Activa |
| `1` | Cancelada |
| `2` | Surtida |
**Detalle `Quotes/{id}` agrega:** `QuoteNumber`, `ClientID`/`ClientContact`/`ClientPhone`, `LocationName/ID`, `PriceListName/ID`, `EmployeeName/ID` (comercial que cotizó), `CurrencyCode` (3 letras), `ExchangeRate`, `Subtotal`, `Discount`, `IEPS`, `VAT`/`VATRate`, `ISR`/`ISRRate`, `VatRet`, `Total`, `BaseCurrency` (bool), `OriginalCurrencySubtotal`, `OriginalCurrencyDiscountAmount`, `IsPercentage` (bool), **`ContactEmails`**, `ExternalIDType` (int), `Comments`, y partidas **`Items[]`**: `ID`, `Code`, `ProductID`, `ProductName`, `Unit`, `Qty`, `Price`, `Amount`, `IEPS`, `VAT`, `IndexNumber`.
> ⚠️ **No hay campo que ligue la cotización con la factura generada** (ni `InvoiceID` en Quote, ni `QuoteID` en Invoice). "Surtida" dice que se convirtió, pero no *a qué* factura. Ver implicaciones (§9.2).
### 3.4 `Clients` — lista (10 campos) y detalle (28)
**Lista:** `ID` (guid), `Number` (int), `ClientName`, `LegalName`, `RFC`, `Email`, `Phone`, `NextContactDate`, `LocationID` (guid), `RegimenFiscal` (string).
**Detalle `Clients/{id}` agrega:**
| Campo | Tipo | Nota |
|---|---|---|
| `CommercialName` | string | |
| **`CreditDays`** | integer | **Días de crédito default del cliente** (los 30/45/90 del Discovery). |
| `CreditAmount` | decimal | Límite de crédito. |
| `PaymentMethod` | string | Forma de pago default (se observó "Efectivo"). |
| `PaymentTermType` | string | Puede venir vacío. |
| `Status` | string | "Activo"/… |
| `SalesContact` / `CreditContact` | string | Contactos comercial y de cobranza. |
| **`Loctaion` / `LoctaionID`** | string / guid | ⚠️ **Typo real del API** ("Loctaion", sic) — el cliente tipado debe usar el nombre con typo. |
| `PriceList` / `PriceListID` | string / guid | |
| `Email`, `Telephones` | string \| null | Correos configurados (los que usa el botón "enviar email" de BIND). |
| `AccountNumber`, `DefaultDiscount`, `ClientSource`, `Account` | varios | |
| `City`, `State`, `Addresses[]` | string / array | |
| `RegimenFiscal` | string | Régimen fiscal SAT. |
| `CreationDate` | datetime | |
> **No se observó** un campo "uso CFDI default por cliente" — el `CFDIUse` vive en la factura. La regla "gastos en general vs sin efectos fiscales" tendrá que derivarse de otra señal (p. ej. RFC extranjero/`XEXX010101000`, país, o configuración en la plataforma).
### 3.5 Catálogos
- **`Currencies`:** `ID` (guid), `Name`, `Code` (3 letras), `ExchangeRate` (decimal). 4 filas en la cuenta.
- **`Warehouses`:** `ID`, `Name` ("Matriz"), `LocationID`, `AvailableInOtherLoc` (bool). 1 fila — confirma el "hoy solo matriz" del Discovery.
- **`Locations`:** `ID`, `Name`, `Street`, `ExtNumber`, `IntNumber`, `ZipCode`, `Colonia`, `City`, `State`. 1 fila.
- **`Products`:** 30 campos, incl. `Code`, `Title`, `Cost`, `CostType(+Text)`, `CurrentInventory`, **`ChargeVAT`** (bool), `Unit`, `CurrencyID/Code`, `PricingType(+Text)`, `PurchaseType(+Text)`, `IEPSRate`, `Type(+Text)`, `SKU`, categorías.
### 3.6 Documentos del CFDI
| Endpoint | Estatus | Content-Type | Nota |
|---|---|---|---|
| `GET /api/Invoices/{id}/pdf` | 200 | `application/pdf` | **PDF real descargable por API** — insumo directo del módulo de envío. |
| `GET /api/Invoices/{id}/xml` | 200 | `application/json` | Responde 200 pero como JSON — probablemente envuelve el XML o una URL. El contenido se descartó por política de no persistir datos; **shape pendiente** (§10). |
---
## 4 · La pregunta del saldo — veredicto
**Plan A (operativo). No se necesita Plan B ni Plan C.**
- No existe un campo literal `Balance`/`Saldo`, **pero** cada fila de `/api/Invoices` trae `Total`, **`Payments`** (acumulado pagado) y **`CreditNotes`** (acumulado de notas de crédito):
$$\text{SaldoPorFactura} = \text{Total} - \text{Payments} - \text{CreditNotes}$$
- **Verificación aritmética (en memoria, sin persistir montos):** en 5/5 facturas con `Status=1` (Pagada), `Payments + CreditNotes ≈ Total` (diferencia < 0.01); en 5/5 con `Status=0` (Activa), el residual es positivo. La fórmula cuadra en ambas poblaciones.
- Es "Plan A" en el sentido operativo del riesgo de la propuesta: **una sola llamada a `/api/Invoices` basta** para calcular saldo y aging de toda la cartera — no hay que correlacionar una colección de pagos (Plan B) ni capturar nada a mano (Plan C).
- Matiz honesto: BIND no expone el número ya restado; la resta la hace la plataforma. El costo es cero (mismos campos, misma fila).
---
## 5 · Payments — el hallazgo duro
**No existe recurso consultable de pagos individuales.** Se probaron 17 nombres de colección y 3 sub-recursos (§2) — todos 404.
Lo que **sí** hay:
| Necesidad del MVP | ¿Cubierta? | Cómo |
|---|---|---|
| Saldo por factura | ✅ | `Total Payments CreditNotes` (§4). |
| ¿Factura pagada? | ✅ | `Status = 1` y/o residual ≈ 0. |
| Aging / vencimiento | ✅ | `ExpirationDate` + saldo. |
| **Fecha y monto de cada abono individual** | ❌ | No visible por API con este token. |
| Complementos de pago (REP) de facturas PPD | ❌ | Ningún recurso visible (`PaymentComplements`, `Complements` → 404). |
**Implicación:** el motor de cobranza puede detectar *que* una factura se pagó (transición de `Status`/residual entre sincronizaciones) y registrar el *timestamp de detección* en la plataforma, pero no la fecha valor del pago según BIND. Preguntar a Pedro/soporte BIND si existe un endpoint de pagos/REP no descubierto (la doc completa está tras login en developers.bind.com.mx) — ver §10.
---
## 6 · OData y paginación
| Mecanismo | ¿Funciona? | Evidencia |
|---|---|---|
| `$top` | ✅ con tope | `$top=100` → 200; **`$top=101` → 500**. |
| `$skip` | ✅ | `$top=1&$skip=1` devuelve la fila siguiente (verificado por ID). |
| `$orderby` | ✅ | `Date asc` → orden ascendente verificado. |
| `$filter eq` (int) | ✅ | `Status eq 1`, `CFDIUse eq 3` → 200. |
| `$filter eq null` | ✅ | `UUID eq null` → 200 con filas. |
| `$filter ge` + fecha | ✅ **sintaxis v3** | `Date ge datetime'2020-01-01T00:00:00'` → 200. |
| `$select` | ❌ | → **500**. No se pueden proyectar columnas; el payload siempre viene completo. |
| `$inlinecount=allpages` (v3) | ❌ | → 500. |
| `$count=true` (v4) | ⚠️ | → 200 pero **ignorado**: no devuelve conteo. |
| `odata.nextLink` | ❌ | Nunca apareció. |
**Paginación:** no hay `nextLink` ni conteo total ⇒ **paginación manual** con `$top=100&$skip=N` hasta recibir página corta. ⚠️ `GET` sin `$top` devuelve la colección completa en una respuesta (se observó con una colección de 41 filas) — con colecciones grandes es un riesgo de payload; **siempre** paginar. Sondeo por `$skip` (sin descargar): la colección histórica de `Invoices` supera las 1,000 filas.
**Rate limit:** no se observó **ningún header** de cuota (`X-RateLimit-*`, `Retry-After` en 200s) — el límite de 20K/día no es observable por request; hay que llevarlo con contador local (como ya hace `BindClient`).
**Estabilidad:** ~3 respuestas `500` transitorias en 117 peticiones (resueltas al primer retry). El retry con backoff **no es opcional** en producción. Nota: BIND usa 500 también para errores de sintaxis OData y token inválido — distinguir por body/contexto antes de reintentar a ciegas.
**GET por ID:** estilo **REST**`GET /api/Invoices/{id}` → 200; el estilo OData `Invoices(guid'...')`**404**. (El cliente del sandbox asumía el estilo OData; ya se corrigió.)
---
## 7 · Multi-empresa
- `Companies` → 404; **ningún** recurso expone campo `Company`/`Empresa`.
- `Locations` y `Warehouses` devuelven **1 fila** (Matriz).
- Conclusión: **el token está acotado a la empresa del usuario que lo generó** (Arturo → Balam). La distinción multi-empresa del portal Jira (Balam/Regiotour/Elmstone, Discovery #27) **no viaja a BIND por este token**: para facturar otras empresas se necesitaría una cuenta BIND distinta con su propio token. Anotado para el roadmap — coherente con dejar multi-empresa fuera del MVP.
---
## 8 · Hallazgos inesperados
1. **Token inválido → 500** (no 401/403), con mensaje `"API Key es inválida"` en el body. El 401 solo aparece cuando *falta* el header.
2. **`$select` no funciona** (500): no se puede reducir payload por columnas.
3. **Conteo total inaccesible**: `$inlinecount` truena (500) y `$count=true` se ignora — el total solo se conoce paginando hasta el final.
4. **No hay recurso de pagos** (17 nombres → 404) — el acumulado vive dentro de la factura (§5).
5. **Nomenclatura CFDI invertida respecto al SAT:** `CFDIPaymentTerm` = *Método de pago* SAT (PPD/PUE); `CFDIPaymentMethod` = *Forma de pago* SAT (transferencia, efectivo…). Cablearlo al revés rompería la validación de oro PPD/PUE.
6. **`CFDIUse` es un código interno** (enteros `3`, `23`), no la clave SAT (`G03`, `S01`…). Se necesita la tabla de mapeo (pedir a Pedro o doc tras login).
7. **Typo real en el API:** el detalle de `Clients` trae `Loctaion`/`LoctaionID` (sic).
8. **Inconsistencias lista vs detalle:** `Serie` (lista) vs `Series` (detalle); `Status` int (lista) vs `Status` string + `StatusCode` int (detalle); `CurrencyID` (lista) vs `CurrencyName` con el código (detalle); PPD/PUE y días de crédito **solo** en el detalle.
9. **Prefacturas visibles** en la misma colección `Invoices` (`UUID` null / `IsFiscalInvoice` false) — no hay recurso separado.
10. **`Activities` existe pero está vacío** en esta cuenta (0 filas) — el recurso que la doc pública usa de ejemplo no tiene datos aquí.
11. **500 transitorios** ocasionales que se resuelven con retry inmediato.
12. **Higiene de secretos:** el `.txt` del token estaba en la raíz del repo sin gitignorear (no trackeado aún) — se agregó `bind_token_api.txt` y `*.env` al `.gitignore` raíz. Recomendación vigente: moverlo a un gestor de secretos y borrarlo del correo/disco.
---
## 9 · Implicaciones para el MVP
Cruce contra el flujo objetivo del Discovery (#27): **Jira → cotización BIND → prefactura → validación humana → CFDI → envío**.
### 9.1 Lo que la API ya sostiene (solo lectura, hoy)
| Paso del flujo | Soporte confirmado |
|---|---|
| **Cotización** | `Quotes` legible con partidas, comercial (`EmployeeName`), moneda/TC y estatus (Activa/Cancelada/Surtida). La plataforma puede detectar cotizaciones nuevas y validar el prerequisito "cotización obligatoria" de Ara. |
| **Prefactura** | Listable vía `UUID eq null` / `IsFiscalInvoice eq false` → el dashboard "prefacturas pendientes de validación" es viable 100 % lectura. |
| **CFDI** | `UUID`, `Series`+`Number`, RFC, moneda, `ExchangeRate`, impuestos por partida (`Services[].VATRate`), uso CFDI (código), PPD/PUE (`CFDIPaymentTerm` en detalle), creador y fechas. |
| **Validaciones de oro** | • **PPD/PUE:** auditable por factura (detalle). La plataforma puede alertar "PUE detectado — ¿fue consciente?" apenas aparezca. • **IVA 16 %/0 %:** `VATRate` por partida + moneda + RFC → la regla "extranjero con IVA ≠ 0" (el error que Ara señaló en vivo) es detectable automáticamente. • **Días de crédito:** `Clients.CreditDays` (default) vs `PaymentTerms` (factura) — discrepancias detectables. |
| **Cobranza / aging** | `ExpirationDate` + saldo derivado (§4) + `Status` → aging y alertas internas sin recurso de pagos. |
| **Envío** | PDF real por API (`/{id}/pdf`) + correos del cliente (`Clients.Email`, `ContactEmails`) + las particularidades por cliente (Excel de Ara/Arturo) viven en la plataforma. |
### 9.2 Restricciones de diseño que impone lo encontrado
1. **Sync incremental obligatorio.** PPD/PUE y días de crédito viven en el **detalle** ⇒ 1 llamada por factura. Con ~55 facturas/mes es trivial, pero el histórico (>1,000) exige sincronizar por delta (`Date ge` la última corrida) y guardar en Postgres — nunca re-barrer todo el detalle.
2. **Trazabilidad cotización→factura la lleva la plataforma.** BIND no expone el vínculo; al orquestar la conversión (Etapa 2) la plataforma debe registrar el par `QuoteID→InvoiceID` en su propia BD (y/o convención en `Comments`, como hoy hacen con el ticket Jira).
3. **"Fecha de pago" = fecha de detección.** Sin pagos individuales, la plataforma registra cuándo *observó* el cambio a Pagada — suficiente para cobranza operativa; insuficiente para conciliación contable fina (que de todos modos es fase posterior).
4. **Catálogos internos a mapear:** `CFDIUse` (int→clave SAT) y códigos de `Status` no observados (3+). Confirmar con Pedro.
5. **Cliente HTTP:** paginar siempre (`$top=100`), retry en 500 transitorio, no usar `$select`, IDs estilo REST, contador local de cuota (sin headers de rate limit).
6. **Los complementos de pago (REP) no son visibles** — riesgo para el flujo PPD completo; escalar a Pedro (§10).
### 9.3 Presupuesto de peticiones (viabilidad del sync)
Escenario conservador: lista de facturas delta (12 req) + detalle solo de facturas nuevas/cambiadas (~3/día) + cotizaciones delta (1 req) + clientes delta (1 req) ⇒ **< 10 req por ciclo**. Con polling cada 15 min ≈ **~1,000 req/día**, 5 % del límite de 20K. Holgado.
---
## 10 · Lo que quedó SIN validar y por qué
| Pendiente | Por qué no se validó | Cómo cerrarlo |
|---|---|---|
| **Escritura** (crear cotización/prefactura, convertir, emitir CFDI, cancelar) | **Prohibido en esta actividad**: cuenta de producción, sin sandbox, efecto fiscal. Regla dura de solo-GET. | Doc detallada tras login (developers.bind.com.mx) con Pedro; luego dry-run + confirmación humana en Etapa 2, empezando por un documento de prueba interno coordinado con Arturo. |
| Si la factura creada desde una cotización hereda alguna referencia a ésta | Requiere ejecutar la conversión (= escritura). | Mismo camino que el punto anterior; o preguntar a Arturo si la UI muestra el vínculo. |
| Shape real del `/{id}/xml` (¿XML embebido? ¿URL?) | El body se descartó por política de no persistir datos reales en esta corrida. | 1 GET dirigido leyendo solo las **claves** del JSON (sin valores), en la próxima sesión técnica. |
| Mapa completo `CFDIUse` interno → clave SAT | No hay catálogo expuesto; solo se observaron códigos `3` y `23`. | Pedir tabla a Pedro o doc tras login. |
| Códigos de `Status` > 2 (¿parciales, vencidas?) | Los filtros 35 no devolvieron filas: o no existen o no hay ejemplares en la cuenta. | Doc tras login; observar en operación. |
| **Complementos de pago (REP)** para PPD | Ningún recurso visible con los nombres probados. | **Crítico** — preguntar a Pedro/soporte BIND; el flujo PPD del MVP lo necesita al menos en lectura. |
| Rate limit real (20K/día) y comportamiento al agotarlo | No hay headers de cuota y agotar el límite adrede sería irresponsable en producción. | Aceptar el dato de Noe (20K) y llevar contador local. |
| Shape de `Users`, `Orders`, `Providers`, `Banks`, `BankAccounts`, `PriceLists` | Fuera del flujo del MVP; `Users` además contiene datos personales. | Cuando conciliación (Anexo B) lo requiera. |
| Webhooks / eventos push | No documentados públicamente; no sondeables por GET. | Preguntar a Pedro; mientras, polling incremental. |
---
## Anexo · Reproducir la validación
```powershell
cd bind-api-sandbox
# .env debe tener BIND_API_TOKEN (nunca se versiona; .gitignore lo cubre)
npm run validate:real # ronda 1: auth + inventario + shapes + OData + byId
npx tsx src/validate-real-api.ts --round2 # pagos, estatus, prefactura, detalles, paginación
npx tsx src/validate-real-api.ts --round3 # tope $top, literales CFDI, pdf/xml
npx tsx src/validate-real-api.ts --round4 # aritmética del saldo + xml
```
- Presupuesto acumulado entre rondas (`VALIDATION_BUDGET`, default 120). El script aborta al agotarlo.
- El reporte `validation-output/report.json` está sanitizado (solo estructura) y además gitignoreado por defensa en profundidad.
- El script es GET-only por construcción: no contiene ningún código capaz de emitir escrituras.
[REGISTRO #22]: ../bitacora/REGISTRO.md
[REGISTRO #29]: ../bitacora/REGISTRO.md
+1
View File
@@ -11,6 +11,7 @@
"mock": "tsx src/mock-server/server.ts", "mock": "tsx src/mock-server/server.ts",
"demo": "tsx src/demo.ts", "demo": "tsx src/demo.ts",
"demo:prod": "BIND_BASE_URL=https://api.bind.com.mx tsx src/demo.ts", "demo:prod": "BIND_BASE_URL=https://api.bind.com.mx tsx src/demo.ts",
"validate:real": "tsx src/validate-real-api.ts",
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit"
}, },
"devDependencies": { "devDependencies": {
+110 -4
View File
@@ -6,9 +6,22 @@
* - dry-run: loguea el request que se haría sin enviarlo (útil para revisar * - dry-run: loguea el request que se haría sin enviarlo (útil para revisar
* un payload antes de aprobarlo manualmente). * un payload antes de aprobarlo manualmente).
* - Retries con backoff exponencial en 429 y 5xx (no en 4xx fuera de 429). * - Retries con backoff exponencial en 429 y 5xx (no en 4xx fuera de 429).
* El API real emite 500 transitorios ocasionales — confirmado 6-jul-2026.
* - Lleva contador local de requests para acercarse al límite de 20K/día * - Lleva contador local de requests para acercarse al límite de 20K/día
* con visibilidad temprana (cuota real la valida el servidor). * con visibilidad temprana (la cuota NO es observable en headers — confirmado).
* - Sin dependencias externas — usa fetch nativo de Node 20+. * - Sin dependencias externas — usa fetch nativo de Node 20+.
*
* Reconciliado contra el API real (validación 6-jul-2026, ver VALIDACION-API.md):
* - Auth: SOLO `Authorization: Bearer` — el Ocp-Apim-Subscription-Key no se requiere.
* - GET por ID: estilo REST `/api/{Recurso}/{id}` (el estilo OData `(guid'...')`
* responde 404 en producción). El mock local sigue usando `(guid'...')`, por
* eso el estilo es configurable (`idStyle`).
* - Recursos reales: `Clients` (no Customers), `Quotes`, `Currencies`,
* `Warehouses`, `Locations`. NO existe recurso `Payments` — el acumulado
* pagado viene en cada factura (campo `Payments`).
* - `$select` NO funciona (500) y `$top` acepta máximo 100.
* - Token inválido → 500 con body "API Key es inválida" (no 401) — no
* reintentamos 500 cuyo body reporte api key inválida.
*/ */
import { buildQueryString, type ODataQuery } from "./odata.js"; import { buildQueryString, type ODataQuery } from "./odata.js";
@@ -20,14 +33,35 @@ import type {
Payment, Payment,
Product, Product,
} from "./types.js"; } from "./types.js";
import type {
BindCollection,
ClientDetail,
ClientListItem,
CurrencyInfo,
InvoiceDetail,
InvoiceListItem,
LocationInfo,
QuoteDetail,
QuoteListItem,
WarehouseInfo,
} from "./types.real.js";
export type ClientMode = "read-only" | "dry-run" | "write"; export type ClientMode = "read-only" | "dry-run" | "write";
/**
* Estilo del GET por ID:
* - "rest": /api/Invoices/{id} → lo que el API REAL acepta (confirmado 6-jul-2026).
* - "odata": /api/Invoices(guid'{id}') → lo que implementa el mock local.
*/
export type IdStyle = "rest" | "odata";
export interface BindClientConfig { export interface BindClientConfig {
baseUrl: string; baseUrl: string;
apiKey: string; apiKey: string;
subscriptionKey?: string; subscriptionKey?: string;
mode?: ClientMode; mode?: ClientMode;
/** Default "rest" (API real). Usa "odata" contra el mock local. */
idStyle?: IdStyle;
/** Máximo de reintentos para 429/5xx. */ /** Máximo de reintentos para 429/5xx. */
maxRetries?: number; maxRetries?: number;
/** Logger opcional. Default: console. */ /** Logger opcional. Default: console. */
@@ -60,6 +94,7 @@ export class BindClient {
private readonly apiKey: string; private readonly apiKey: string;
private readonly subscriptionKey?: string; private readonly subscriptionKey?: string;
private readonly mode: ClientMode; private readonly mode: ClientMode;
private readonly idStyle: IdStyle;
private readonly maxRetries: number; private readonly maxRetries: number;
private readonly logger: Pick<Console, "info" | "warn" | "error">; private readonly logger: Pick<Console, "info" | "warn" | "error">;
private readonly fetchImpl: typeof fetch; private readonly fetchImpl: typeof fetch;
@@ -72,19 +107,78 @@ export class BindClient {
this.apiKey = cfg.apiKey; this.apiKey = cfg.apiKey;
this.subscriptionKey = cfg.subscriptionKey; this.subscriptionKey = cfg.subscriptionKey;
this.mode = cfg.mode ?? "read-only"; this.mode = cfg.mode ?? "read-only";
this.idStyle = cfg.idStyle ?? "rest";
this.maxRetries = cfg.maxRetries ?? 3; this.maxRetries = cfg.maxRetries ?? 3;
this.logger = cfg.logger ?? console; this.logger = cfg.logger ?? console;
this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch; this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch;
} }
// --- Recursos del MVP -------------------------------------------------- private byId(resource: string, id: string): string {
return this.idStyle === "rest"
? `/api/${resource}/${id}`
: `/api/${resource}(guid'${id}')`;
}
// --- Recursos REALES confirmados (validación 6-jul-2026) ----------------
/** GET /api/Invoices — lista con acumulados Payments/CreditNotes (saldo = Total ambos). */
invoiceList(query: ODataQuery = {}): Promise<BindCollection<InvoiceListItem>> {
return this.get<BindCollection<InvoiceListItem>>(`/api/Invoices${buildQueryString(query)}`);
}
/** GET /api/Invoices/{id} — única fuente de PPD/PUE (CFDIPaymentTerm) y días de crédito. */
invoiceDetail(id: string): Promise<InvoiceDetail> {
return this.get<InvoiceDetail>(this.byId("Invoices", id));
}
/** GET /api/Clients — así se llaman los clientes en el API real (no Customers). */
clients(query: ODataQuery = {}): Promise<BindCollection<ClientListItem>> {
return this.get<BindCollection<ClientListItem>>(`/api/Clients${buildQueryString(query)}`);
}
/** GET /api/Clients/{id} — trae CreditDays, contactos y (sic) Loctaion/LoctaionID. */
clientDetail(id: string): Promise<ClientDetail> {
return this.get<ClientDetail>(this.byId("Clients", id));
}
/** GET /api/Quotes — cotizaciones (0=Activa, 1=Cancelada, 2=Surtida). */
quotes(query: ODataQuery = {}): Promise<BindCollection<QuoteListItem>> {
return this.get<BindCollection<QuoteListItem>>(`/api/Quotes${buildQueryString(query)}`);
}
/** GET /api/Quotes/{id} — partidas Items[]; SIN referencia a la factura generada. */
quoteDetail(id: string): Promise<QuoteDetail> {
return this.get<QuoteDetail>(this.byId("Quotes", id));
}
currencies(query: ODataQuery = {}): Promise<BindCollection<CurrencyInfo>> {
return this.get<BindCollection<CurrencyInfo>>(`/api/Currencies${buildQueryString(query)}`);
}
warehouses(query: ODataQuery = {}): Promise<BindCollection<WarehouseInfo>> {
return this.get<BindCollection<WarehouseInfo>>(`/api/Warehouses${buildQueryString(query)}`);
}
locations(query: ODataQuery = {}): Promise<BindCollection<LocationInfo>> {
return this.get<BindCollection<LocationInfo>>(`/api/Locations${buildQueryString(query)}`);
}
/** GET /api/Invoices/{id}/pdf — devuelve el PDF binario del CFDI (insumo del módulo de envío). */
async invoicePdf(id: string): Promise<ArrayBuffer> {
return this.getBinary(`/api/Invoices/${id}/pdf`);
}
// --- Recursos de la era mock (types.ts aproximados) ----------------------
// El mock server sirve Customers/Payments con el schema aproximado previo a la
// validación. Se conservan para la demo local; NO usarlos contra producción
// (Customers → 404 real; Payments → 404 real — no existe el recurso).
customers(query: ODataQuery = {}): Promise<ODataCollection<Customer>> { customers(query: ODataQuery = {}): Promise<ODataCollection<Customer>> {
return this.get<ODataCollection<Customer>>(`/api/Customers${buildQueryString(query)}`); return this.get<ODataCollection<Customer>>(`/api/Customers${buildQueryString(query)}`);
} }
customer(id: string): Promise<Customer> { customer(id: string): Promise<Customer> {
return this.get<Customer>(`/api/Customers(guid'${id}')`); return this.get<Customer>(this.byId("Customers", id));
} }
invoices(query: ODataQuery = {}): Promise<ODataCollection<Invoice>> { invoices(query: ODataQuery = {}): Promise<ODataCollection<Invoice>> {
@@ -92,7 +186,7 @@ export class BindClient {
} }
invoice(id: string): Promise<Invoice> { invoice(id: string): Promise<Invoice> {
return this.get<Invoice>(`/api/Invoices(guid'${id}')`); return this.get<Invoice>(this.byId("Invoices", id));
} }
payments(query: ODataQuery = {}): Promise<ODataCollection<Payment>> { payments(query: ODataQuery = {}): Promise<ODataCollection<Payment>> {
@@ -133,6 +227,18 @@ export class BindClient {
return this.request<T>("GET", path); return this.request<T>("GET", path);
} }
/** GET binario (PDF del CFDI). Cuenta contra la cuota como cualquier request. */
private async getBinary(path: string): Promise<ArrayBuffer> {
this.rolloverIfNewDay();
this.requestCount++;
const headers: Record<string, string> = { Authorization: `Bearer ${this.apiKey}` };
if (this.subscriptionKey) headers["Ocp-Apim-Subscription-Key"] = this.subscriptionKey;
const url = `${this.baseUrl}${path}`;
const res = await this.fetchImpl(url, { method: "GET", headers });
if (!res.ok) throw new BindApiError(res.status, url, await safeJson(res));
return res.arrayBuffer();
}
private async request<T>(method: string, path: string, body?: unknown): Promise<T> { private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
if (MUTATING.has(method) && this.mode === "read-only") { if (MUTATING.has(method) && this.mode === "read-only") {
throw new BindReadOnlyViolation(method, path); throw new BindReadOnlyViolation(method, path);
+306
View File
@@ -0,0 +1,306 @@
/**
* Tipos CONFIRMADOS contra el API real de BIND (validación del 6-jul-2026,
* cuenta Balam, solo lectura). Fuente: VALIDACION-API.md + validation-output/report.json.
*
* Conviven con types.ts (la aproximación que consume el mock server): el mock
* queda intacto; el código que apunte a producción debe tipar con ESTOS.
*
* Notas duras del API real:
* - Los clientes son `Clients` (no `Customers`); no existe recurso `Payments`.
* - GET por ID es estilo REST (`/api/Invoices/{id}`), NO OData `(guid'...')`.
* - La lista y el detalle de un mismo recurso difieren en campos y hasta en
* nombres (`Serie` vs `Series`; `Status` int vs string+`StatusCode`).
* - `CFDIPaymentTerm` = Método de pago SAT (PPD/PUE) y `CFDIPaymentMethod` =
* Forma de pago SAT — nomenclatura invertida respecto al SAT.
* - `Loctaion`/`LoctaionID` es un typo real del API en el detalle de Clients.
* - Saldo por factura = Total Payments CreditNotes (misma fila de lista).
*/
export type Guid = string;
export type IsoDateTime = string; // "2026-07-06T00:00:00" (sin zona en lo observado)
// ─── Invoices ───────────────────────────────────────────────────────────────
/** Códigos de Invoices.Status confirmados vía filtros + detalle. */
export enum InvoiceStatusCode {
Activa = 0,
Pagada = 1,
Cancelada = 2,
}
/** Fila de GET /api/Invoices (lista, 32 campos). */
export interface InvoiceListItem {
ID: Guid;
/** ⚠️ En el detalle este campo se llama `Series`. */
Serie: string;
Number: number;
/** Folio fiscal. `null` ⇒ prefactura (sin timbrar). */
UUID: Guid | null;
Date: IsoDateTime;
/** Vencimiento — insumo del aging. No existe `DueDate`. */
ExpirationDate: IsoDateTime;
ClientID: Guid;
ClientName: string;
RFC: string;
Cost: number;
Subtotal: number;
Discount: number;
VAT: number;
IEPS: number;
ISRRet: number;
VATRet: number;
Total: number;
/** Acumulado PAGADO de la factura (no es una colección). */
Payments: number;
/** Acumulado de notas de crédito aplicadas. */
CreditNotes: number;
CurrencyID: Guid;
LocationID: Guid;
WarehouseID: Guid;
PriceListID: Guid;
/** Código INTERNO de BIND (se observaron 3, 23) — no es la clave SAT (G03…). */
CFDIUse: number;
ExchangeRate: number;
VATRetRate: number;
Comments: string;
VATRate: number;
PurchaseOrder: string;
/** false ⇒ prefactura. */
IsFiscalInvoice: boolean;
ShowIEPS: boolean;
Status: InvoiceStatusCode;
}
/** Partida de servicios del detalle de factura. */
export interface InvoiceServiceLine {
ID: Guid;
IndexNumber: number;
ServiceID: Guid;
Name: string;
Code: string;
Qty: number;
Price: number;
/** Tasa de IVA por partida — habilita la validación 16 % MXN / 0 % extranjero. */
VATRate: number;
Discount: number;
}
/** GET /api/Invoices/{id} (detalle, 50 campos). Campos exclusivos vs lista. */
export interface InvoiceDetail {
ID: Guid;
UUID: Guid | null;
/** ⚠️ La lista lo llama `Serie`. */
Series: string;
Number: number;
ClientID: Guid;
ClientName: string;
/** Días de crédito de la factura — solo en detalle. */
PaymentTerms: number;
/** Etiqueta legible ("Activa" | "Pagada" | "Cancelada"). */
Status: string;
StatusCode: InvoiceStatusCode;
ClientPhoneNumber: string | null;
ClientContact: string | null;
RFC: string;
CreatedByID: Guid;
CreatedByName: string;
CreationDate: IsoDateTime;
ApplicationDate: IsoDateTime;
PriceListID: Guid;
PriceListName: string;
LocationID: Guid;
LocationName: string;
WarehouseID: Guid;
WarehouseName: string;
/** ⚠️ FORMA de pago SAT (ej. "Transferencia Electrónica de Fondos", "Por Definir"). */
CFDIPaymentMethod: string;
/** ⚠️ MÉTODO de pago SAT — PPD/PUE (ej. "PAGO EN UNA SOLA EXHIBICIÓN"). Puede venir vacío. */
CFDIPaymentTerm: string;
CFDIAccountNumber: string;
/** Código de 3 letras ("MXN"/"USD") — a pesar del nombre. */
CurrencyName: string;
ExchangeRate: number;
PurchaseOrder: string;
FiscalID: Guid;
Address: string;
Comments: string;
Subtotal: number;
Discount: number;
VAT: number;
IEPS: number;
VATRet: number;
ISRRet: number;
Payments: number;
CreditNotes: number;
Products: unknown[]; // partidas de producto (vacío en Balam — facturan servicios)
Services: InvoiceServiceLine[];
}
/** Saldo abierto por factura (Plan A operativo — ver VALIDACION-API.md §4). */
export function invoiceOpenBalance(inv: Pick<InvoiceListItem, "Total" | "Payments" | "CreditNotes">): number {
return inv.Total - inv.Payments - inv.CreditNotes;
}
// ─── Clients ────────────────────────────────────────────────────────────────
/** Fila de GET /api/Clients (lista, 10 campos). */
export interface ClientListItem {
ID: Guid;
Number: number;
ClientName: string;
LegalName: string;
RFC: string;
Email: string | null;
Phone: string | null;
NextContactDate: IsoDateTime | null;
LocationID: Guid;
RegimenFiscal: string;
}
/** GET /api/Clients/{id} (detalle, 28 campos). */
export interface ClientDetail {
ID: Guid;
RFC: string;
LegalName: string;
CommercialName: string;
/** Días de crédito default del cliente (30/45/90 del Discovery). */
CreditDays: number;
CreditAmount: number;
PaymentMethod: string;
CreationDate: IsoDateTime;
Status: string;
SalesContact: string;
CreditContact: string;
/** ⚠️ Typo REAL del API (sic). */
Loctaion: string;
/** ⚠️ Typo REAL del API (sic). */
LoctaionID: Guid;
Comments: string;
PriceList: string;
PriceListID: Guid;
PaymentTermType: string;
Email: string | null;
Telephones: string | null;
Number: number;
AccountNumber: string | null;
DefaultDiscount: number | null;
ClientSource: string;
Account: string;
City: string;
State: string;
Addresses: unknown[];
RegimenFiscal: string;
}
// ─── Quotes ─────────────────────────────────────────────────────────────────
/** Códigos de Quotes.Status confirmados (StatusText de la misma fila). */
export enum QuoteStatusCode {
Activa = 0,
Cancelada = 1,
Surtida = 2,
}
/** Fila de GET /api/Quotes (lista, 11 campos). */
export interface QuoteListItem {
ID: Guid;
Number: string;
CreationDate: IsoDateTime;
ClientName: string;
Locations: string;
Comments: string | null;
TotalOriginalCurrency: number;
/** Nombre ("Peso mexicano") — el código de 3 letras vive en el detalle. */
Currency: string;
Status: QuoteStatusCode;
Total: number;
StatusText: string | null;
}
/** Partida del detalle de cotización. */
export interface QuoteItem {
ID: Guid;
Code: string;
ProductID: Guid;
ProductName: string;
Unit: string;
Qty: number;
Price: number;
Amount: number;
IEPS: number;
VAT: number;
IndexNumber: number;
}
/** GET /api/Quotes/{id} (detalle, 45 campos).
* ⚠️ NO trae referencia a la factura generada — la trazabilidad la lleva la plataforma. */
export interface QuoteDetail {
ID: Guid;
QuoteNumber: string;
ClientName: string;
ClientContact: string;
ClientID: Guid;
ClientPhone: string | null;
LocationName: string;
LocationID: Guid;
PriceListName: string;
PriceListID: Guid;
EmployeeName: string;
EmployeeID: Guid;
CurrencyCode: string;
ExchangeRate: number;
CreationDate: IsoDateTime;
Status: QuoteStatusCode;
StatusText: string | null;
Subtotal: number;
Discount: number;
IEPS: number;
VAT: number;
VATRate: number;
ISR: number;
ISRRate: number;
Total: number;
BaseCurrency: boolean;
Comments: string | null;
OriginalCurrencyDiscountAmount: number;
OriginalCurrencySubtotal: number;
IsPercentage: boolean;
ContactEmails: string | null;
ExternalIDType: number;
VatRet: number;
Items: QuoteItem[];
}
// ─── Catálogos ──────────────────────────────────────────────────────────────
export interface CurrencyInfo {
ID: Guid;
Name: string;
Code: string; // "MXN", "USD"…
ExchangeRate: number;
}
export interface WarehouseInfo {
ID: Guid;
Name: string;
LocationID: Guid;
AvailableInOtherLoc: boolean;
}
export interface LocationInfo {
ID: Guid;
Name: string;
Street: string;
ExtNumber: string;
IntNumber: string;
ZipCode: string;
Colonia: string;
City: string;
State: string;
}
/** Respuesta de colección del API real: { value: [...] } sin count ni nextLink
* (el conteo total NO es accesible; paginar con $top=100 + $skip). */
export interface BindCollection<T> {
value: T[];
}
+6 -1
View File
@@ -20,9 +20,14 @@ import { and, eq, ge, guid, lt } from "./client/odata.js";
const cfg = { const cfg = {
baseUrl: process.env.BIND_BASE_URL ?? "http://localhost:4010", baseUrl: process.env.BIND_BASE_URL ?? "http://localhost:4010",
apiKey: process.env.BIND_API_KEY ?? "mock-bearer-token", apiKey: process.env.BIND_API_TOKEN ?? process.env.BIND_API_KEY ?? "mock-bearer-token",
subscriptionKey: process.env.BIND_SUBSCRIPTION_KEY, subscriptionKey: process.env.BIND_SUBSCRIPTION_KEY,
mode: (process.env.BIND_MODE as "read-only" | "dry-run" | "write") ?? "read-only", mode: (process.env.BIND_MODE as "read-only" | "dry-run" | "write") ?? "read-only",
// El mock local implementa el GET por ID estilo OData (guid'...'); el API
// real usa estilo REST /{id} (validado 6-jul-2026 — ver VALIDACION-API.md §6).
idStyle: (/localhost|127\.0\.0\.1/.test(process.env.BIND_BASE_URL ?? "localhost")
? "odata"
: "rest") as "odata" | "rest",
}; };
const client = new BindClient(cfg); const client = new BindClient(cfg);
+857
View File
@@ -0,0 +1,857 @@
/**
* Validación técnica de la API REAL de BIND ERP (producción, cuenta Balam).
* Actividad "Validación técnica de la API de BIND" — Etapa 0.
*
* REGLAS DURAS (no negociables):
* - SOLO LECTURA. Este archivo únicamente construye peticiones GET; no existe
* código capaz de emitir POST/PUT/PATCH/DELETE.
* - El token se lee de `.env` (BIND_API_TOKEN) y JAMÁS se imprime, se loguea
* ni se escribe en el reporte. El serializado final pasa por un scrub que
* además redacta cualquier patrón tipo RFC o email por si el sanitizador
* estructural dejara pasar algo.
* - El reporte solo conserva ESTRUCTURA: nombres de campos, tipos, formatos,
* conteos, códigos de estatus. Nunca valores reales (nombres, RFCs, montos,
* folios, correos).
* - Presupuesto duro de peticiones (default 120 < 150 acordado; el límite de
* BIND es 20K/día). Cada retry cuenta contra el presupuesto.
*
* Salida: validation-output/report.json (sanitizado; el folder está gitignoreado
* por defensa en profundidad) + resumen sanitizado en consola.
*
* Uso: npm run validate:real
*/
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const HERE = dirname(fileURLToPath(import.meta.url));
const ROOT = join(HERE, "..");
const OUT_DIR = join(ROOT, "validation-output");
// ─── Configuración ──────────────────────────────────────────────────────────
const env = loadEnv();
const BASE = (env.BIND_BASE_URL ?? process.env.BIND_BASE_URL ?? "https://api.bind.com.mx").replace(/\/+$/, "");
const TOKEN = env.BIND_API_TOKEN ?? env.BIND_API_KEY ?? process.env.BIND_API_TOKEN ?? "";
const BUDGET = Number(env.VALIDATION_BUDGET ?? 120);
const PACE_MS = 120; // pausa entre peticiones — gentileza con producción
function loadEnv(): Record<string, string> {
const out: Record<string, string> = {};
try {
const raw = readFileSync(join(ROOT, ".env"), "utf8");
for (const line of raw.split(/\r?\n/)) {
const m = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*?)\s*$/.exec(line);
if (m && m[1] && m[2] !== undefined) out[m[1]] = m[2].replace(/^["']|["']$/g, "");
}
} catch {
/* sin .env — se valida abajo */
}
return out;
}
// ─── Sonda HTTP (GET-only por construcción) ─────────────────────────────────
let used = 0;
interface Probe {
path: string;
status: number;
ok: boolean;
contentType: string | null;
headers: Record<string, string>; // allowlist no sensible
bodyShape: "array" | "odata-value" | "object" | "empty" | "non-json";
rowCount: number | null;
count: number | string | null; // odata.count viene como string en OData v3
nextLink: boolean;
errorSnippet?: string;
/** SOLO en memoria — nunca va al reporte. */
rows: unknown[] | null;
}
const HEADER_KEEP = /rate|limit|quota|remain|retry-after|dataserviceversion|odata-version|content-type|www-authenticate|apim/i;
async function probeGet(path: string, tokenOverride?: string | null): Promise<Probe> {
if (used >= BUDGET) throw new Error(`Presupuesto de ${BUDGET} peticiones agotado — abortando por seguridad.`);
const token = tokenOverride === undefined ? TOKEN : tokenOverride;
for (let attempt = 0; attempt < 2; attempt++) {
used++;
const headers: Record<string, string> = { Accept: "application/json" };
if (token) headers.Authorization = `Bearer ${token}`;
let res: Response;
try {
res = await fetch(`${BASE}${path}`, {
method: "GET", // ÚNICO método en todo el archivo
headers,
signal: AbortSignal.timeout(25_000),
});
} catch (err) {
await sleep(PACE_MS);
if (attempt === 0) continue;
return {
path, status: 0, ok: false, contentType: null, headers: {},
bodyShape: "empty", rowCount: null, count: null, nextLink: false,
errorSnippet: `network: ${scrub(String((err as Error).message)).slice(0, 120)}`, rows: null,
};
}
const keep: Record<string, string> = {};
res.headers.forEach((v, k) => { if (HEADER_KEEP.test(k)) keep[k] = v; });
const text = await res.text();
let json: unknown = null;
try { json = text ? JSON.parse(text) : null; } catch { /* non-json */ }
if ((res.status === 429 || res.status >= 500) && attempt === 0) {
const ra = Number(res.headers.get("Retry-After") ?? 2);
console.log(`${res.status} en ${path} — retry en ${ra}s`);
await sleep(Math.min(ra, 10) * 1000);
continue;
}
const { rows, bodyShape, count, nextLink } = extractRows(json, text);
const probe: Probe = {
path, status: res.status, ok: res.ok,
contentType: res.headers.get("content-type"),
headers: keep, bodyShape,
rowCount: rows ? rows.length : null,
count, nextLink, rows,
};
if (!res.ok) {
const raw = typeof json === "object" && json !== null ? JSON.stringify(json) : text;
probe.errorSnippet = scrub(raw ?? "").slice(0, 300);
}
await sleep(PACE_MS);
return probe;
}
throw new Error("unreachable");
}
function extractRows(json: unknown, text: string): Pick<Probe, "rows" | "bodyShape" | "count" | "nextLink"> {
if (json === null) return { rows: null, bodyShape: text.trim() ? "non-json" : "empty", count: null, nextLink: false };
if (Array.isArray(json)) return { rows: json, bodyShape: "array", count: null, nextLink: false };
if (typeof json === "object") {
const o = json as Record<string, unknown>;
const value = o["value"];
if (Array.isArray(value)) {
const count = (o["odata.count"] ?? o["@odata.count"] ?? null) as number | string | null;
const nextLink = Boolean(o["odata.nextLink"] ?? o["@odata.nextLink"]);
return { rows: value, bodyShape: "odata-value", count, nextLink };
}
return { rows: [json], bodyShape: "object", count: null, nextLink: false };
}
return { rows: null, bodyShape: "non-json", count: null, nextLink: false };
}
// ─── Sanitizador estructural ────────────────────────────────────────────────
interface FieldInfo {
name: string;
types: string[];
formats: string[];
nullable: boolean;
enumValues?: string[];
}
/** Campos cuyo VALOR es un código de proceso (no dato personal) y puede documentarse. */
const ENUM_FIELD = /status|estatus|type|tipo|method|metodo|use|uso|currency|moneda|cfdi|way/i;
/** Nunca documentar valores de campos que huelan a monto/cantidad aunque matcheen arriba. */
const ENUM_EXCLUDE = /total|amount|monto|price|cost|balance|exchange|sum|qty|quantity|rate|saldo/i;
/** Literales de catálogo SAT (PPD/PUE, uso CFDI) — seguros y valiosos; se permite más largo. */
const SAT_CATALOG_FIELD = /cfdi(use|paymentmethod|paymentterm)|paymentmethod|regimenfiscal/i;
function formatHint(v: unknown): string {
if (v === null || v === undefined) return "null";
if (typeof v === "boolean") return "boolean";
if (typeof v === "number") return Number.isInteger(v) ? "integer" : "decimal";
if (Array.isArray(v)) return "array";
if (typeof v === "object") return "object";
const s = String(v);
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s)) return "guid/uuid";
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(s)) return "datetime-iso";
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return "date-iso";
if (/^\/Date\(-?\d+([+-]\d{4})?\)\/$/.test(s)) return "datetime-wcf(/Date(ms)/)";
if (/^[\w.+-]+@[\w-]+\.[\w.]+$/.test(s)) return "email(REDACTADO)";
if (/^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/.test(s)) return "rfc(REDACTADO)";
if (/^https?:\/\//.test(s)) return "url";
if (/^[A-Z]{3}$/.test(s)) return "code-3letras";
return `string(≈${lenBucket(s.length)})`;
}
function lenBucket(n: number): string {
if (n === 0) return "vacío";
if (n <= 10) return "corto";
if (n <= 40) return "medio";
return "largo";
}
function safeEnumValue(fieldName: string, v: unknown): string | null {
if (ENUM_EXCLUDE.test(fieldName)) return null;
if (!ENUM_FIELD.test(fieldName)) return null;
// Números: solo enteros pequeños (códigos de catálogo), jamás montos/decimales.
if (typeof v === "number") return Number.isInteger(v) && Math.abs(v) < 1000 ? String(v) : null;
const maxLen = SAT_CATALOG_FIELD.test(fieldName) ? 60 : 14;
if (typeof v !== "string" || v.length === 0 || v.length > maxLen) return null;
const h = formatHint(v);
if (/REDACTADO|guid|datetime|date-iso|url/.test(h)) return null;
return v;
}
/** Analiza filas y devuelve SOLO estructura. Recorre objetos anidados un nivel (Lines[].Campo). */
function analyzeRows(rows: unknown[], cap = 5): FieldInfo[] {
const acc = new Map<string, { types: Set<string>; formats: Set<string>; nullable: boolean; enums: Set<string> }>();
const visit = (obj: Record<string, unknown>, prefix: string) => {
for (const [k, v] of Object.entries(obj)) {
const name = prefix + k;
let rec = acc.get(name);
if (!rec) { rec = { types: new Set(), formats: new Set(), nullable: false, enums: new Set() }; acc.set(name, rec); }
if (v === null || v === undefined) { rec.nullable = true; rec.types.add("null"); continue; }
rec.types.add(Array.isArray(v) ? "array" : typeof v);
rec.formats.add(formatHint(v));
const ev = safeEnumValue(k, v);
if (ev !== null && rec.enums.size < 10) rec.enums.add(ev);
if (!prefix && Array.isArray(v) && typeof v[0] === "object" && v[0] !== null) {
visit(v[0] as Record<string, unknown>, `${k}[].`);
} else if (!prefix && typeof v === "object" && !Array.isArray(v)) {
visit(v as Record<string, unknown>, `${k}.`);
}
}
};
for (const row of rows.slice(0, cap)) {
if (typeof row === "object" && row !== null && !Array.isArray(row)) {
visit(row as Record<string, unknown>, "");
}
}
return [...acc.entries()].map(([name, r]) => {
const fi: FieldInfo = {
name,
types: [...r.types],
formats: [...r.formats],
nullable: r.nullable,
};
if (r.enums.size > 0) fi.enumValues = [...r.enums];
return fi;
});
}
function scrub(s: string): string {
let out = s;
if (TOKEN) out = out.replaceAll(TOKEN, "[TOKEN-REDACTADO]");
return out
.replace(/[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}/g, "[RFC-REDACTADO]")
.replace(/[\w.+-]+@[\w-]+\.[\w.]+/g, "[EMAIL-REDACTADO]");
}
function sleep(ms: number): Promise<void> {
return new Promise((r) => setTimeout(r, ms));
}
// ─── Reporte ────────────────────────────────────────────────────────────────
interface InventoryEntry {
resource: string;
path: string;
status: number;
bodyShape: string;
rowCount: number | null;
note: string;
}
const report = {
meta: {
ranAt: new Date().toISOString(),
baseUrl: BASE,
tokenSource: ".env BIND_API_TOKEN (usuario BIND: Arturo Rosas, según correo de Pedro 6-jul-2026)",
budget: BUDGET,
requestsUsed: 0,
note: "Reporte sanitizado: solo estructura (campos, tipos, formatos, conteos, códigos). Sin valores reales.",
},
auth: {} as Record<string, unknown>,
inventory: [] as InventoryEntry[],
shapes: {} as Record<string, { rowsAnalyzed: number; totalCount: number | string | null; fields: FieldInfo[] }>,
odata: {} as Record<string, unknown>,
byId: {} as Record<string, unknown>,
multiCompany: {} as Record<string, unknown>,
balanceQuestion: {} as Record<string, unknown>,
headersObserved: {} as Record<string, string>,
paymentsHunt: {} as Record<string, unknown>,
statusSemantics: {} as Record<string, unknown>,
prefactura: {} as Record<string, unknown>,
pagination: {} as Record<string, unknown>,
seriesHunt: {} as Record<string, unknown>,
};
function projection(p: Probe): Omit<Probe, "rows"> {
const { rows: _rows, ...rest } = p;
return rest;
}
// ─── Fases ──────────────────────────────────────────────────────────────────
const PRIORITY_RESOURCES = [
"Invoices", "Clients", "Customers", "Payments",
"Quotes", "Quotations", "Cotizaciones",
"Products", "Currencies", "Warehouses", "Locations", "Branches", "Sucursales", "Series",
];
const SECONDARY_RESOURCES = [
"Activities", "CreditNotes", "Taxes", "PriceLists", "Prices",
"Orders", "SalesOrders", "PurchaseOrders", "Providers", "Suppliers",
"Banks", "BankAccounts", "Sellers", "Employees", "Users",
"Companies", "Expenses", "Inventory", "CFDI", "CFDIs",
];
async function phaseAuth(): Promise<string> {
console.log("\n── Fase 1 · Autenticación");
// Endpoint de referencia barato. Products está documentado públicamente.
const ok = await probeGet("/api/Products?$top=1");
const noToken = await probeGet("/api/Products?$top=1", null);
const badToken = await probeGet("/api/Products?$top=1", "invalid-token-abc123");
report.auth = {
scheme: "Authorization: Bearer <token> (único header; sin Ocp-Apim-Subscription-Key)",
validToken: projection(ok),
missingToken: projection(noToken),
invalidToken: projection(badToken),
};
Object.assign(report.headersObserved, ok.headers);
console.log(` token válido → ${ok.status} · sin token → ${noToken.status} · token corrupto → ${badToken.status}`);
if (!ok.ok) {
console.log(" ⚠️ El token de .env NO autenticó contra /api/Products. Revisar antes de seguir.");
}
return ok.ok ? "ok" : "fail";
}
async function phaseInventory(): Promise<Map<string, Probe>> {
console.log("\n── Fase 2 · Inventario de recursos (GET {recurso}?$top=1)");
const results = new Map<string, Probe>();
for (const res of [...PRIORITY_RESOURCES, ...SECONDARY_RESOURCES]) {
let p = await probeGet(`/api/${res}?$top=1`);
let note = "";
// Algunos endpoints podrían rechazar $top — reintenta plano solo para prioritarios.
if (p.status === 400 && PRIORITY_RESOURCES.includes(res)) {
const plain = await probeGet(`/api/${res}`);
if (plain.ok) { p = plain; note = "existe pero rechaza $top=1 (400)"; }
else note = "400 con y sin $top";
}
if (p.status === 404) note ||= "no existe con este nombre";
if (p.status === 401 || p.status === 403) note ||= "sin permiso para este token";
if (p.ok) note ||= `responde ${p.bodyShape}`;
results.set(res, p);
report.inventory.push({
resource: res, path: p.path, status: p.status,
bodyShape: p.bodyShape, rowCount: p.rowCount, note,
});
Object.assign(report.headersObserved, p.headers);
console.log(` [${String(used).padStart(3)}/${BUDGET}] ${res.padEnd(15)}${p.status}${note ? ` (${note})` : ""}`);
}
return results;
}
async function phaseShapes(inventory: Map<string, Probe>): Promise<Map<string, unknown[]>> {
console.log("\n── Fase 3 · Inventario de campos ($top=5, solo estructura)");
const rowsByResource = new Map<string, unknown[]>();
const targets = [...PRIORITY_RESOURCES, "Companies", "CreditNotes", "Activities"]
.filter((r) => inventory.get(r)?.ok);
for (const res of targets) {
const p = await probeGet(`/api/${res}?$top=5`);
const rows = p.rows ?? [];
rowsByResource.set(res, rows);
report.shapes[res] = {
rowsAnalyzed: Math.min(rows.length, 5),
totalCount: p.count,
fields: analyzeRows(rows),
};
console.log(` [${String(used).padStart(3)}/${BUDGET}] ${res.padEnd(15)}${rows.length} filas analizadas, ${report.shapes[res].fields.length} campos`);
}
return rowsByResource;
}
async function phaseOData(rowsByResource: Map<string, unknown[]>): Promise<void> {
console.log("\n── Fase 4 · Mecánica OData");
// Elige el mejor recurso disponible para las pruebas.
const resource = ["Invoices", "Products", "Clients", "Customers"].find((r) => rowsByResource.has(r));
if (!resource) { report.odata = { skipped: "ningún recurso disponible" }; return; }
const fields = report.shapes[resource]?.fields ?? [];
const idField = fields.find((f) => /^id$/i.test(f.name))?.name ?? fields.find((f) => f.formats.includes("guid/uuid"))?.name;
const dateField = fields.find((f) => f.formats.some((x) => x.startsWith("datetime")))?.name;
const numField = fields.find((f) => /integer|decimal/.test(f.formats.join()) && !/id/i.test(f.name))?.name;
const enumField = fields.find((f) => f.enumValues?.length);
const odata: Record<string, unknown> = { resourceUsed: resource, idField, dateField, numField };
// $top / $skip coherentes
const a = await probeGet(`/api/${resource}?$top=2`);
const b = await probeGet(`/api/${resource}?$top=1&$skip=1`);
if (idField && a.rows?.length === 2 && b.rows?.length === 1) {
const id = (r: unknown) => (r as Record<string, unknown>)[idField];
odata.topSkip = { works: id(a.rows[1]) === id(b.rows[0]), statuses: [a.status, b.status] };
} else {
odata.topSkip = { works: null, statuses: [a.status, b.status], note: "sin filas suficientes para comparar" };
}
// $orderby
if (dateField) {
const o = await probeGet(`/api/${resource}?$top=3&$orderby=${encodeURIComponent(`${dateField} asc`)}`);
let sorted: boolean | null = null;
if (o.rows && o.rows.length >= 2) {
const vals = o.rows.map((r) => String((r as Record<string, unknown>)[dateField] ?? ""));
sorted = vals.every((v, i) => i === 0 || v >= String(vals[i - 1]));
}
odata.orderby = { field: dateField, status: o.status, ascendingVerified: sorted };
}
// Conteo total: v3 ($inlinecount) vs v4 ($count)
const v3 = await probeGet(`/api/${resource}?$top=1&$inlinecount=allpages`);
const v4 = await probeGet(`/api/${resource}?$top=1&$count=true`);
odata.countMechanism = {
"v3 $inlinecount=allpages": { status: v3.status, countReturned: v3.count !== null, totalCount: v3.count },
"v4 $count=true": { status: v4.status, countReturned: v4.count !== null, totalCount: v4.count },
};
// $filter numérico
if (numField) {
const f = await probeGet(`/api/${resource}?$top=1&$filter=${encodeURIComponent(`${numField} ge 0`)}`);
odata.filterNumeric = { expr: `${numField} ge 0`, status: f.status, rows: f.rowCount };
}
// $filter por enum observado (código de proceso, no dato personal)
if (enumField?.enumValues?.[0] !== undefined) {
const isNum = /^\d+$/.test(enumField.enumValues[0]);
const lit = isNum ? enumField.enumValues[0] : `'${enumField.enumValues[0]}'`;
const f = await probeGet(`/api/${resource}?$top=1&$filter=${encodeURIComponent(`${enumField.name} eq ${lit}`)}`);
odata.filterEnum = { expr: `${enumField.name} eq ${lit}`, status: f.status, rows: f.rowCount };
}
// $filter por fecha: sintaxis v3 (datetime'...') vs v4 (literal ISO)
if (dateField) {
const fv3 = await probeGet(`/api/${resource}?$top=1&$filter=${encodeURIComponent(`${dateField} ge datetime'2020-01-01T00:00:00'`)}`);
let fv4: Probe | null = null;
if (!fv3.ok) fv4 = await probeGet(`/api/${resource}?$top=1&$filter=${encodeURIComponent(`${dateField} ge 2020-01-01T00:00:00Z`)}`);
odata.filterDate = {
"v3 datetime'...'": fv3.status,
...(fv4 ? { "v4 ISO literal": fv4.status } : {}),
verdict: fv3.ok ? "sintaxis OData v3" : fv4?.ok ? "sintaxis OData v4" : "ninguna funcionó",
};
}
// $select
if (idField) {
const s = await probeGet(`/api/${resource}?$top=1&$select=${idField}`);
odata.select = { status: s.status, works: s.ok };
// Página default (barata: solo IDs) — tamaño de página y nextLink
if (s.ok) {
const d = await probeGet(`/api/${resource}?$select=${idField}`);
odata.defaultPage = { rowsReturned: d.rowCount, nextLinkPresent: d.nextLink, totalCount: d.count, status: d.status };
}
}
report.odata = odata;
console.log(` recurso de prueba: ${resource} · resultados en reporte`);
}
async function phaseById(rowsByResource: Map<string, unknown[]>): Promise<void> {
console.log("\n── Fase 5 · GET por ID");
const resource = ["Invoices", "Clients", "Customers", "Products"].find((r) => rowsByResource.has(r) && (rowsByResource.get(r)?.length ?? 0) > 0);
if (!resource) { report.byId = { skipped: "sin filas para tomar un ID" }; return; }
const fields = report.shapes[resource]?.fields ?? [];
const idField = fields.find((f) => /^id$/i.test(f.name))?.name;
if (!idField) { report.byId = { skipped: "sin campo ID identificable" }; return; }
const firstId = String((rowsByResource.get(resource)![0] as Record<string, unknown>)[idField] ?? "");
if (!firstId) { report.byId = { skipped: "ID vacío" }; return; }
const odataStyle = await probeGet(`/api/${resource}(guid'${firstId}')`);
let restStyle: Probe | null = null;
if (!odataStyle.ok) restStyle = await probeGet(`/api/${resource}/${firstId}`);
report.byId = {
resource,
"odata (guid'...')": odataStyle.status,
...(restStyle ? { "rest (/{id})": restStyle.status } : {}),
verdict: odataStyle.ok ? "estilo OData key" : restStyle?.ok ? "estilo REST /{id}" : "ninguno funcionó",
// ¿El detalle trae más campos que la lista? (p.ej. Lines embebidas)
detailFieldCount: odataStyle.ok || restStyle?.ok
? analyzeRows((odataStyle.ok ? odataStyle : restStyle!).rows ?? []).length
: null,
listFieldCount: fields.length,
};
if (odataStyle.ok || restStyle?.ok) {
const detail = (odataStyle.ok ? odataStyle : restStyle!).rows ?? [];
report.shapes[`${resource}(detalle por ID)`] = {
rowsAnalyzed: detail.length,
totalCount: null,
fields: analyzeRows(detail),
};
}
console.log(` ${resource} por ID → OData:${odataStyle.status}${restStyle ? ` / REST:${restStyle.status}` : ""}`);
}
function phaseBalanceVerdict(): void {
const inv = report.shapes["Invoices"] ?? report.shapes["Invoices(detalle por ID)"];
if (!inv) { report.balanceQuestion = { verdict: "SIN VALIDAR — Invoices no accesible" }; return; }
const all = [
...(report.shapes["Invoices"]?.fields ?? []),
...(report.shapes["Invoices(detalle por ID)"]?.fields ?? []),
];
const balanceish = [...new Set(all.filter((f) => /balance|saldo|due|paid|pending|remain|credit|debt|payment/i.test(f.name)).map((f) => f.name))];
report.balanceQuestion = {
fieldsMatching: balanceish,
verdict: balanceish.length > 0
? "REVISAR nombres arriba — hay candidatos a saldo por factura (Plan A probable)"
: "Sin campo de saldo visible en Invoices (apunta a Plan B: total pagos)",
};
}
function phaseMultiCompany(inventory: Map<string, Probe>): void {
const companies = inventory.get("Companies");
const companyFields: string[] = [];
for (const [res, shape] of Object.entries(report.shapes)) {
for (const f of shape.fields) {
if (/company|empresa/i.test(f.name)) companyFields.push(`${res}.${f.name}`);
}
}
report.multiCompany = {
companiesEndpoint: companies ? { status: companies.status, rowCount: companies.rowCount } : "no sondeado",
companyLikeFields: companyFields,
note: "1 token = 1 usuario BIND (kickoff #22). Si Companies no existe o regresa 1 fila, el token está acotado a la empresa del usuario (Balam).",
};
}
// ─── Fases de ronda 2 (sondeos dirigidos) ─────────────────────────────
async function phasePaymentsHunt(): Promise<void> {
console.log("\n── Ronda 2 · Búsqueda del recurso de pagos");
const candidates = [
"Payment", "ClientPayments", "CustomerPayments", "Incomes", "Income",
"Deposits", "Collections", "PaymentComplements", "Complements", "CashReceipts",
"AccountsReceivable", "Receivables",
];
const found: Record<string, number> = {};
for (const c of candidates) {
const p = await probeGet(`/api/${c}?$top=1`);
found[c] = p.status;
console.log(` [${String(used).padStart(3)}/${BUDGET}] ${c.padEnd(20)}${p.status}`);
if (p.ok && p.rows) {
report.shapes[c] = { rowsAnalyzed: p.rows.length, totalCount: p.count, fields: analyzeRows(p.rows) };
}
}
// Sub-recurso bajo factura: /api/Invoices/{id}/Payments
const inv = await probeGet("/api/Invoices?$top=1");
const invId = inv.rows?.[0] ? String((inv.rows[0] as Record<string, unknown>)["ID"] ?? "") : "";
const subProbes: Record<string, number> = {};
if (invId) {
for (const sub of ["Payments", "payments", "CreditNotes"]) {
const p = await probeGet(`/api/Invoices/${invId}/${sub}`);
subProbes[`Invoices/{id}/${sub}`] = p.status;
console.log(` [${String(used).padStart(3)}/${BUDGET}] Invoices/{id}/${sub.padEnd(12)}${p.status}`);
if (p.ok && p.rows?.length) {
report.shapes[`Invoices/{id}/${sub}`] = { rowsAnalyzed: p.rows.length, totalCount: p.count, fields: analyzeRows(p.rows) };
}
}
}
report.paymentsHunt = {
collectionCandidates: found,
subResources: subProbes,
invoiceEmbeddedField: "Invoices.Payments es numérico (acumulado pagado) — ver shapes",
};
}
async function phaseStatusSemantics(): Promise<void> {
console.log("\n── Ronda 2 · Semántica de estatus");
// Quotes: la lista trae Status(int) + StatusText(string) en la misma fila — mapeo barato.
const quoteMap: Record<string, string> = {};
for (const code of [0, 1, 2, 3, 4, 5]) {
const p = await probeGet(`/api/Quotes?$top=1&$filter=${encodeURIComponent(`Status eq ${code}`)}`);
if (p.ok && p.rows?.length) {
const r = p.rows[0] as Record<string, unknown>;
quoteMap[String(code)] = String(r["StatusText"] ?? "(sin StatusText)");
} else if (!p.ok) {
quoteMap[String(code)] = `error ${p.status}`;
}
}
console.log(` Quotes.Status → ${JSON.stringify(quoteMap)}`);
// Invoices: lista trae Status(int); el label vive en el detalle (Status string + StatusCode int).
const invoiceMap: Record<string, string> = {};
for (const code of [0, 1, 2, 3, 4, 5]) {
const list = await probeGet(`/api/Invoices?$top=1&$filter=${encodeURIComponent(`Status eq ${code}`)}`);
if (!list.ok || !list.rows?.length) continue;
const id = String((list.rows[0] as Record<string, unknown>)["ID"] ?? "");
if (!id) continue;
const det = await probeGet(`/api/Invoices/${id}`);
if (det.ok && det.rows?.length) {
const d = det.rows[0] as Record<string, unknown>;
invoiceMap[String(code)] = `${String(d["Status"] ?? "?")} (StatusCode=${String(d["StatusCode"] ?? "?")})`;
}
}
console.log(` Invoices.Status → ${JSON.stringify(invoiceMap)}`);
report.statusSemantics = {
quotesStatusToText: quoteMap,
invoicesStatusToLabel: invoiceMap,
note: "Labels vienen del propio API (campo StatusText / Status del detalle); son códigos de proceso, no datos personales.",
};
}
async function phasePrefactura(): Promise<void> {
console.log("\n── Ronda 2 · ¿Prefacturas visibles? (UUID null / IsFiscalInvoice false)");
const uuidNull = await probeGet(`/api/Invoices?$top=1&$filter=${encodeURIComponent("UUID eq null")}`);
const notFiscal = await probeGet(`/api/Invoices?$top=1&$filter=${encodeURIComponent("IsFiscalInvoice eq false")}`);
report.prefactura = {
"filter UUID eq null": { status: uuidNull.status, rows: uuidNull.rowCount },
"filter IsFiscalInvoice eq false": { status: notFiscal.status, rows: notFiscal.rowCount },
interpretation:
(uuidNull.rowCount ?? 0) > 0 || (notFiscal.rowCount ?? 0) > 0
? "Hay documentos sin timbrar visibles en /api/Invoices — prefactura distinguible vía UUID/IsFiscalInvoice"
: "Con los filtros probados no aparecieron prefacturas — posible que /api/Invoices solo exponga CFDI timbrados (validar en UI con Arturo)",
};
console.log(` UUID null → ${uuidNull.status}/${uuidNull.rowCount} filas · IsFiscalInvoice false → ${notFiscal.status}/${notFiscal.rowCount} filas`);
}
async function phaseDetailShapes(): Promise<void> {
console.log("\n── Ronda 2 · Detalle por ID de Clients y Quotes");
for (const res of ["Clients", "Quotes"]) {
const list = await probeGet(`/api/${res}?$top=1`);
const id = list.rows?.[0] ? String((list.rows[0] as Record<string, unknown>)["ID"] ?? "") : "";
if (!id) continue;
const det = await probeGet(`/api/${res}/${id}`);
console.log(` [${String(used).padStart(3)}/${BUDGET}] ${res}/{id} → ${det.status} (${det.ok ? analyzeRows(det.rows ?? []).length : 0} campos)`);
if (det.ok && det.rows?.length) {
report.shapes[`${res}(detalle por ID)`] = {
rowsAnalyzed: det.rows.length,
totalCount: null,
fields: analyzeRows(det.rows),
};
}
}
}
async function phasePagination(): Promise<void> {
console.log("\n── Ronda 2 · Paginación");
const plain = await probeGet("/api/Quotes"); // colección chica conocida; mide page size default
const top101 = await probeGet("/api/Quotes?$top=101");
report.pagination = {
"GET sin $top (Quotes)": { rows: plain.rowCount, nextLink: plain.nextLink, count: plain.count, status: plain.status },
"GET $top=101 (Quotes)": { rows: top101.rowCount, nextLink: top101.nextLink, status: top101.status },
note: "Si rows < total esperado y no hay nextLink, la paginación es por $top/$skip manual.",
};
console.log(` sin $top → ${plain.rowCount} filas (nextLink=${plain.nextLink}) · $top=101 → ${top101.rowCount} filas`);
}
async function phaseSeriesHunt(): Promise<void> {
console.log("\n── Ronda 2 · Series de facturación");
const out: Record<string, number> = {};
for (const c of ["InvoiceSeries", "Folios", "DocumentSeries"]) {
const p = await probeGet(`/api/${c}?$top=1`);
out[c] = p.status;
if (p.ok && p.rows?.length) {
report.shapes[c] = { rowsAnalyzed: p.rows.length, totalCount: p.count, fields: analyzeRows(p.rows) };
}
}
report.seriesHunt = out;
console.log(` ${JSON.stringify(out)}`);
}
/** Carga el reporte previo y purga enumValues de campos tipo monto (fuga corregida). */
function loadPreviousReport(): boolean {
try {
const prev = JSON.parse(readFileSync(join(OUT_DIR, "report.json"), "utf8")) as typeof report;
Object.assign(report, prev);
for (const shape of Object.values(report.shapes)) {
for (const f of shape.fields) {
if (f.enumValues && ENUM_EXCLUDE.test(f.name)) delete f.enumValues;
}
}
return true;
} catch {
return false;
}
}
// ─── Fases de ronda 3 (cabos sueltos) ───────────────────────────────────────
async function phaseCaps(): Promise<void> {
console.log("\n── Ronda 3 · Límites de $top y tamaño de colecciones");
const top100 = await probeGet("/api/Quotes?$top=100");
const skip100 = await probeGet("/api/Invoices?$top=1&$skip=100");
const skip1000 = await probeGet("/api/Invoices?$top=1&$skip=1000");
report.pagination = {
...(report.pagination as Record<string, unknown>),
"GET $top=100 (Quotes)": { status: top100.status, rows: top100.rowCount },
topCapVerdict: top100.ok ? "$top acepta hasta 100; 101 → 500" : `$top=100 también falla (${top100.status})`,
invoicesSizeBracket: {
"skip=100 devuelve fila": (skip100.rowCount ?? 0) > 0,
"skip=1000 devuelve fila": (skip1000.rowCount ?? 0) > 0,
note: "brackets aproximados del total de facturas históricas, sin descargar la colección",
},
};
console.log(` $top=100 → ${top100.status} · skip100 → ${skip100.rowCount} · skip1000 → ${skip1000.rowCount}`);
}
async function phaseCfdiLiterals(): Promise<void> {
console.log("\n── Ronda 3 · Literales CFDI (PPD/PUE, uso CFDI) — sanitizador corregido");
const list = await probeGet("/api/Invoices?$top=2");
const rows = list.rows ?? [];
const detailRows: unknown[] = [];
for (const r of rows) {
const id = String((r as Record<string, unknown>)["ID"] ?? "");
if (!id) continue;
const det = await probeGet(`/api/Invoices/${id}`);
if (det.ok && det.rows) detailRows.push(...det.rows);
}
if (detailRows.length) {
report.shapes["Invoices(detalle por ID)"] = {
rowsAnalyzed: detailRows.length,
totalCount: null,
fields: analyzeRows(detailRows),
};
const f = report.shapes["Invoices(detalle por ID)"].fields.find((x) => x.name === "CFDIPaymentMethod");
console.log(` CFDIPaymentMethod literales → ${JSON.stringify(f?.enumValues ?? [])}`);
}
}
async function phasePaymentsHuntEs(): Promise<void> {
console.log("\n── Ronda 3 · Pagos: nombres en español y variantes finales");
const extra: Record<string, number> = {};
for (const c of ["Cobros", "Pagos", "InvoicePayments", "PaymentsReceived"]) {
const p = await probeGet(`/api/${c}?$top=1`);
extra[c] = p.status;
if (p.ok && p.rows?.length) {
report.shapes[c] = { rowsAnalyzed: p.rows.length, totalCount: p.count, fields: analyzeRows(p.rows) };
}
}
report.paymentsHunt = { ...(report.paymentsHunt as Record<string, unknown>), spanishAndFinal: extra };
console.log(` ${JSON.stringify(extra)}`);
}
async function phaseDocEndpoints(): Promise<void> {
console.log("\n── Ronda 3 · ¿Descarga de PDF/XML del CFDI? (solo estatus; el contenido se descarta)");
const list = await probeGet("/api/Invoices?$top=1");
const id = list.rows?.[0] ? String((list.rows[0] as Record<string, unknown>)["ID"] ?? "") : "";
const out: Record<string, unknown> = {};
if (id) {
for (const sub of ["pdf", "xml", "PDF", "cfdi"]) {
const p = await probeGet(`/api/Invoices/${id}/${sub}`);
out[`Invoices/{id}/${sub}`] = { status: p.status, contentType: p.contentType };
if (p.ok) break; // con uno confirmado basta
}
}
(report as Record<string, unknown>)["documentDownload"] = out;
console.log(` ${JSON.stringify(out)}`);
}
// ─── Ronda 4: verificación aritmética del saldo (en memoria, sin persistir montos) ───
async function phaseBalanceArithmetic(): Promise<void> {
console.log("\n── Ronda 4 · Verificación del saldo: ¿Payments acumula lo pagado? (aritmética en memoria)");
const paid = await probeGet(`/api/Invoices?$top=5&$filter=${encodeURIComponent("Status eq 1")}`);
const active = await probeGet(`/api/Invoices?$top=5&$filter=${encodeURIComponent("Status eq 0")}`);
const near = (a: number, b: number) => Math.abs(a - b) < 0.01;
const summarize = (rows: unknown[]) =>
rows.map((r) => {
const o = r as Record<string, unknown>;
const total = Number(o["Total"] ?? NaN);
const pay = Number(o["Payments"] ?? NaN);
const cn = Number(o["CreditNotes"] ?? 0);
return { settled: near(pay + cn, total), residualPositive: total - pay - cn > 0.01 };
});
const paidChecks = summarize(paid.rows ?? []);
const activeChecks = summarize(active.rows ?? []);
report.balanceQuestion = {
...(report.balanceQuestion as Record<string, unknown>),
arithmetic: {
paidSample: { n: paidChecks.length, allSettled: paidChecks.every((c) => c.settled) },
activeSample: { n: activeChecks.length, allWithResidual: activeChecks.every((c) => c.residualPositive) },
formula: "SaldoPorFactura = Total Payments CreditNotes (campos de la MISMA fila de /api/Invoices)",
},
};
console.log(
` pagadas: ${paidChecks.length} muestras, todas saldadas=${paidChecks.every((c) => c.settled)} · activas: ${activeChecks.length} muestras, todas con residual=${activeChecks.every((c) => c.residualPositive)}`,
);
// XML del CFDI (quedó sin probar en ronda 3 por el break temprano)
const id = paid.rows?.[0] ? String((paid.rows[0] as Record<string, unknown>)["ID"] ?? "") : "";
if (id) {
const xml = await probeGet(`/api/Invoices/${id}/xml`);
const doc = ((report as Record<string, unknown>)["documentDownload"] ?? {}) as Record<string, unknown>;
doc["Invoices/{id}/xml"] = { status: xml.status, contentType: xml.contentType };
(report as Record<string, unknown>)["documentDownload"] = doc;
console.log(` xml → ${xml.status} (${xml.contentType})`);
}
}
// ─── Main ───────────────────────────────────────────────────────────────────
async function main() {
const round2 = process.argv.includes("--round2");
const round3 = process.argv.includes("--round3");
const round4 = process.argv.includes("--round4");
console.log(`BIND API · validación técnica SOLO LECTURA${round2 ? " · RONDA 2" : round3 ? " · RONDA 3" : round4 ? " · RONDA 4" : ""}`);
console.log(`Base: ${BASE} · presupuesto: ${BUDGET} peticiones`);
if (!TOKEN) {
console.error("❌ No hay BIND_API_TOKEN en bind-api-sandbox/.env — abortando.");
process.exitCode = 1;
return;
}
console.log("Token cargado desde .env (no se imprime).");
if (/localhost|127\.0\.0\.1/.test(BASE)) {
console.log("⚠️ Base URL apunta al mock local; esto NO valida producción.");
}
if (round2 || round3 || round4) {
if (!loadPreviousReport()) {
console.error("❌ --round2/--round3/--round4 requieren validation-output/report.json previo.");
process.exitCode = 1;
return;
}
used = report.meta.requestsUsed; // presupuesto acumulado entre rondas
if (round2) {
await phasePaymentsHunt();
await phaseStatusSemantics();
await phasePrefactura();
await phaseDetailShapes();
await phasePagination();
await phaseSeriesHunt();
} else if (round3) {
await phaseCaps();
await phaseCfdiLiterals();
await phasePaymentsHuntEs();
await phaseDocEndpoints();
} else {
await phaseBalanceArithmetic();
}
phaseBalanceVerdict();
finish();
return;
}
const auth = await phaseAuth();
if (auth !== "ok") {
finish();
return;
}
const inventory = await phaseInventory();
const rowsByResource = await phaseShapes(inventory);
await phaseOData(rowsByResource);
await phaseById(rowsByResource);
phaseBalanceVerdict();
phaseMultiCompany(inventory);
finish();
}
function finish() {
report.meta.requestsUsed = used;
mkdirSync(OUT_DIR, { recursive: true });
const serialized = scrub(JSON.stringify(report, null, 2));
writeFileSync(join(OUT_DIR, "report.json"), serialized, "utf8");
console.log(`\n✔ Reporte sanitizado escrito en validation-output/report.json`);
console.log(`✔ Peticiones usadas: ${used}/${BUDGET}`);
}
main().catch((err) => {
console.error("Error fatal:", scrub(String(err?.message ?? err)));
finish();
process.exitCode = 1;
});
+70 -10
View File
@@ -2,16 +2,67 @@
Acciones vivas del proyecto. Formato: `[ ]` abierta · `[x]` cerrada (no se borran, dejan rastro). Cada una con responsable y, si aplica, fecha. Ver contexto en [REGISTRO.md](REGISTRO.md). Acciones vivas del proyecto. Formato: `[ ]` abierta · `[x]` cerrada (no se borran, dejan rastro). Cada una con responsable y, si aplica, fecha. Ver contexto en [REGISTRO.md](REGISTRO.md).
_Última actualización: 2026-06-30 (plan de actividades entregado; kickoff con Noé el 1-jul, 7am)._ _Última actualización: 2026-08-10 (Balam definió el flujo Jira→BIND en el correo del 7-ago: disparador = `En proceso de facturación`, todos los request types, monto/conceptos como campos de Jira, prueba acompañada sin `FACTEST`. Verificado por API el 10-ago: el campo `Monto sin IVA` ya existe, pero **los conceptos no tienen campo** y **10 de 69 tickets no traen datos estructurados**. Ver [REGISTRO #59](REGISTRO.md))._
## 🔥 Flujo Jira→BIND — abierto tras la definición del 7-ago
- [x] ~~🔥 **Johann — responder el correo del hilo de Jira**~~**Enviado el 10-ago.** Pide ticket de ejemplo, propone mié 12 / jue 13 a las 7:00 am, fija el alcance en la cotización y recuerda Azure. Texto en [REGISTRO #59](REGISTRO.md).
- [ ] 🔥 **Balam — levantar el TICKET DE EJEMPLO capturado "como debería ser"** (pedido para hoy/mañana en el correo del 10-ago). Tarea **dejada sin asignar a propósito** para que Balam la ruteé; en la práctica es de Arturo. Es el mecanismo elegido para resolver por evidencia, y no por correo, los huecos de abajo. ⚠️ **Riesgo: el precedente de latencia es de 8 días** (pregunta del 30-jul contestada el 7-ago). Si no hay respuesta para mañana al mediodía, empujar por WhatsApp con Erika, que es el canal que responde el mismo día.
- [ ] 🔥 **Balam/Noé — confirmar la sesión** (mié 12 o jue 13, 7:00 am). Sin fecha confirmada no hay prueba acompañada.
- [ ] 🔴 **Conceptos/partidas — se resuelve con el ticket de ejemplo.** El acuerdo del 4-ago resolvió el monto (`customfield_11556`) pero **no existe campo de conceptos en todo el sitio de Jira**. Si en el molde el desglose no cabe en ningún campo, hay que agregar uno; si no, la cotización va de una sola línea. **Sigue siendo el único bloqueo real para cerrar B7.**
- [ ] 🔴 **ACUNTIA — se resuelve con el segundo ticket de ejemplo.** `FAC-100` trae **un solo** `Monto sin IVA` (7,594.00 USD) para el ticket que históricamente representa 4048 facturas. ¿Un ticket → una cotización? Ver [REGISTRO #55](REGISTRO.md) punto 6.
- [ ] ⚠️ **Tickets de `Automation for Jira` — convertido en SUPUESTO, ya no bloquea.** 10 de 69 no tienen request type ni un solo campo (incluido `FAC-91`, vivo en validación nacional). En el correo del 10-ago se asienta que **siguen tramitándose a mano** y que la automatización cubre solo los que entran por el portal. Si Balam objeta, la regla de Automation tendría que propagar los campos (trabajo de ellos). El molde capturado a mano no puede resolver esto.
- [ ] ⚠️ **Johann — decidir el destino de la cotización de la prueba en BIND.** El ejercicio escribe una **cotización real en BIND producción**. Anunciado en el correo, con dos salidas ofrecidas: cancelarla al terminar o apuntarla a un cliente de prueba. Definir cuál antes de la sesión.
- [ ] 🔴 **¿El comercial ya genera la cotización en BIND, o la genera la plataforma?** Contradicción abierta: el 6-jul Ara dijo que **el comercial la genera y la plataforma la convierte** a prefactura ([REGISTRO #27](REGISTRO.md)); el 4-ago Arturo dijo que **la plataforma la genera**; y el formulario de Jira sigue exigiendo **adjuntar la cotización**. Si ambas cosas ocurren, **quedan dos cotizaciones por ticket**. Se resuelve viendo qué adjunto pone Arturo en el ticket de ejemplo: cotización de BIND ya existente (→ convertir) o documento comercial (→ crear).
- [x] ~~**Alcance del ejercicio en vivo: ¿cotización o prefactura?**~~**Decidido (10-ago): termina en la COTIZACIÓN.** Es lo que contestó Arturo el 4-ago; la aprobación de Araceli va entre `En proceso de facturación` y `Facturado`, así que la prefactura pertenece después; Arturo pidió gradualismo explícito; y la cotización se cancela sin efecto fiscal mientras la prefactura es un registro en `Invoices` con `UUID = null`. La prefactura queda para la segunda sesión. Candados acordados: **cotización → prefactura → aprobación humana → timbrado** ([REGISTRO #55](REGISTRO.md)).
- [ ] ⚠️ **La transición automática depende de Azure.** En la prueba del miércoles el disparo es **manual** (pipeline `Draft→DryRun→Confirmed` de ADR-001 con flags apagados). Para que corra automática hace falta el ambiente publicado y corriendo continuo — otro argumento para insistir en el acceso a Azure.
- [ ] 🔥 **Johann — preparar el script contra el ticket de ejemplo** en cuanto Arturo lo levante, para llegar a la sesión con el flujo funcionando. Compartirlo con Balam **antes** de la sesión (protocolo del Bloque 6 de `../planeacion/Investigacion-API-Jira.md`).
- [ ] **Balam/Noé — fecha para la prueba acompañada de escritura.** Aceptado el formato el 7-ago, sin día propuesto por ellos. En el correo del 10-ago se proponen **mié 12 o jue 13-ago, 7:00 am o después de 6:00 pm** (30 min), sobre un ticket que cree Arturo, con el script compartido de antemano. **No habrá `FACTEST`.**
- [ ] **Balam — ¿nacional vs extranjero cambia la cotización** o solo el paquete de salida (PDF+XML vs PDF)? Hay dos estatus de validación y una aprobación por rama.
- [ ] **Balam/Pedro — migrar a cuenta de servicio** en vez de la cuenta personal de Pedro. Planteado el 29-jul, sin respuesta: hoy todo lo que escriba la plataforma queda firmado como Pedro y una rotación suya mata la integración.
- [ ] **Johann — levantar el sandbox Jira Cloud propio** (plan Free, proyecto JSM que replique el workflow de FAC). Con `FACTEST` descartado, es el único lugar donde se puede equivocar sin costo.
- [ ] ⚠️ **Johann — implementar la detección por changelog, no por estatus actual.** `FAC-100` estuvo **2m44s** en el estatus disparador; un poller de 15 min que consulte el estado actual se pierde la mayoría de los disparos. Refuerza el caso de pedir un webhook / regla de Automation a Pedro.
- [ ] **Johann — mover el token de Jira a user-secrets/Key Vault** y borrarlo de disco (ya está en `.gitignore:9`). Mismo pendiente que arrastra `bind_token_api.txt`.
## 🔴 Johann (proveedor) — inmediato ## 🔴 Johann (proveedor) — inmediato
- [ ] **Asistir al kickoff con Noé (mié 1-jul, 7:00 am)** — llevar agenda, lista de accesos a pedir y preguntas de Discovery. Ver [REGISTRO #21](REGISTRO.md). - [x] ~~**Asistir al kickoff con Noé (mié 1-jul, 7:00 am)**~~**Hecho (1-jul).** Ver [REGISTRO #22](REGISTRO.md).
- [x] ~~Preparar el Excel de actividades~~**Entregado:** Etapa 0 y 1 (29-jun) y **completo, 4 etapas (03)** con fechas tentativas (30-jun). En `../planeacion/Plan-actividades.xlsx`. - [x] ~~📅 **Asistir a la sesión "Proceso actual de facturación y cobranza" (lun 6-jul, 7:00 am)**~~**Hecha (6-jul).** Proceso mapeado end-to-end; lista blanca eliminada; cotización BIND obligatoria. Ver [REGISTRO #27](REGISTRO.md).
- [x] ~~🎨 **Preparar y entregar el prototipo de la Etapa 0**~~**Entregado por correo (10-jul)** a Erika + Noé, CC Pedro, con PDF y versión navegable. Refleja facturación, envío, cobranza y reglas del Discovery. Ver [REGISTRO #40](REGISTRO.md).
- [x] ~~📧 **Enviar por correo el prototipo (imágenes) + comentarios**~~**Hecho (10-jul).** Balam respondió que lo revisaría internamente.
- [x] ~~📊 **Responder a Erika el % de avance de Fase 0**~~**Atendido mediante el Excel de avance ajustado y entrega del prototipo.** La validación final sigue abierta.
- [x] ~~📅 **Preparar y asistir a la sesión de reglas/dudas de Etapa 1 (mié 22-jul)**~~**Hecha (22-jul, 7 am):** alta de cliente/proveedor mapeada (Arturo en pantalla), fee = lo registra el despacho (plataforma solo detecta), Jira confirmado en el proceso (estatus final "resuelto"; validación PDF+XML nacional / PDF internacional). No se tocaron particularidades de envío ni PUE/PPD. Ver [REGISTRO #54](REGISTRO.md) y minuta en `../planeacion/Sesion-Etapa1-2026-07-22.md`.
- [ ] 📅 **Preparar y asistir a la validación del prototipo (jue 23-jul, 7:00 pm).** Llevar decisiones que requieren visto bueno y separar MVP de Anexo B. **Aprovechar para meter la pregunta PUE/PPD que no se alcanzó el 22-jul.** Ver [REGISTRO #42](REGISTRO.md).
- [x] ~~📊 **Compartir con Erika el corte de avance de la Etapa 1 solicitado el 16-jul**~~**Hecho (16-jul, 8:40 pm):** Excel `Plan-actividades-avance-2026-07-16.xlsx` enviado por WhatsApp; Erika acusó recibo ("Ntp, gracias"). Ver [REGISTRO #46](REGISTRO.md).
- [ ] 📄 **Revisar los procedimientos de carga de facturas por cliente enviados por correo el 16-jul.** Conservar correo/adjuntos como evidencia y contrastar destinatarios, adjuntos, asunto, cuerpo y nomenclatura contra el Discovery y el prototipo. Ver [REGISTRO #46](REGISTRO.md).
- [x] ~~🔐 **Validar permiso de escritura en el repositorio privado de Balam**~~**Comprobado (16-jul):** push exitoso del scaffold inicial (backend .NET 10 + Angular 21, commits `220942a..1f7f098`) a `pedro-balam-itsm/BALAM`. Ver [REGISTRO #46](REGISTRO.md).
- [ ] ⏱️ **Validar el corte reconstruido de 30 h** en `../planeacion/Seguimiento-horas.csv`: 22 h de Etapa 0 + 8 h de Etapa 1. Solo 3.08 h corresponden a sesiones con duración comprobable; las otras 26.92 h están marcadas como reconstruidas. Ajustarlas si la memoria/evidencia indica otra distribución y después conciliar con Jira. Ver [REGISTRO #45](REGISTRO.md).
- [ ] 📝 **Cerrar el documento de hallazgos + ADRs** (`../planeacion/Hallazgos-y-decisiones-Etapa0.md`) después de las sesiones del 2223 jul.
- [ ] 🔐 **Decidir/aplicar el rol local `balam_app` para que RLS aplique en desarrollo:** la política RLS de B6 está aplicada, pero el usuario `balam` del contenedor es superuser (BYPASSRLS) y la ignora. Falta: `CREATE ROLE balam_app LOGIN NOSUPERUSER NOBYPASSRLS` + `REASSIGN OWNED` + apuntar la cadena de conexión de desarrollo (appsettings.Development y DesignTimeDbContextFactory) a ese rol + repetir la verificación psql. En Azure no existe este hueco (el usuario de app no es superuser). Ver [REGISTRO #53](REGISTRO.md).
- [ ] ⚠️ **Preguntar a Arturo: ¿por qué TODO el histórico se factura PUE?** 1,374/1,374 facturas con método de pago = PUE, cero PPD, aunque cobran a crédito 3090 días. Toca la regla "PPD default" de la capa de escritura (B7) y el requerimiento del SAT que ellos mismos sufrieron. **No se alcanzó a preguntar en la sesión del 22-jul** — reintentar el 23-jul (validación del prototipo) o en la sesión de API Jira con Pedro. Ver [REGISTRO #52](REGISTRO.md), [#54](REGISTRO.md).
- [x] ~~📅 **Proponer a Erika usar la sesión del martes 7-jul para COBRANZA**~~**Propuesto (6-jul, 3:01 pm) y CONFIRMADO (6-jul, 6:36 pm):** convocatoria de Teams enviada para el martes 7-jul, 7:008:00 am, con Araceli y Arturo (CC Noé). Ver [REGISTRO #34](REGISTRO.md).
- [x] ~~📅 **Asistir a la sesión de cobranza (mar 7-jul, 7:00 am)**~~**Hecha (7-jul).** Sin grabación. Ver [REGISTRO #35](REGISTRO.md).
- [x] ~~📝 **Documentar el proceso de cobranza** de la sesión del 7-jul (sin grabación)~~**Hecho (7-jul):** reconstruido de memoria el mismo día. Notas en `../fuentes/2026-07-07 - Notas - Proceso actual de cobranza (sin grabacion).md`; entrada [REGISTRO #35](REGISTRO.md).
- [ ] 📊 **Exceles de cobranza (condicional):** si Balam valida que el prototipo representa bien su operación, ya no se requieren. Si pide ajustes, solicitar a Arturo estructura con datos ficticios de abiertas/canceladas/días vencidos, pago↔folio y estado de cuenta. **No confundir con el Excel de particularidades de envío**, que sigue pendiente. Ver [REGISTRO #44](REGISTRO.md).
- [ ] 🔑 **Dar seguimiento a si Pedro crea el usuario de solo lectura de BIND** que pidió Noé (mientras tanto Erika opera con el usuario de Arturo, sin bloqueo) — sigue sin resolverse una semana después (7-jul). Ver [REGISTRO #37](REGISTRO.md).
- [x] ~~🔧 **Decidir si probar endpoints de escritura (POST/PUT) de BIND**~~**Decidido (7-jul): NO todavía.** Contradice la instrucción de Noé de mantener solo-lectura mientras Pedro confirma el alcance del token; sin sandbox, el riesgo fiscal es real. Alternativa segura: catalogar operaciones de escritura desde el **portal de desarrolladores de BIND** (documentación), no probarlas en vivo. Ver [REGISTRO #36](REGISTRO.md).
- [x] ~~📧 **Responder el correo de Pedro**~~**Enviado (6-jul, ~3:28 pm):** acuse de recibo + usuario de Arturo documentado + arranque de trabajo con la API, sin comprometer entregas adicionales. Ver [REGISTRO #29](REGISTRO.md).
- [ ] 📧⚠️ **Responder el correo de Noé (importancia alta, 4:33 pm)** describiendo las **salvaguardas** ya operando: solo-lectura bloqueado en código, consultas acotadas, token en gestor de secretos fuera del repo, sin datos reales en documentos, escritura solo con autorización + candados de la propuesta. Borrador listo. **Confirmación informal ya dada por WhatsApp (6-jul, 5:01 pm) — falta la respuesta formal por correo para dejar constancia en el canal correcto.** Ver [REGISTRO #31](REGISTRO.md), [#33](REGISTRO.md).
- [ ] ⚠️ **No atar nada al token actual:** Pedro está revisando permisos y puede **reemplazarlo** por uno de un usuario nuevo de solo lectura — mantener el token como variable de entorno intercambiable (ya es así en el sandbox). Ver [REGISTRO #31](REGISTRO.md).
- [x] ~~🔑 **Validar la API de BIND con el token real**~~ → ✅ **Hecha (6-jul, adelantada un día):** 117 peticiones GET-only, Plan A del saldo CONFIRMADO, flujo MVP 100% sostenible en lectura, PDF por API. Hallazgo duro: **sin recurso de pagos/REP**. Documento: [`../bind-api-sandbox/VALIDACION-API.md`](../bind-api-sandbox/VALIDACION-API.md). Ver [REGISTRO #32](REGISTRO.md).
- [ ] 📨 **Escalar a Pedro las preguntas técnicas de la API** (juntas, esta semana): (1) ¿existe endpoint de **pagos individuales / complementos de pago (REP)** no documentado? — es el hueco más relevante para el flujo PPD, _y ganó caso de negocio el 7-jul: el despacho registra los pagos en BIND uno por uno a mano_; (2) **tabla de mapeo `CFDIUse`** interno → clave SAT; (3) shape del endpoint `/{id}/xml`; (4) ¿webhooks/eventos o solo polling?; (5) ⚠️ **qué token alimenta el Power BI** — el 7-jul Arturo mostró su Power BI conectado con **su** token, pero el kickoff acordó Ara=Power BI / Arturo=desarrollo; BIND emite 1 token por usuario, así que si ambos usos comparten el de Arturo, reemplazarlo por el usuario solo-lectura que planteó Noé rompería uno de los dos. Ver [REGISTRO #32](REGISTRO.md) §10, [#35](REGISTRO.md).
- [ ] 🔐 **Higiene del token:** moverlo a un gestor de secretos y **borrar `bind_token_api.txt`** de la raíz del repo y del correo/descargas (está gitignoreado, pero sigue en disco).
- [ ] ⚠️ **Aclarar expectativa de recordatorios a clientes:** lo que Ara/Arturo describieron el 6-jul son recordatorios automáticos **a clientes**, que están **diferidos al Anexo B** (el MVP trae alertas *internas*). Aclararlo pronto o anticipar que pidan ese módulo al cierre del MVP. Igual con la idea de **agentes observando Jira** (Nivel 3, fase posterior) y el deseo **multi-empresa** (Regiotour, Elmstone). **Reapareció el 7-jul:** quieren correos automáticos al cliente pasados 15 días de vencimiento ("ser proactivos"). Ver [REGISTRO #27](REGISTRO.md), [#35](REGISTRO.md).
- [x] ~~**Ajustar la propuesta** (30 h explícitas, sin "Etapa 0", términos comerciales en una sección)~~**Hecho (1-jul):** propuesta **v1.2** — se agregó el concepto **"Facturación inicial: 30 h / $18,000 + IVA"** (cubre Etapa 0 + inicio de Etapa 1; Etapa 0 se mantiene en 1822 h) y se consolidó **§3.3 Condiciones comerciales**. PDF generado y enviado el 2-jul.
- [x] ~~📧 **Enviar el correo** (Noé, CC Pedro, Ara, Erika) con la propuesta v1.2 ajustada, vinculando la **facturación inicial de 30 h** al acuerdo~~**Hecho (2-jul, 5:39 PM):** enviado con `Propuesta-Balam.pdf` adjunto, sin esperar el correo de Erika+Paola. Ver [REGISTRO #26](REGISTRO.md).
- [ ] 💸 **NO facturar todavía.** Erika confirmó el 13-jul que recibió la propuesta v1.2; la validación para emitir sigue pendiente porque Noé y la CEO están fuera del país. Mantener la factura lista y emitir en cuanto llegue el visto bueno, con pago a 30 días. Ver [REGISTRO #41](REGISTRO.md).
- [ ] **Configurar Jira y aprender el flujo con Pedro** — reportar horas ahí (incluye material informativo); Erika hace el corte los lunes. Mientras tanto usar `../planeacion/Seguimiento-horas.csv`.
- [x] ~~Usar los **tokens de marca** en el prototipo~~**Hecho:** prototipo y capturas usan Amarillo `#F7BD0C`, Café `#331F0E` y Poppins.
- [x] ~~Preparar el Excel de actividades~~**Entregado y consolidado:** la única versión operativa se conserva en `../planeacion/Plan-actividades-avance-2026-07-10-ajustado.xlsx`; contiene el corte reconstruido de 30 h al 15-jul.
- [x] ~~Proponer sesiones de Discovery~~**Hecho (29-jun):** propuestas y aceptadas; **Erika coordina las agendas** (intermediaria de sesiones). - [x] ~~Proponer sesiones de Discovery~~**Hecho (29-jun):** propuestas y aceptadas; **Erika coordina las agendas** (intermediaria de sesiones).
- [ ] Cambiar régimen fiscal (en proceso) para poder facturar (CFDI semanal los viernes, pago a 30 días). - [ ] Cambiar régimen fiscal (en proceso) para poder facturar (CFDI semanal los viernes, pago a 30 días).
- [ ] Confirmar **qué permisos exactos de Azure** necesita (crear App Service + PostgreSQL; no Global Admin). - [x] ~~Confirmar **qué permisos exactos de Azure** necesita~~**Definido:** acceso `Contributor` acotado a un grupo de recursos de Balam; no se requiere Global Admin ni una cuenta nueva. Solicitar durante la semana del 21-jul.
- [ ] **Arrancar el Discovery** una vez Balam entregue los accesos (el contrato ya está firmado). - [x] ~~**Arrancar el Discovery** una vez Balam entregue los accesos~~**Hecho (67 jul):** facturación, envío y cobranza mapeados.
- [ ] (Opcional) Pedir a Balam **copia limpia del contrato**: la cláusula de Firma Electrónica de la última página quedó duplicada y aún dice "EL PATRÓN" (residuo de plantilla, bajo riesgo). Ver [REGISTRO #19](REGISTRO.md). - [ ] (Opcional) Pedir a Balam **copia limpia del contrato**: la cláusula de Firma Electrónica de la última página quedó duplicada y aún dice "EL PATRÓN" (residuo de plantilla, bajo riesgo). Ver [REGISTRO #19](REGISTRO.md).
- [x] ~~Revisar y firmar el contrato de servicios~~**Hecho (26-jun):** revisado, negociados 2 ajustes (pago de horas al terminar + aceptación a 10 días) y **FIRMADO**. Ver [REGISTRO #18](REGISTRO.md), [#19](REGISTRO.md). - [x] ~~Revisar y firmar el contrato de servicios~~**Hecho (26-jun):** revisado, negociados 2 ajustes (pago de horas al terminar + aceptación a 10 días) y **FIRMADO**. Ver [REGISTRO #18](REGISTRO.md), [#19](REGISTRO.md).
- [x] ~~Responder el correo de Noe (8-jun)~~**Hecho (10-jun):** aceptados los 4 ajustes y respondidas las 3 preguntas técnicas. Ver [REGISTRO #16](REGISTRO.md). - [x] ~~Responder el correo de Noe (8-jun)~~**Hecho (10-jun):** aceptados los 4 ajustes y respondidas las 3 preguntas técnicas. Ver [REGISTRO #16](REGISTRO.md).
@@ -26,14 +77,23 @@ _Última actualización: 2026-06-30 (plan de actividades entregado; kickoff con
## 🟡 Balam ## 🟡 Balam
- [x] ~~**Balam:** enviar el documento/contrato de firma~~**Hecho (25-jun):** contrato enviado vía Paola (RH); ajustado y **firmado el 26-jun**. Ver [REGISTRO #18](REGISTRO.md), [#19](REGISTRO.md). - [x] ~~**Balam:** enviar el documento/contrato de firma~~**Hecho (25-jun):** contrato enviado vía Paola (RH); ajustado y **firmado el 26-jun**. Ver [REGISTRO #18](REGISTRO.md), [#19](REGISTRO.md).
- [ ] 🔑 **Balam: entregar los ACCESOS para arrancar**API BIND (cuenta ARA / llave de Arturo), Azure (Guajardo/Erika), manual de marca (Pedro), reglas de negocio + bancos (Arturo). **Es el bloqueador para iniciar el Discovery.** - [ ] 🔑 **Balam: completar accesos de Etapa 1**token BIND ✅; manual de marca ✅; invitación al repo GitHub recibida y acceso confirmado informalmente (falta validar escritura); Azure programado para semana del 21-jul. Ya no bloquea el desarrollo local, pero Azure sí condiciona despliegue/CI-CD.
- [x] ~~Erika (PM): pedir el plan de actividades~~**Recibido (30-jun).** Erika es la **intermediaria de todas las sesiones**, agendó el **kickoff (1-jul, 7am)** y monta el **tablero Kanban en Jira**. Ver [REGISTRO #21](REGISTRO.md). - [x] ~~Erika (PM): pedir el plan de actividades~~**Recibido (30-jun).** Erika es la **intermediaria de todas las sesiones**, agendó el **kickoff (1-jul, 7am)** y monta el **tablero Kanban en Jira**. Ver [REGISTRO #21](REGISTRO.md).
- [x] ~~**Noe:** formalizar por correo~~**Hecho:** aclaraciones (8-jun, [#15](REGISTRO.md)) y **luz verde + redacción del documento de firma** (16-jun, [#17](REGISTRO.md)). - [x] ~~**Noe:** formalizar por correo~~**Hecho:** aclaraciones (8-jun, [#15](REGISTRO.md)) y **luz verde + redacción del documento de firma** (16-jun, [#17](REGISTRO.md)).
- [ ] **Pedro + Erika:** armar el **tablero de seguimiento en Jira** y revisarlo juntos (instruido formalmente por Noe el 16-jun). - [ ] **Pedro + Erika:** armar el **tablero de seguimiento en Jira** y revisarlo juntos (instruido formalmente por Noe el 16-jun).
- [ ] **Pedro:** enviar **manual de marca** (paleta, tipografía, logos). - [x] ~~**Pedro:** enviar **manual de marca**~~**Hecho (1-jul):** enviado por correo. Tokens en [`../marca/Marca-Balam.md`](../marca/Marca-Balam.md). Ver [REGISTRO #23](REGISTRO.md).
- [ ] **Pedro:** revisar API BIND — ¿cuántas llaves por usuario? Generar la de **desarrollo desde la cuenta maestra (ARA)** con permisos de Arturo; documentar cuál es para qué (no confundir con la del Power BI). - [x] ~~**Erika:** entregar el **token de BIND**~~ → ✅ **ENTREGADO por correo (6-jul, 12:40 pm)**, mismo día en que se solicitó. Ver [REGISTRO #28](REGISTRO.md).
- [ ] **Erika / Guajardo:** gestionar la **cuenta/permiso de Azure**. - [x] ~~**Balam:** confirmar **a qué usuario pertenece el token**~~ → ✅ **Confirmado (6-jul, 12:38 pm):** Pedro lo entregó por correo (`bind_token_api.txt`) indicando que fue generado con el **usuario de Arturo Rosas** — conforme al kickoff (Arturo=dev, Ara=Power BI). Ver [REGISTRO #29](REGISTRO.md).
- [ ] **Arturo:** definir **reglas de negocio** + dar acceso/contexto de **bancos** (para conciliación). - [ ] **Pedro/Balam:** confirmar permisos de **escritura** para `Johann-28` en el repositorio GitHub privado. Pedro envió la invitación el 15-jul y Johann confirmó acceso el 16-jul; falta una prueba efectiva de escritura. Ver [REGISTRO #43](REGISTRO.md), [#46](REGISTRO.md).
- [ ] **Pedro:** enseñar a Johann el **flujo de Jira** (reporte de horas como los demás consultores).
- [ ] **Pedro + Noé:** **configurar Azure** y permisos (Noé otorga donde Pedro tiene limitantes).
- [x] ~~**Erika:** **coordinar la sesión de Discovery con Arturo + Araceli**~~**Hecho:** agendada (1-jul) y **realizada (6-jul, 7am)**. Ver [REGISTRO #24](REGISTRO.md), [#27](REGISTRO.md).
- [ ] 📊 **Ara + Arturo:** enviar el **Excel de particularidades de envío por cliente** (destinatarios + adjuntos + nomenclatura). Erika confirmó el 13-jul que continúa en preparación y que esperan entregarlo durante la semana. Ver [REGISTRO #41](REGISTRO.md).
- [ ] **Arturo:** definir el proceso para cuando el **cliente NO esté dado de alta en BIND** — el ASIS del alta ya quedó mapeado en la sesión del 22-jul ([REGISTRO #54](REGISTRO.md)); **sigue abierta la decisión de MVP: ¿la plataforma solo detecta que falta el cliente o también lo crea?** (cruza con la estimación Jira→BIND de ~10 h). Ver [REGISTRO #27](REGISTRO.md), [#51](REGISTRO.md).
- [ ] 📤 **Arturo/Pedro:** enviar a Johann el **diagrama del flujo Jira de facturación** en tamaño legible (comprometido en la sesión del 22-jul; el screenshot era ilegible). Ver [REGISTRO #54](REGISTRO.md).
- [ ] 📅 **Erika:** agendar la **sesión con Pedro (+Arturo)** para explorar la **API de Jira** (conexión, campos, webhook), la **facturación recurrente** (~30 facturas/mes) y qué facturas son automáticas vs manuales — acordada en la sesión del 22-jul. Ver [REGISTRO #54](REGISTRO.md).
- [ ] **Erika + Paola / Noé:** confirmar la propuesta v1.2 para emitir las 30 h. Erika confirmó recepción; validación pendiente por viaje de Noé y CEO. Ver [REGISTRO #41](REGISTRO.md).
- [ ] **Arturo:** dar acceso/contexto de **bancos** (para conciliación). _Las reglas de negocio de facturación ya quedaron mapeadas en la sesión del 6-jul ([REGISTRO #27](REGISTRO.md)); bancos sigue pendiente._
## ⚙️ Acordado (referencia, ya cerrado) ## ⚙️ Acordado (referencia, ya cerrado)
+3
View File
@@ -8,6 +8,8 @@ Esta carpeta es el **registro vivo** del proyecto Balam. Cada vez que pase algo
|---|---| |---|---|
| [REGISTRO.md](REGISTRO.md) | **Log cronológico** de toda comunicación (correos, llamadas, mensajes). Entradas numeradas, más antigua arriba. | | [REGISTRO.md](REGISTRO.md) | **Log cronológico** de toda comunicación (correos, llamadas, mensajes). Entradas numeradas, más antigua arriba. |
| [PENDIENTES.md](PENDIENTES.md) | **Acciones abiertas** (checklist). Lo que hay que hacer y quién. | | [PENDIENTES.md](PENDIENTES.md) | **Acciones abiertas** (checklist). Lo que hay que hacer y quién. |
| [`../planeacion/Seguimiento-horas.md`](../planeacion/Seguimiento-horas.md) | Reglas, resumen y reconstrucción pendiente de horas efectivamente trabajadas. |
| [`../planeacion/Seguimiento-horas.csv`](../planeacion/Seguimiento-horas.csv) | Fuente tabular para conciliación con Jira y facturación. |
| `../fuentes/` | **Material crudo**: transcripciones, archivos `.eml`, PRD. No se edita; es evidencia. | | `../fuentes/` | **Material crudo**: transcripciones, archivos `.eml`, PRD. No se edita; es evidencia. |
| `../README.md` | **Estado del proyecto** (resumen ejecutivo, datos clave, decisiones). Se actualiza cuando algo cambia el rumbo. | | `../README.md` | **Estado del proyecto** (resumen ejecutivo, datos clave, decisiones). Se actualiza cuando algo cambia el rumbo. |
@@ -18,6 +20,7 @@ Esta carpeta es el **registro vivo** del proyecto Balam. Cada vez que pase algo
3. **Registra la entrada** en [REGISTRO.md](REGISTRO.md) con la plantilla que corresponda (ver abajo). Usa el siguiente número consecutivo. 3. **Registra la entrada** en [REGISTRO.md](REGISTRO.md) con la plantilla que corresponda (ver abajo). Usa el siguiente número consecutivo.
4. **Mueve los pendientes** que surjan a [PENDIENTES.md](PENDIENTES.md). 4. **Mueve los pendientes** que surjan a [PENDIENTES.md](PENDIENTES.md).
5. Si cambió el **alcance, precio, plazo o una decisión clave**, actualiza también `../README.md`. 5. Si cambió el **alcance, precio, plazo o una decisión clave**, actualiza también `../README.md`.
6. Si hubo trabajo facturable, registra el tiempo real el mismo día en `../planeacion/Seguimiento-horas.csv`; no infieras horas desde el porcentaje de avance.
> Regla de oro: si no está en la bitácora, no pasó. Registrar toma 2 minutos y evita malentendidos caros. > Regla de oro: si no está en la bitácora, no pasó. Registrar toma 2 minutos y evita malentendidos caros.
+805 -11
View File
@@ -11,7 +11,7 @@
- **Pedro Alberto Ayala Elizondo** — Desarrollador / contacto técnico, Balam — `pedro.ayala@balamtalentoestrategico.com` - **Pedro Alberto Ayala Elizondo** — Desarrollador / contacto técnico, Balam — `pedro.ayala@balamtalentoestrategico.com`
- **Paola** — Recursos Humanos, Balam — coordinó la firma del contrato (WhatsApp) - **Paola** — Recursos Humanos, Balam — coordinó la firma del contrato (WhatsApp)
**Periodo:** 30 abr 2026 → 30 jun 2026 **Periodo:** 30 abr 2026 → 22 jul 2026 (última actualización: sesión de reglas Etapa 1 — alta de clientes, fee y flujo Jira, 22-jul)
**Orden:** cronológico (más antiguo arriba) **Orden:** cronológico (más antiguo arriba)
--- ---
@@ -386,7 +386,7 @@ Erika (PM, contacto principal) confirma que **ya pasaron los temas administrativ
## 21 · Jun 2930, 2026 — WhatsApp Johann ↔ Erika · plan de actividades entregado + kickoff agendado ⭐ ## 21 · Jun 2930, 2026 — WhatsApp Johann ↔ Erika · plan de actividades entregado + kickoff agendado ⭐
> Evidencia: `../fuentes/2026-06-29 - WhatsApp - Erika arranque del plan de actividades.md`. Plan: `../planeacion/Plan-actividades.xlsx` (+ `.md`). > Evidencia: `../fuentes/2026-06-29 - WhatsApp - Erika arranque del plan de actividades.md`. Plan vigente consolidado: `../planeacion/Plan-actividades-avance-2026-07-10-ajustado.xlsx` (+ `.md`).
- Johann entrega el **plan de actividades** (Excel sencillo: actividad · fecha iniciofin · responsable · apoyo de Balam): primero Etapa 0 y 1 (29-jun) y luego **enviado completo, las 4 etapas (03)** con fechas tentativas (**30-jun, 12:34**). Las sesiones quedan ubicadas por etapa; la Etapa 01 se mantiene idéntica a lo enviado el 29-jun. - Johann entrega el **plan de actividades** (Excel sencillo: actividad · fecha iniciofin · responsable · apoyo de Balam): primero Etapa 0 y 1 (29-jun) y luego **enviado completo, las 4 etapas (03)** con fechas tentativas (**30-jun, 12:34**). Las sesiones quedan ubicadas por etapa; la Etapa 01 se mantiene idéntica a lo enviado el 29-jun.
- **Erika confirma que será la intermediaria** de todas las sesiones ("lo que necesites me lo pides y yo coordino agendas"). - **Erika confirma que será la intermediaria** de todas las sesiones ("lo que necesites me lo pides y yo coordino agendas").
@@ -400,6 +400,790 @@ Erika (PM, contacto principal) confirma que **ya pasaron los temas administrativ
--- ---
## 22 · Jul 1, 2026 — 7:00 AM · Llamada · Kickoff del proyecto ⭐
> Participan: Noe Rocha, Pedro Ayala, Erika Chávez y Johann. Canal: Microsoft Teams. Evidencia: `../fuentes/2026-07-01 - Transcript - Kick off-Proyecto integración Balam.txt`.
**Resumen:** Arranque formal del MVP. Noé fija la expectativa (plataforma robusta en **menos de 6 meses**, con posible integración futura de **CRM** — "vámonos por partes"). Revisan el GANTT por etapas, el detalle de **accesos**, la **mecánica de horas en Jira** y —el punto más largo— cómo **vincular la factura de la Etapa 0** con el documento contractual.
**Acuerdos / decisiones:**
1. **API BIND (token):** solo **Ara y Arturo** tienen usuario en BIND; se acordó que los tokens salgan de la **cuenta mayor** (todos los permisos habilitados). Para desarrollo se usará el **token de Arturo** (aún sin usar), dejando el de **Ara** para los tableros Power BI. BIND = **1 token por usuario**, no caducable ni múltiple. Se **probará primero el token de Arturo** para confirmar que expone todo lo necesario. Entendimiento: es de **pura consulta** (invoices, facturas, pagos); esta etapa es **solo visualización, sin edición**.
2. **Manual de marca:** Pedro lo **envía hoy por correo** (paquete de branding). → cumplido, ver [#23](#23--jul-1-2026--733-am--correo--pedro--johann--manual-de-imagen-corporativa).
3. **Repositorio:** lo **crea Balam / Pedro** (GitHub **privado**) para montar backend/frontend en Fase 12. (Antes se preveía que lo montara Johann; ahora lo provee Balam.)
4. **Azure:** lo gestionan **Pedro + Noé** (Noé otorga permisos donde Pedro tiene limitantes).
5. **Discovery / proceso actual:** sesión **sí o sí con Arturo y Araceli** (Araceli conoce mejor el proceso; Arturo lleva 3 meses y aún no define todo). **Erika la coordina** (pedirá horas disponibles del equipo).
6. **Horas / Jira:** Johann reportará sus horas en **Jira** igual que los demás consultores, subiendo incluso material informativo para transparencia. **Pedro le enseñará** el flujo. **Erika hace el corte los lunes** y reporta a dirección al cierre de semana.
7. **Facturación Etapa 0 = 30 h (tema abierto):** se confirma el monto (**30 h**), pero la **propuesta** dice Etapa 0 = **1822 h**, lo que el área de pagos/compras cuestionará. Noé necesita que la factura sea **muy vinculante** con un documento. **Acción (Erika + Paola):** revisar si el **contrato** ya ata las 30 h; si no, pedirán por correo a Johann **ajustar la propuesta** para que indique explícitamente las 30 h — **sin etiquetarlo "Etapa 0"** (para no contraponerse con las 1822 h que figuran arriba; "primer pago por 30 h" abarcaría Etapa 0 + un poco más). Johann **aún no factura**: espera la aclaración/correo para emitir con redacción clara. Balam quiere que ya **corra el plazo de pago** (30 días).
8. **Conciliación:** sigue de interés; se evaluará **integrarla en esta primera fase** según lo que arroje el Discovery (que definirá **112 vs 136 h** del módulo de facturación). Hoy la hacen 100% manual.
**Pendientes que surgieron:**
- [ ] Balam/Pedro — generar y entregar el **token de Arturo** (BIND) y probar cobertura de endpoints — arranque Discovery.
- [ ] Balam/Pedro — crear el **repositorio GitHub privado**.
- [ ] Pedro + Noé — **configurar Azure** y permisos.
- [ ] Pedro — **enseñar a Johann el flujo de Jira** (reporte de horas).
- [ ] Erika — **coordinar la sesión de Discovery con Arturo + Araceli** (pedir horas disponibles).
- [ ] Erika + Paola — revisar si el **contrato vincula las 30 h**; de no ser así, solicitar a Johann por correo el ajuste de la propuesta.
- [ ] Johann — **no facturar aún**; al recibir el correo, **ajustar la propuesta** (30 h explícitas, sin llamarlo "Etapa 0", **términos comerciales en una sola sección**) y **emitir la factura**.
**Citas relevantes:** *"Vámonos por partes, como dice Chuck el destripador."* · *"Necesito que sea muy vinculante al tema del pago con lo que dice el documento… me van a decir ¿dónde dice que son 30 horas?"* · *"Como recomendación, cuando hables de términos comerciales, déjalo en una sola sección."*
> **Lectura estratégica:**
> - El bloqueador ya no es solo "accesos": la **emisión de la primera factura** queda condicionada a que Balam aclare internamente (contrato vs propuesta) y lo pida por correo. Johann hizo bien en **no facturar todavía**; conviene tener lista la versión ajustada de la propuesta para responder rápido cuando llegue el correo.
> - **Balam asume más de la infraestructura de lo previsto** (crea el repo, gestiona Azure con Pedro/Noé), lo que reduce fricción de accesos para Johann.
> - **Token de Arturo, solo consulta**: coherente con la estrategia de "lectura primero"; la escritura/emisión se valida en Discovery. Un solo token por usuario refuerza el pendiente de **documentar cuál llave es para qué**.
> - **Erika = punto único** para agendar la sesión Arturo+Araceli, clave del Discovery. **Jira** pasa a ser obligatorio para el reporte de horas (corte lunes).
---
## 23 · Jul 1, 2026 — 7:33 AM · Correo · Pedro → Johann · manual de imagen corporativa
> **CC:** Noe Rocha, Erika Chávez, Araceli Sánchez. Dirección: recibido. Evidencia (adjunto): `../fuentes/manual de imagen corporativa - Balam.pdf`.
**Resumen:** Pedro comparte el **manual de imagen corporativa de Balam** *"para su uso en la herramienta que se desarrollará"*. Sobre el **API de BIND**, indica que buscará a Johann *"en otro momento para ver este tema"* (queda para coordinar por separado). Es el "paquete de branding" que Pedro ofreció en la llamada de hoy ([#22](#22--jul-1-2026--700-am--llamada--kickoff-del-proyecto-)).
**Acción derivada:** cierra el pendiente del **manual de marca**. Los tokens (color, tipografía, uso de logo) quedan destilados en [`../marca/Marca-Balam.md`](../marca/Marca-Balam.md) para el **prototipo** de la Etapa 0.
**Adjuntos:** `manual de imagen corporativa - Balam.pdf`.
> **Nota de marca:** colores oficiales **Amarillo `#F7BD0C`** + **Café `#331F0E`** + Blanco; tipografía **Poppins**. El ámbar `#C0892F` de la propuesta PDF es acento editorial de Johann, distinto del amarillo de marca — para la plataforma se usan los oficiales.
---
## 24 · Jul 1, 2026 — WhatsApp Erika ↔ Johann · agenda la sesión "Proceso actual de facturación y cobranza" (lunes 6-jul)
> Evidencia: `../fuentes/2026-07-01 - WhatsApp - Erika coordinacion sesion facturacion-cobranza.md`.
**7:01 AM:** Erika confirma con Johann que ya están en la sesión de kickoff y que se pueda conectar (ver [#22](#22--jul-1-2026--700-am--llamada--kickoff-del-proyecto-)).
**1:451:46 PM:** Erika pregunta si puede pedir agenda a las **personas involucradas en el proceso de facturación y cobranza** para verlo el **lunes 06 y martes 07 de julio a las 7 am**. Johann da el visto bueno; Erika queda en confirmar por correo.
**6:096:39 PM:** Erika confirma que le **aceptaron la reunión del lunes 06 a las 7 am** y envía la liga de Teams. Convocatoria: *"Proceso actual de facturación y cobranza- Balam"*, lunes 6-jul 7:008:00 AM, organiza Erika, invitados **Johann, Araceli Sánchez Jiménez y Arturo Rosas Hernández** (CC Noe Rocha).
> **Lectura estratégica:**
> - Esta sesión **es** la reunión de Discovery con Arturo + Araceli que Erika se comprometió a coordinar en el kickoff ([#22](#22--jul-1-2026--700-am--llamada--kickoff-del-proyecto-)) — cierra ese pendiente.
> - Solo quedó confirmado el **lunes 6-jul**; no hay evidencia de que se haya agendado también el **martes 7-jul** mencionado por Erika. A confirmar si hace falta una segunda sesión.
---
## 25 · Jul 2, 2026 — 4:184:41 PM · WhatsApp Erika ↔ Johann · agenda/materiales para la sesión del 6-jul
> Evidencia: `../fuentes/2026-07-01 - WhatsApp - Erika coordinacion sesion facturacion-cobranza.md`.
Erika pregunta si Johann necesita **algún documento o ejercicio** de parte de Balam para la sesión del lunes, para poder **anticiparlo a los asistentes**. Johann responde con los puntos que propone cubrir:
- Proceso de facturación en BIND (PDF/XML), con ejemplos en **USD y MXN**.
- Revisión de **cobranza y reglas de crédito**.
- Confirmación de la **"lista blanca" de clientes** (sin recordatorios).
- Cualquier otro tema operativo que tengan en el radar.
- Pregunta si **ya tienen el token de BIND** disponible, para poder arrancar con lo técnico.
> **Lectura estratégica:**
> - Johann fija la **agenda de la sesión de Discovery** (#24) antes de que ocurra — mismos temas que venía preguntando desde el 4-may (facturación BIND, cobranza, lista blanca).
> - Aprovecha el mensaje para **dar seguimiento al token de BIND (de Arturo)**, pendiente desde el kickoff ([#22](#22--jul-1-2026--700-am--llamada--kickoff-del-proyecto-)) — sin respuesta todavía a este punto.
---
## 26 · Jul 2, 2026 — 5:39 PM · Correo · Johann → Noe (CC Ara, Erika, Pedro) · envío de la propuesta v1.2
> **Asunto:** RE: Solicitud de cotización PRD
> **Para:** Noe Rocha · **CC:** Araceli Sánchez Jiménez, Erika Chávez, Pedro Alberto Ayala Elizondo
> Adjunto: `Propuesta-Balam.pdf` (v1.2, 2 MB).
*"Buenas tardes a todos, como comentamos en la sesión, les comparto la propuesta actualizada (v1.2, adjunta), donde queda explícita la facturación inicial de 30 horas al arranque del proyecto, con pago a 30 días naturales. Quedo atento a su confirmación para proceder con la emisión de la factura correspondiente. Cualquier comentario o ajuste, con gusto lo revisamos antes."*
Johann envía la **propuesta v1.2** (30 h de facturación inicial explícitas, condiciones comerciales consolidadas en §3.3) y queda a la espera de que Balam confirme para poder **emitir la factura**.
> **Lectura estratégica:**
> - Johann **toma la iniciativa**: en el kickoff ([#22](#22--jul-1-2026--700-am--llamada--kickoff-del-proyecto-)) el plan era que Erika+Paola revisaran primero el contrato y, de ser necesario, pidieran por correo el ajuste; en vez de esperar ese correo, Johann ya envió la propuesta ajustada directamente, lo que puede **acelerar el ciclo de la factura**.
> - Sigue vigente el candado: **no facturar** hasta recibir la confirmación de Balam sobre este correo. Ver [PENDIENTES.md](PENDIENTES.md).
> - Nota menor: el documento adjunto conserva la frase *"arranque condicionado a contrato u orden de trabajo firmado"* (§3.3 y Próximos pasos), redactada como si la firma estuviera pendiente — cuando el contrato ya se firmó el 26-jun ([#19](#19--jun-26-2026--whatsapp-johann--paola-rh--ajustes-finales-y-firma-del-contrato-)). No debería generar confusión (Balam ya sabe que está firmado), pero queda anotado por si alguien lo señala.
---
## 27 · Jul 6, 2026 — 7:00 AM · Llamada · Discovery: proceso actual de facturación y cobranza ⭐
> Participan: **Araceli Sánchez** (comercial/dirección), **Arturo Rosas Hernández** (administración/facturación), Erika Chávez y Johann. Noé era opcional y no asistió. Canal: Microsoft Teams (~1 h 5 min). Evidencia: `../fuentes/2026-07-06 Proceso actual de facturación y cobranz_ Transcript.txt`.
**Resumen:** Primera sesión de Discovery (Etapa 0). Araceli y Arturo muestran en vivo el proceso completo de **facturación**: entrada por **Jira ITSM** (obligatoria desde hace ~1 mes) → validación de administración → **prefactura en BIND** → emisión de CFDI → **envío por correo con particularidades por cliente**. Se demostró el flujo real en BIND (crearon y cancelaron una prefactura en vivo). Dos reglas de negocio cambiaron en la propia sesión. **La parte de cobranza NO se cubrió** — solo se tocaron la lista blanca y la idea de recordatorios; el proceso de seguimiento de pagos queda pendiente de mapear (cuando Johann preguntó si después seguía cobranza, Ara redirigió al proceso de envío de factura).
### El proceso actual, paso a paso
**1. Entrada — Jira ITSM (portal de servicios interno):**
- Desde hace ~2 quincenas es **mandatorio**: *"si no hay algo que se levante a través de Jira en un ticket, no se factura"*. Antes se controlaba con un Excel manual → facturas olvidadas (descubrían en marzo que enero no se facturó) y errores de moneda.
- Módulo *Administración General → Facturación*, con dos tipos: **"Facturación adicional"** (suma) y **"Bajas"** (resta).
- El portal sirve a **varias empresas** (Balam, Regiotour, Elmstone); el campo "empresa origen" las distingue. A futuro quieren que la plataforma facture también para las demás — por ahora el foco es Balam.
- **Campos del formulario:** empresa origen · summary · proyecto · **cliente nuevo (sí/no** — si es nuevo se adjunta **cédula de identificación fiscal + cotización**; si es recurrente solo cotización) · moneda (MXN/USD) · **días de crédito** (default 30; a veces 45; CEMEX 90 innegociable) · periodo de incidencias (horas extra, periodos de servicio, comentarios) · **facturación recurrente (sí/no)** + periodo de recurrencia en meses (el equipo de tecnología trabaja en que las recurrencias se detonen solas cierto día).
- **Quién lo llena:** siempre la parte **comercial = Araceli** (excepcionalmente Pau la apoya). *"El deber ser es que la parte comercial siempre levante el ticket."*
- **Tres vías generan factura:** (a) ticket directo de facturación adicional; (b) **Headhunting** — el ticket de RH detona automáticamente una factura de anticipo y, al colocar a la persona, el 50% o 100% restante; (c) **Staff augmentation** — al arrancar la persona en el cliente se genera el ticket de factura.
- **Ruteo:** todos los tickets se asignan por regla a **una sola persona: Arturo**. Administración hace doble check (datos, cédula fiscal, estado de cuenta) sobre la lista.
- **Flujo interno del ticket con SLAs:** solicitud abierta → proceso de facturación → (espera del colaborador / cancelado) → se adjunta **PDF + XML obligatorios** como evidencia → botón de validación/autorización → estatus **"facturado"**. Flujo alterno de **facturación extranjera**: sin XML, solo la **invoice en PDF** ("validación extranjera").
**2. BIND ERP (lo opera Arturo):**
- Consulta: *Finanzas → Cuentas por cobrar* (facturas en proceso, vencidas, pagadas — ahí dan seguimiento a cobranza).
- Creación: *Ventas → generar documento*. Siempre hacen **prefactura primero** (no se timbra ante el SAT; cancelar una factura timbrada es retrabajo administrativo y contable) → doble check → **Emitir CFDI**.
- Prerequisitos que asumen cargados: cliente dado de alta, cuentas, moneda. **Pregunta abierta que dejó Arturo:** definir qué hará la automatización cuando el cliente NO esté dado de alta (proceso aparte).
- Campos relevantes: sucursal (hoy solo matriz; serviría para facturar por unidad de negocio a futuro) · días de crédito (manual, editable, default del cliente) · orden de compra (deber ser: OC autorizada como prerequisito) · **uso CFDI**: "gastos en general" (nacional) y **"sin efectos fiscales"** (extranjera — se timbra igual pero con **IVA 0%**) · **método de pago PPD/PUE** · conceptos precargados editables (ej. 029 "consultoría y servicios"; sugieren incluir el nombre del recurso) · dirección fiscal precargada · comentarios (ponen el ticket de Jira para cruzar reportes).
- **⚠️ PPD vs PUE es delicadísimo:** siempre dan crédito → casi todo es **PPD**. Hace ~2 años administración seleccionó PUE por error y les cayó un **requerimiento del SAT**. PUE exige complemento de pago timbrado el mismo día. (Regla de validación clara para la plataforma.)
- **⚠️ IVA no es automático en BIND:** "sin efectos fiscales"/extranjero debería ir con 0% y pesos con 16%, pero BIND **no lo pone solo** — Arturo lo capturó manualmente (y en el ejemplo puso 16% en una sin efectos fiscales; Ara lo señaló). Otra validación clara para la plataforma. Además, por ser reclutadora a veces llevan retenciones adicionales.
- Tras la prefactura se habilitan: emitir CFDI, registrar pago, nota de crédito, **editar**, **copiar** (así manejan las recurrencias), cancelar, exportar partidas a Excel, **enviar por email** (a los correos configurados del cliente), descargar PDF, póliza contable.
**3. Envío al cliente (el paso que les falta sistematizar):**
- La facturación "termina" hasta que la factura **se envía por correo**, y cada cliente tiene particularidades: **Axie** (extranjero): facturas + estado de cuenta de todas las facturas · **CEMEX**: factura a un hub + **Excel de horas del colaborador con visto bueno del jefe** + **nomenclatura específica del asunto** (número de proveedor, mes, número de factura en posiciones exactas) y redacción específica del correo · **Dilo** (proyectos): factura + cotización del proyecto · **Acuntia**: .zip + estado de cuenta.
- Tienen un Excel con cliente → destinatarios; les falta la columna de adjuntos/particularidades. **Ara + Arturo se comprometieron a completarlo y enviarlo HOY (6-jul).**
- Volumen real: **~55 facturas/mes** de solo **46 clientes** — el cliente mayor exige **una factura por colaborador** (~40 colaboradores); agrupadas serían 56 facturas.
### Dolores (en palabras de Ara, dirección general)
- El caos de control ya lo mitigó Jira; el dolor vivo es que **el proceso en BIND sigue siendo manual** → errores en montos, descripciones, moneda, IVA, PPD/PUE.
- No quiere "engrosar la nómina" con capturistas: quiere que la automatización absorba la carga y **enfocar a la gente en actividades de más valor**. El volumen es bajo (~55/mes); el problema es la **incidencia de errores**, y están en franco crecimiento.
- Reporteo ya lo cubren con Power BI; lo que piden de la plataforma es que **administración solo valide prefacturas** antes del envío.
- **Dónde quieren la automatización:** después de Jira (confirmado explícitamente por Ara y Arturo cuando Johann lo preguntó). Idea de Arturo: que los agentes **observen Jira** (botones/aprobaciones del flujo) para saber cuándo accionar en BIND.
### 🔄 Cambios de reglas de negocio (decididos en la sesión)
1. **Lista blanca ELIMINADA.** Solo tenían a **Acuntia** (nunca hubo "top 3" reales). Y en la propia llamada **Ara revirtió la decisión**: los recordatorios de morosidad deben ir a **TODOS los clientes, sin excepciones** — hoy arrastran una factura de febrero y otra de abril justamente del cliente "muy pagador" por no recordarle a tiempo. Arturo coincidió: con recordatorios automáticos no habrían llegado a julio con una factura de febrero.
2. **Cotización en BIND = punto de partida OBLIGATORIO.** Ara lo fijó como requisito formal: *"sí puedes tomar, Johann, como un requisito de que vamos a partir de una cotización del sistema"*. El deber ser: comercial genera la **cotización en BIND** → se adjunta al ticket de Jira → administración (o el agente) la **convierte a prefactura con un clic** → validación humana → CFDI. Para **cliente nuevo**: comercial levanta ticket → administración (que tiene el privilegio) da de alta al cliente en BIND → avisa → comercial ya puede cotizar. No quiere "desarrollo con parchecitos". *(Excepción discutida y descartada: aun en headhunting con rango salarial abierto, la cotización puede esperar al cierre — siempre habrá cotización.)*
**Acuerdos / próximos pasos de la sesión:**
- [ ] **Ara + Arturo** — enviar hoy (6-jul) el **Excel de particularidades de envío por cliente** (destinatarios + adjuntos + nomenclatura).
- [ ] **Johann** — trabajar el **prototipo** reflejando el flujo real (lo dijo al cierre: *"ya me da una idea más clara de cómo trabajar el prototipo que les mostraré"*). Dudas de seguimiento vía **Erika**.
> **Lectura estratégica:**
> - **El flujo real valida el diseño de la propuesta**: cotización → factura vía API era exactamente el mecanismo cotizado en la Etapa 2, y ahora además es política interna de Balam. El pipeline objetivo queda nítido: **Jira (disparador) → cotización BIND → prefactura → validación humana → CFDI → envío por correo**.
> - **La eliminación de la lista blanca simplifica el MVP** (el catálogo/lista configurable puede quedar como capacidad, hoy vacía). PERO ojo: lo que Ara y Arturo describen son **recordatorios automáticos a clientes**, que están **diferidos al Anexo B** (el MVP trae alertas *internas*). Su expectativa apunta a ese módulo — conviene aclararlo pronto o anticipar que lo pidan al cierre del MVP.
> - **Jira como disparador del flujo** (agentes observando tickets/botones) se parece al "Nivel 3" (generación desde eventos) que estaba en fase posterior. La integración con la API de Jira no está cotizada en el MVP — vigilar ese límite de alcance cuando se diseñe el prototipo.
> - **Se levantaron reglas de validación de oro para la plataforma:** PPD por default (PUE solo consciente — ya les costó un requerimiento del SAT) · IVA 16% MXN / 0% extranjero-sin efectos fiscales (BIND no lo automatiza) · prefactura SIEMPRE antes de timbrar · OC/cotización como prerequisito · alta de cliente como flujo aparte.
> - **El token de BIND NO se tocó en la sesión** — sigue abierto desde el kickoff y el WhatsApp del 2-jul ([#25](#25--jul-2-2026--418441-pm--whatsapp-erika--johann--agendamateriales-para-la-sesión-del-6-jul)).
> - **La cobranza quedó sin mapear** — la sesión del **martes 7-jul** (que Erika mencionó desde el 1-jul) sería el espacio natural para cubrirla: cómo dan seguimiento hoy a los pagos, quién persigue morosos, cómo concilian cuentas por cobrar, y de dónde saldría el aging. Proponérselo a Erika.
> - **Multi-empresa** (Regiotour, Elmstone) aparece como deseo de futuro de Ara — anotarlo para el roadmap, no para el MVP.
---
## 28 · Jul 6, 2026 — 9:01 AM12:40 PM · WhatsApp Erika ↔ Johann · token de BIND ENTREGADO ⭐
> Evidencia: `../fuentes/2026-07-06 - WhatsApp - Erika sesion discovery y seguimiento token BIND.md`.
Tras la sesión de Discovery (78 am, [#27](#27--jul-6-2026--700-am--llamada--discovery-proceso-actual-de-facturación-y-cobranza-)), Erika revisa el **plan de actividades** línea por línea:
- **9:01** — Sobre *"Entrega y validación de accesos (BIND, Azure, manual de marca) · lun 06 → mar 07 jul"*: *"¿solo necesitas el token tal cual?"* **Johann (9:539:54):** *"Sí, para BIND solo necesito el token tal cual. Lo de Azure no me urge hoy y el manual de marca ya lo tengo."*
- **10:26** — Erika: *"okey deja lo solicito"***el token queda formalmente solicitado dentro de Balam.**
- **10:2810:37** — Sobre *"Validación técnica de la API de BIND con la cuenta real · mar 07 → mié 08 jul"*: *"¿se necesita una sesión?"* **Johann (10:37):** *"No, esa validación la hago yo por mi cuenta ya teniendo el token."*
- **12:1012:19** — **Token GENERADO** dentro de Balam: *"ya solicitaran el token ahorita te lo comparto"*. Erika desconoce si tiene vencimiento (según el kickoff: no caduca), comenta que lo tienen en un **.txt** y pregunta si sirve **por correo**. Johann (12:25): sí, por correo y .txt está bien; (12:27) pide que le confirmen **a qué usuario pertenece** el token para documentarlo.
- **12:40** — Erika: *"ya se compartió por correo"* → ✅ **TOKEN DE BIND ENTREGADO.**
> **Lectura estratégica:**
> - **El bloqueador del token se resolvió el mismo día:** Johann lo empujó a las 9:01 vía el plan de actividades, Erika lo solicitó a las 10:26 y estaba entregado a las 12:40 — un día antes de la fecha del plan (mar 7-jul). Cierra el seguimiento que venía desde el 2-jul ([#25](#25--jul-2-2026--418441-pm--whatsapp-erika--johann--agendamateriales-para-la-sesión-del-6-jul)).
> - Que Erika trabaje sobre el plan de actividades confirma que **el Excel de Johann es el instrumento real de seguimiento** — mantenerlo al día paga.
> - **Quedan dos higienes:** (1) Balam debe confirmar **de qué usuario salió** el token (Johann lo pidió 12:27, Erika "okey" — el acuerdo del kickoff fue el de **Arturo** para dev); (2) tratarlo como **llave de producción** (sin sandbox): guardarlo en gestor de secretos, no dejarlo en el correo/.txt.
> - **Desbloquea la validación técnica de la API** (mar 7 mié 8 del plan) — puede incluso adelantarse hoy.
---
## 29 · Jul 6, 2026 — 12:38 PM · Correo · Pedro → Johann (CC Noe, Erika) · entrega formal del token de BIND ✅
> **Adjunto:** `bind_token_api.txt`. Evidencia: `../fuentes/2026-07-06 - Correo - Pedro entrega token BIND (usuario Arturo Rosas).md`.
Pedro entrega el **token de la API de BIND** por correo (es el envío que Erika anunció por WhatsApp a las 12:40, [#28](#28--jul-6-2026--901-am1240-pm--whatsapp-erika--johann--token-de-bind-entregado-)) y **confirma que fue generado con el usuario de Arturo Rosas** — conforme al acuerdo del kickoff (llave de Arturo para desarrollo; la de Ara para Power BI). Se ofrece para validar dudas directamente. Erika agradece en el hilo (12:39). **Johann acusa recibo (~3:28 pm):** toma nota del usuario de Arturo para documentarlo, confirma que ya puede comenzar a trabajar con la API y que cualquier duda la validará con Pedro — deliberadamente **sin comprometer entregas adicionales** (los hallazgos se integran al documento de cierre de la Etapa 0 ya planeado).
> **Lectura estratégica:**
> - Cierra **las dos puntas** del pendiente de accesos BIND: token entregado **y** usuario documentado. La entrega por correo (no WhatsApp) además deja la evidencia formal en el canal correcto.
> - Higiene inmediata: pasar el token del `.txt` a un **gestor de secretos** y no conservarlo en el buzón.
> - Dato colateral: la firma de Pedro lo identifica como **ITSM Analyst / Consultor de Gestión de Servicios TI** — coherente con que él montó el portal Jira ITSM del Discovery.
---
## 30 · Jul 6, 2026 — 3:01 PM · WhatsApp Johann → Erika · propone sesión de cobranza (martes 7-jul)
> Evidencia: `../fuentes/2026-07-06 - WhatsApp - Erika sesion discovery y seguimiento token BIND.md` (bloque 7).
Johann plantea a Erika que la sesión de hoy solo alcanzó para **facturación y envío**, y que falta mapear **cobranza** (seguimiento de pagos y cuentas por cobrar). Propone el **martes 7-jul, 7am** — retomando la fecha que Erika misma había mencionado el 1-jul — o cuando se acomode en la semana. **Erika queda en revisar la agenda con las personas involucradas y confirmar.**
> **Lectura estratégica:**
> - Completa el Discovery pendiente de [#27](#27--jul-6-2026--700-am--llamada--discovery-proceso-actual-de-facturación-y-cobranza-) reutilizando la propia propuesta de Erika (bajo costo de coordinación). Interlocutor clave: **Arturo** (lleva CxC en BIND); Ara deseable por el contexto comercial.
> - Idealmente se confirma antes del **viernes 10** (validación del prototipo), para que la pantalla de Cobranza llegue respaldada por el proceso real y no como hipótesis.
---
## 31 · Jul 6, 2026 — 4:33 PM · Correo · Noé → Johann, Pedro (CC Erika) · salvaguardas sobre el token ⚠️
> **Importancia alta.** Evidencia: `../fuentes/2026-07-06 - Correo - Pedro entrega token BIND (usuario Arturo Rosas).md` (respuesta de Noé en el hilo).
Noé responde al hilo de la entrega del token con dos instrucciones:
1. **A Johann:** mientras Pedro revisa si el acceso es de lectura o también de **escritura**, aplicar *"las salvaguardas necesarias para evitar alguna afectación operativa"*.
2. **A Pedro:** si es necesario, **crear un usuario específico de solo lectura** en BIND para esta etapa de exploración — *"la cuenta de Arturo tiene algunos privilegios elevados que creo que no serían necesarios en este momento"*.
**Implicación:** el token de Arturo **podría ser reemplazado** por uno de un usuario nuevo de solo lectura.
> **Lectura estratégica:**
> - La preocupación de Noé es **exactamente el diseño ya construido**: el sandbox opera en modo solo-lectura por defecto con bloqueo de escrituras en código, dry-run, cuota vigilada y token fuera del repo (`.gitignore` ya cubre `bind_token_api.txt` y `*.env`). Responder describiendo esas salvaguardas convierte un correo de riesgo en una oportunidad de confianza con el CTO.
> - Ojo operativo: si Pedro crea un usuario nuevo, **el token cambiará** — no invertir esfuerzo en atar nada al token actual; el cliente ya está parametrizado por variable de entorno, el cambio es trivial.
> - Coherente con la estrategia "lectura primero" de la propuesta: nadie está pidiendo frenar la validación, solo asegurar el perímetro.
---
## 32 · Jul 6, 2026 — tarde · Validación técnica de la API de BIND con la cuenta real ⭐ ✅
> Actividad del plan "Validación técnica de la API de BIND" (mar 7 mié 8) — **ejecutada un día antes**, el mismo día en que llegó el token. Evidencia completa: [`../bind-api-sandbox/VALIDACION-API.md`](../bind-api-sandbox/VALIDACION-API.md) (117 peticiones, exclusivamente GET, solo estructura — cero datos reales persistidos).
**Veredictos clave:**
1.**Plan A del saldo CONFIRMADO** — el riesgo central de la propuesta quedó resuelto a favor: cada fila de `Invoices` trae `Total`, `Payments` (acumulado) y `CreditNotes`; el saldo por factura es una resta local, verificada aritméticamente. **No se activa el Plan C (+68 h)** — la inversión apunta a la parte baja del rango.
2.**El flujo del MVP es 100% sostenible en lectura:** cotizaciones legibles (con partidas y comercial), prefacturas distinguibles (`UUID null` / `IsFiscalInvoice false`), PPD/PUE y días de crédito auditables (en el detalle), IVA por partida (habilita la validación 16%/0%), **PDF del CFDI descargable por API** (insumo del módulo de envío), aging viable con `ExpirationDate` + saldo.
3.**No existe recurso de pagos individuales ni de complementos de pago (REP)** — 20 nombres probados, todos 404. La cobranza operativa del MVP funciona igual (detecta pago por transición de estatus/residual), pero la fecha valor del pago y los REP del flujo PPD no son visibles. **Escalar a Pedro.**
4. ⚠️ **Sin vínculo cotización→factura en la API** — la trazabilidad la llevará la plataforma (registrar el par al orquestar la conversión).
5. ⚠️ **Rarezas a cablear con cuidado:** token inválido responde 500 (no 401); `$select` y conteos no funcionan (paginación manual con `$top=100`); nomenclatura CFDI **invertida** vs SAT (`CFDIPaymentTerm` = PPD/PUE); `CFDIUse` es código interno (falta tabla de mapeo); typo real del API (`Loctaion`); campos clave solo en el detalle → **sync incremental obligatorio**.
6.**Token acotado a una sola empresa** (la de Arturo → Balam) — multi-empresa confirmado fuera del alcance por API.
7. **Presupuesto de sync:** ~1,000 req/día con polling cada 15 min ≈ 5% del límite de 20K. Holgado.
**Preguntas que quedan para Pedro/doc (§10 del documento):** endpoint de pagos/REP no descubierto · tabla `CFDIUse` interno→clave SAT · shape del endpoint `/xml` · códigos de `Status` >2 · webhooks/eventos.
> **Lectura estratégica:**
> - **El Discovery técnico ya pagó:** el Plan A confirmado elimina la mayor incertidumbre de horas de la propuesta, y todo lo que el MVP necesita en lectura existe. La actividad del plan se cerró **anticipada** — buen dato para el corte de Erika del lunes.
> - El hueco de REP/pagos es real pero **no bloquea el MVP** (cobranza operativa funciona por transición de estatus); importa para el flujo PPD completo y para conciliación (Anexo B). Escalarlo con Pedro esta semana, idealmente junto con la tabla de `CFDIUse`.
> - Las salvaguardas prometidas a Noé ([#31](#31--jul-6-2026--433-pm--correo--noé--johann-pedro-cc-erika--salvaguardas-sobre-el-token-)) se cumplieron al pie: GET-only por construcción, presupuesto de peticiones, reporte sanitizado, token fuera de git.
---
## 33 · Jul 6, 2026 — 4:345:03 PM · WhatsApp Erika → Johann · confirma operar solo-lectura (eco del correo de Noé)
> Evidencia: `../fuentes/2026-07-06 - WhatsApp - Erika sesion discovery y seguimiento token BIND.md` (bloque 8).
**Resumen:** Erika transmite por WhatsApp, en versión breve, la instrucción de Noé sobre salvaguardas del token ([#31](#31--jul-6-2026--433-pm--correo--noé--johann-pedro-cc-erika--salvaguardas-sobre-el-token-)): *"referente a lo del token que se te compartió, para evitar complicaciones operativas."* Johann confirma: *"por el momento estaré haciendo operaciones solo de lectura."* Erika agradece el entendimiento.
**Acción derivada:** confirmación informal, no sustituye la respuesta formal por correo a Noé (borrador listo, ver [PENDIENTES.md](PENDIENTES.md)) — conviene enviarla igual para dejar constancia en el canal formal, tal como pidió Noé.
> **Lectura estratégica:**
> - Erika actúa como puente entre la instrucción formal de Noé (correo, 4:33 pm) y Johann — coherente con su rol de intermediaria única.
> - El contenido no agrega nada nuevo a lo ya resuelto por diseño (sandbox solo-lectura); es una confirmación de bajo costo que sostiene la confianza mientras se prepara la respuesta formal.
---
## 34 · Jul 6, 2026 — 6:366:40 PM · WhatsApp + convocatoria Outlook/Teams · confirma sesión de cobranza (martes 7-jul) ⭐
> Evidencia: `../fuentes/2026-07-06 - WhatsApp - Erika sesion discovery y seguimiento token BIND.md` (bloque 9).
**Resumen:** Erika envía la convocatoria **"Proceso actual de cobranza- Balam"**, martes **07/07/2026, 7:008:00 AM**, por Microsoft Teams. Organiza Erika Chávez; invitados **Johann, Araceli Sánchez Jiménez y Arturo Rosas Hernández** (CC: Noé Rocha) — cierra la propuesta que Johann hizo el mismo día a las 3:01 pm ([#30](#30--jul-6-2026--301-pm--whatsapp-johann--erika--propone-sesión-de-cobranza-martes-7-jul-)). Johann confirma recepción por WhatsApp (6:40 pm).
**Acción derivada:** asistir a la sesión el martes 7-jul, 7:00 am (agenda: cómo dan seguimiento hoy a pagos y cuentas por cobrar, quién persigue morosos, cómo concilian, de dónde saldría el aging — temas listados en la lectura estratégica de [#27](#27--jul-6-2026--700-am--llamada--discovery-proceso-actual-de-facturación-y-cobranza-)).
> **Lectura estratégica:**
> - **Cierra el hueco de Discovery que quedó abierto el 6-jul:** facturación y envío ya están mapeados ([#27](#27--jul-6-2026--700-am--llamada--discovery-proceso-actual-de-facturación-y-cobranza-)); cobranza se mapea el 7-jul, antes del viernes 10 (fecha objetivo para la validación del prototipo) — como Johann buscaba al proponerlo.
> - **Interlocutores correctos confirmados:** Arturo (lleva CxC en BIND) y Araceli (contexto comercial), igual que en la sesión anterior — buena señal de continuidad.
> - Convocatoria aún sin respuestas registradas ("4 sin respuesta") al momento de reenviarla — no es un riesgo en sí, Balam ya confirmó la sesión por WhatsApp.
---
## 35 · Jul 7, 2026 — 7:00 AM · Llamada · Discovery: proceso actual de cobranza (sin grabación) ⭐
> Participan: **Arturo Rosas** (administración/CxC — mostró el proceso) y Johann; la convocatoria incluía también a Araceli y Erika (CC Noé). Canal: Microsoft Teams, 7:008:00 AM. **⚠️ Sin grabación** — evidencia: `../fuentes/2026-07-07 - Notas - Proceso actual de cobranza (sin grabacion).md` (notas de memoria de Johann, mismo día).
**Resumen:** Segunda sesión de Discovery — cierra el mapeo de **cobranza** que quedó pendiente el 6-jul ([#27](#27--jul-6-2026--700-am--llamada--discovery-proceso-actual-de-facturación-y-cobranza-)). Arturo mostró sus **Exceles de control** (facturas abiertas, canceladas, días de morosidad — el aging de facto) y el flujo real de un pago: el cliente avisa por **correo/mensaje con su estado de cuenta** → se comparte con el **despacho contable**, que **registra los pagos en BIND uno por uno** → un **Power BI** (conectado, según Arturo, con **su token**) muestra la cartera pero **no está al día**.
**El detalle que complica conciliar:**
- Un mismo pago puede cubrir **decenas de facturas** ("10 pesos divididos en 40 facturas" — consistente con el cliente que exige factura por colaborador, ~40).
- Los comprobantes llegan **todos con el mismo patrón de referencia** (tipo `num_referencia.pdf`) → la referencia no distingue facturas, **se concilia por folio**.
- Al recibir el dinero hay un **fee/comisión** → los montos **no cuadran exactos** contra el total facturado.
- Caso mostrado: Arturo pidió a **Acuntia** su relación de pagos; respondieron con un **Excel pago ↔ folio** — control de ambos lados, pero totales distintos por el fee.
- Casos límite: clientes que pagan **facturas viejas arrastradas** (aplicación fuera de orden) y facturas pagadas cuyo **registro va atrás de la realidad**.
**Lo que buscan:** ser **proactivos** — recordatorios configurables (pasados **15 días** de vencimiento, correo al cliente) o al menos visibilidad inmediata del atraso. Su evolución: eran **reactivos** ("ya hace rato que no me paga"), hoy son **activos**, quieren ser **proactivos**.
**Pendientes que surgieron:**
- [ ] Johann — **pedir a Arturo los Exceles**: control de cobranza (abiertas/canceladas/morosidad), el Excel tipo Acuntia (pago↔folio) y un estado de cuenta ejemplo.
- [ ] Johann — preguntar **cómo registran en BIND la diferencia por fee** (¿pago parcial con residual? ¿nota de crédito?).
- [ ] Johann/Pedro — **verificar qué token alimenta el Power BI** (ver lectura estratégica).
> **Lectura estratégica:**
> - **El diseño de cobranza del MVP queda respaldado por el proceso real:** el aging **por factura** con residual (Plan A: `Total Payments CreditNotes`, confirmado en [#32](#32--jul-6-2026--tarde--validación-técnica-de-la-api-de-bind-con-la-cuenta-real--)) cubre exactamente los casos que Arturo describió — pagos fuera de orden y facturas arrastradas se leen por factura, no por cliente.
> - **Regla de diseño nueva — tolerancia a fees:** "pagada" no puede exigir residual = 0 exacto; hace falta un **umbral configurable** para no mostrar como morosas facturas saldadas con comisión. Aplica también a la conciliación futura (Anexo B).
> - **El hueco de pagos/REP del API ([#32](#32--jul-6-2026--tarde--validación-técnica-de-la-api-de-bind-con-la-cuenta-real--)) ahora tiene caso de negocio:** el despacho registra pagos **a mano, uno por uno** — automatizar ese registro requeriría justo el endpoint que no apareció. Refuerza la escalación a Pedro.
> - ⚠️ **Discrepancia de tokens a verificar:** Arturo mostró el Power BI conectado con **su** token, pero el kickoff ([#22](#22--jul-1-2026--700-am--llamada--kickoff-del-proyecto-)) acordó **Ara = Power BI / Arturo = desarrollo**. BIND emite **1 token por usuario**: si Power BI y el desarrollo comparten el de Arturo, el reemplazo por un usuario solo-lectura que planteó Noé ([#31](#31--jul-6-2026--433-pm--correo--noé--johann-pedro-cc-erika--salvaguardas-sobre-el-token-)) **rompería uno de los dos**. Verificar con Pedro antes de cualquier cambio.
> - **Los recordatorios proactivos a clientes reaparecen** (tercera vez: propuesta original, sesión del 6-jul, hoy) — siguen siendo módulo del **Anexo B** (el MVP trae alertas internas + visibilidad). La aclaración de expectativas ya no puede esperar mucho.
> - **Actor nuevo en el mapa: el despacho contable** — no había aparecido en el Discovery de facturación; es quien toca BIND para los pagos.
> - Los **Exceles de Arturo son la especificación de facto de la pantalla de Cobranza** (columnas, buckets de morosidad que ya usan) — pedirlos con las salvaguardas de siempre: datos reales fuera del repo y de los documentos, solo estructura.
---
## 36 · Jul 7, 2026 — 12:27 PM · WhatsApp Erika → Johann · seguimiento del pendiente de BIND (¿probar escritura?)
> Evidencia: `../fuentes/2026-07-07 - WhatsApp - Erika seguimiento BIND.md`.
**Resumen:** Erika revisa de nuevo el plan de actividades y pregunta por la línea **"Validación técnica de la API de BIND con la cuenta real"** (vigente hoy 7-jul y mañana 8-jul según el plan): *"johan respecto a este punto, es para hoy y mañana, todo bien, necesitas algo?"* — la misma actividad que Johann ya adelantó y cerró el 6-jul ([#32](#32--jul-6-2026--tarde--validación-técnica-de-la-api-de-bind-con-la-cuenta-real--)).
> ⚠️ A las 9:28 am Erika había respondido *"no"* a un mensaje previo que no está incluido en la evidencia disponible — contexto pendiente de aclarar.
**Acción derivada:** Johann evalúa si hace falta sondear los endpoints de **escritura (POST/PUT)** de BIND, ya que la validación de lectura cerró en #32. **Decisión:** no probarlos en vivo contra producción todavía — sigue vigente la instrucción de Noé de mantener el modo solo-lectura mientras Pedro confirma el alcance real del token ([#31](#31--jul-6-2026--433-pm--correo--noé--johann-pedro-cc-erika--salvaguardas-sobre-el-token-)), y no hay sandbox donde ensayar sin riesgo fiscal. Camino seguro en su lugar: revisar el **catálogo de operaciones del portal de desarrolladores de BIND** (ya referenciado por Noé el 25-may — incluye al menos `Activities_AddActivity`) para documentar qué escrituras existen, sin ejecutarlas. Respuesta a Erika: nada adicional urgente para las pruebas; lo único abierto es escalar con Pedro las preguntas técnicas ya listadas en [PENDIENTES.md](PENDIENTES.md) (endpoint de pagos/REP, tabla `CFDIUse`, shape de `/xml`, webhooks).
> **Lectura estratégica:**
> - Buena disciplina: la tentación de "ya que tenemos el token, probemos escritura" se descarta porque **contradice justo lo que Noé pidió resguardar** — probarlo ahora sería el peor momento (token de Arturo con privilegios elevados, posible reemplazo en curso).
> - El `BindClient` ya está diseñado para este escenario: modo `read-only` bloquea cualquier método mutante en código (`BindReadOnlyViolation`), y `addActivity()` queda estructuralmente listo pero inerte hasta que se active `dry-run`/`write` con autorización — los candados de la propuesta (dry-run + confirmación humana) siguen intactos.
---
## 37 · Jul 7, 2026 — 3:565:49 PM · WhatsApp Erika ↔ Johann · seguimiento al usuario de lectura de BIND
> Evidencia: `../fuentes/2026-07-07 - WhatsApp - Erika seguimiento BIND.md` (bloque 3).
Erika confirma que, mientras se resuelve si Pedro crea el **usuario de solo lectura** que pidió Noé por correo ([#31](#31--jul-6-2026--433-pm--correo--noé--johann-pedro-cc-erika--salvaguardas-sobre-el-token-)), ella sigue operando en BIND con el **usuario de Arturo** a modo de lectura, sin que esto la bloquee. Pregunta si ese usuario de lectura se lo iban a crear. Johann aclara que **Noe le pidió a Pedro revisar si era necesario crearlo** — la decisión no depende de Erika. Erika, reconociendo que no está familiarizada con el tema, queda en revisarlo con el equipo técnico.
> **Lectura estratégica:**
> - Confirma que el reemplazo de token propuesto por Noé el 6-jul ([#31](#31--jul-6-2026--433-pm--correo--noé--johann-pedro-cc-erika--salvaguardas-sobre-el-token-)) **sigue sin resolverse una semana después** — Pedro no ha confirmado si crea el usuario nuevo. No es bloqueante hoy (Erika opera con el de Arturo sin problema), pero sigue abierto el riesgo señalado en [#35](#35--jul-7-2026--700-am--llamada--discovery-proceso-actual-de-cobranza-sin-grabación-): si el Power BI de Arturo comparte el mismo token que el de desarrollo, reemplazarlo rompería uno de los dos usos.
---
## 38 · Jul 8, 2026 — 10:09 AM10:55 AM · WhatsApp Erika ↔ Johann · datos ficticios para los Exceles de cobranza
> Evidencia: `../fuentes/2026-07-08 - WhatsApp - Erika datos ficticios cobranza y avance fase 0.md` (bloques 12).
Erika avisa que Balam está **validando internamente** si puede compartir la información de cobranza que Johann solicitó ([#35](#35--jul-7-2026--700-am--llamada--discovery-proceso-actual-de-cobranza-sin-grabación-), pendiente en PENDIENTES.md), por tratarse de información delicada. Johann ofrece una salida de bajo fricción: acepta que sean **datos ficticios**, ya que lo que necesita es la **estructura** que siguen, no los datos reales. Erika traslada la propuesta al equipo (10:50) y queda en avisar cuando tenga respuesta.
> **Lectura estratégica:**
> - Resuelve por adelantado la fricción de confidencialidad de los Exceles de cobranza pedidos en [#35](#35--jul-7-2026--700-am--llamada--discovery-proceso-actual-de-cobranza-sin-grabación-): en vez de esperar una validación legal/interna que podría demorar, Johann baja el estándar a "estructura, no datos reales" — coherente con la salvaguarda ya prometida a Noé de mantener datos reales fuera del repo y de los documentos.
> - Sin fecha comprometida para la respuesta de Balam; sigue siendo **no bloqueante** para el avance del prototipo.
---
## 39 · Jul 910, 2026 · WhatsApp Erika ↔ Johann · avance de Fase 0 + prototipo sin sesión de validación agendada
> Evidencia: `../fuentes/2026-07-08 - WhatsApp - Erika datos ficticios cobranza y avance fase 0.md` (bloques 34).
**9-jul, 7:20 PM:** Erika pide a Johann un corte de **avance de las actividades de Etapa 0** ("cómo vamos"). Johann responde hasta las 9:10 PM preguntando por qué medio compartirlo, sin resolverlo esa noche.
**10-jul, 8:419:39 AM:** Erika insiste ("nomás dime qué actividades y % de avance"). Johann reconoce que **no confirmó la sesión de validación del prototipo** que él mismo se había puesto como meta para el **viernes 10-jul** (ver PENDIENTES.md): el día anterior no dio seguimiento y no quedó agendada la reunión. Ofrece, en su lugar, **compartir el prototipo por correo con sus propios comentarios**. Erika acepta y da instrucciones de destinatarios, **corrigiéndose dos veces en minutos**: primero pide copiar a Pedro, al Ing. Noé **y a Araceli** (9:00); a los 21 minutos corrige — sin Araceli (9:219:22); y pocos minutos después acota aún más — **solo a ella y al Ing. Noé, con Pedro en copia**, "nosotros se los pasamos internamente" (9:28). Johann confirma y, al cierre, retoma la pregunta pendiente del 9-jul sobre si el % de avance de Fase 0 se reporta por el mismo canal de WhatsApp — **sin respuesta aún al cierre de este tramo**.
> **Lectura estratégica:**
> - **Dos pendientes de Johann quedan expuestos por la falta de seguimiento propio:** (1) el reporte de avance/% de Fase 0 que Erika pidió desde el 9-jul, y (2) la sesión de validación del prototipo del viernes 10-jul (comprometida en PENDIENTES.md) que no se agendó a tiempo. Ambos se resuelven convergiendo en un solo entregable: **correo con el prototipo (imágenes) + avance de Fase 0**, en vez de una reunión.
> - **Lista de destinatarios del correo del prototipo, final:** Erika + Ing. Noé, **CC Pedro únicamente** — Araceli queda excluida (Balam decide compartirlo con ella internamente). Difiere del patrón habitual del hilo de correo principal, donde Araceli sí solía ir en copia — respetar esta instrucción explícita para este envío.
> - Sigue sin resolverse el % de avance de Fase 0 que se debe reportar — acción abierta de Johann.
---
## 40 · Jul 10, 2026 · Correo · Johann → Erika, Noé (CC Pedro) · entrega del prototipo Etapa 0 ⭐
> Evidencia documental: `../prototipo/Correo-prototipo-Etapa0.md`. Adjunto: `../prototipo/Prototipo-Balam-Etapa0.pdf`.
Johann entrega por correo el prototipo navegable de facturación y cobranza, con PDF y acceso temporal a la versión web. El material usa datos ficticios y refleja el flujo levantado en Discovery: Jira → cotización BIND → prefactura → validación humana → CFDI → envío, además de cobranza por factura.
Balam responde que lo revisará internamente y compartirá comentarios. La retroalimentación queda pendiente; no se realizó la sesión en vivo prevista originalmente para ese día.
**Acción derivada:** mantener el entregable en validación y continuar únicamente con trabajo de Etapa 1 que no dependa de cambios visuales.
---
## 41 · Jul 13, 2026 · WhatsApp Erika ↔ Johann · continuidad de Etapa 1, sesión con Arturo y factura de 30 h
> Evidencia: `../fuentes/2026-07-13 a 2026-07-15 - WhatsApp - Seguimiento prototipo sesiones accesos.md`.
Johann comunica que, mientras Balam revisa el prototipo, avanzará localmente con base de datos, autenticación/roles y cliente de consulta de BIND. Erika explica que la CEO se encuentra fuera del país y que la diferencia de horario dificulta la validación inmediata.
Johann pide coordinar una sesión con Arturo para cerrar alta de clientes nuevos, tratamiento del fee en BIND y Excel de particularidades de envío. Erika contactará a Arturo y confirma que el Excel continúa en preparación.
Sobre la propuesta v1.2 y la factura inicial de 30 h, Erika confirma que recibió el documento. La validación administrativa sigue pendiente porque la CEO y Noé están fuera del país por trabajo; Erika revisará cómo obtener el visto bueno.
> **Lectura estratégica:** no hay rechazo comercial ni bloqueo técnico total. Johann mantiene momentum en local, pero la factura aún no debe emitirse sin confirmación y las definiciones de negocio se recorren.
---
## 42 · Jul 14, 2026 · WhatsApp Erika ↔ Johann · dos sesiones confirmadas para 2223 jul
> Evidencia: `../fuentes/2026-07-13 a 2026-07-15 - WhatsApp - Seguimiento prototipo sesiones accesos.md`.
Erika confirma dos espacios distintos:
1. **Miércoles 22-jul:** sesión de dudas y definiciones de la Etapa 1 con Arturo y participación solicitada de la CEO.
2. **Jueves 23-jul, 7:00 pm:** sesión de validación del prototipo de la Etapa 0. Erika envía la convocatoria.
**Temas para el 22-jul:** alta de cliente nuevo, registro de diferencias por fee, particularidades de envío y definición de alcance de la posible automatización Jira → cotización BIND.
---
## 43 · Jul 1415, 2026 · WhatsApp Erika ↔ Johann · ajuste de accesos y repositorio GitHub autorizado
> Evidencia: `../fuentes/2026-07-13 a 2026-07-15 - WhatsApp - Seguimiento prototipo sesiones accesos.md`.
Johann aclara que para la Etapa 1 requiere un repositorio privado de GitHub de Balam y, posteriormente, acceso acotado a Azure. Se mantiene la reprogramación: repositorio primero; Azure durante la semana del 21-jul; CI/CD y secretos el 24-jul.
El 15-jul Erika confirma que Noé autorizó la creación del repositorio y solicita el usuario de GitHub. Johann comparte `Johann-28` (`https://github.com/Johann-28`).
**Estado:** repositorio autorizado; falta recibir la invitación y verificar permisos de escritura. Azure aún no bloquea el desarrollo local.
---
## 44 · Jul 14, 2026 · WhatsApp Erika ↔ Johann · Excel de días vencidos condicionado a validación
> Evidencia: `../fuentes/2026-07-13 a 2026-07-15 - WhatsApp - Seguimiento prototipo sesiones accesos.md`.
Erika pregunta si todavía se requiere el Excel de control de cobranza con días vencidos. Johann aclara que, si Balam considera que la estructura del prototipo refleja correctamente su operación, ya no será necesario prepararlo; si detectan ajustes, seguirá siendo útil como referencia y puede contener datos ficticios.
**Impacto:** deja de ser un pendiente obligatorio y permanece condicionado a la retroalimentación del prototipo. Esto no sustituye el **Excel de particularidades de envío por cliente**, que Balam continúa preparando.
---
## 45 · Jul 15, 2026 · Gestión interna · se inicia control local de horas
Mientras Pedro habilita el flujo de reporte en Jira, Johann crea un control local en `../planeacion/Seguimiento-horas.csv` y su guía en `../planeacion/Seguimiento-horas.md`.
Se cargan 3.08 h de sesiones con duración comprobable y se reconstruye retrospectivamente el resto del esfuerzo por actividad hasta un corte de **30 h**: **22 h de Etapa 0** y **8 h de Etapa 1**. Las 26.92 h reconstruidas quedan etiquetadas como estimadas y deben validarse contra memoria/evidencia y Jira antes de facturar; no se derivan del porcentaje de avance.
**Acción:** Johann debe validar el desglose reconstruido, capturar diariamente en adelante y conciliar con Jira cuando Balam otorgue acceso al flujo.
---
## 46 · Jul 16, 2026 · WhatsApp · Erika ↔ Johann · invitación Git, procedimientos y solicitud de avance
> Evidencia: `../fuentes/2026-07-16 - WhatsApp - Erika invitacion Git procedimientos y avance Etapa1.md`.
Erika informa que Pedro envió el 15-jul la invitación al repositorio privado y pide validar el acceso. Johann confirma por WhatsApp que ya puede entrar; queda pendiente comprobar que también tenga permisos de escritura. Erika envía por correo los procedimientos de carga de facturas por cliente y Johann confirma recepción.
Erika solicita un corte del avance de la Etapa 1. Johann se compromete a prepararlo y compartirlo por WhatsApp. **Esa misma noche (8:40 pm) Johann envía por WhatsApp el Excel `Plan-actividades-avance-2026-07-16.xlsx`; Erika acusa recibo a las 8:44 pm ("Ntp, gracias").**
**Acciones derivadas:**
- [x] ~~Johann — validar permisos de escritura en el repositorio de Balam~~**Comprobado (16-jul):** push exitoso del scaffold inicial (backend .NET 10 + frontend Angular 21) al repo de Balam.
- [ ] Johann — revisar el correo y los procedimientos de carga de facturas; documentar reglas o diferencias frente al Discovery.
- [x] ~~Johann — enviar a Erika el corte de avance de Etapa 1~~**Hecho (16-jul, 8:40 pm):** Excel enviado por WhatsApp con acuse de Erika.
**Estado técnico comprobado al preparar el corte:** repositorio local limpio; solución .NET 10 y cliente BIND compilando; 13/13 pruebas del cliente BIND aprobadas; endpoints base `/health` y `/api/bind/status`. La base de datos, autenticación/roles, sincronización y endpoints de cartera siguen en construcción.
---
## 47 · Jul 19, 2026 · Gestión interna · demo del 18-jul no realizada; entorno local montado en la Mac
La **demo semanal planeada para el viernes 18-jul no ocurrió** (confirmado por Johann el 19-jul). Causa señalada: la validación del prototipo de la Etapa 0 sigue pendiente (quedó para el jue 23-jul) y eso ha retrasado el avance de la etapa. Los días 1718 jul no registran trabajo en `../planeacion/Seguimiento-horas.csv`. La próxima demo queda apuntada al **viernes 24-jul** (cierre de Etapa 1), donde también conviene comunicar que la capa de escritura se entrega en dry-run (ver nota en `../planeacion/Agenda-semana-2026-07-20.md`).
El mismo 19-jul se montó el entorno local en la Mac: repo del cliente clonado en `balam-plataforma/` (convención de `../planeacion/Plan-Etapa1.md`), SDK .NET 10 instalado en usuario, token cargado en user-secrets, API corriendo (`/health` y `/api/bind/status` verificados, modo ReadOnly, 13/13 pruebas verdes) y frontend Angular servido. Se creó la agenda por día de la semana 2024 jul (`../planeacion/Agenda-semana-2026-07-20.md`) y se actualizó el CSV de horas con los cortes del 16 y 19 jul.
---
## 48 · Jul 19, 2026 — noche · Desarrollo · B0+B1 completados (adelantados del lunes) + Scalar UI
Trabajo adelantado la noche del domingo siguiendo `../planeacion/Plan-Etapa1.md` al pie, con asistencia de IA (Claude Code). Tiempo real registrado en `../planeacion/Seguimiento-horas.csv` (~1.25 h de sesión — el plan estimaba 45.5 h manuales; el registro es de horas efectivamente trabajadas, conforme al contrato).
**B0 — Preparación local:** `docker-compose.yml` con Postgres 17 en puerto **5438** (54335437 ocupados por otros proyectos locales — difiere del 5433 que asume el plan en la otra máquina); cadena de conexión en `appsettings.Development.json`; `DesignTimeDbContextFactory`; referencia Infrastructure → Integrations.Bind; `dotnet-ef` 10.0.10.
**B1 — Fundación de datos:** entidades `Tenant`, `Client`, `Invoice` (modelo central: `Uuid` null ⇒ prefactura, `OpenBalance`, `CfdiPaymentTermRaw`, `PaidDetectedAtUtc`), `Quote`, `QuoteInvoiceLink` (ADR-003, con `JiraTicketKey` ADR-006), `InvoiceStatusChange` (ADR-004, fecha de detección), `WriteOperation` (pipeline Draft→DryRun→Confirmed, ADR-001); `TenantId` en `SyncCheckpoint`/`AuditLogEntry`; `BalamDbContext``IdentityDbContext` con llaves Guid; convenciones fechas BIND sin zona vs `*Utc` timestamptz y `decimal(18,2)`/`ExchangeRate(18,6)`; migración `Inicial` aplicada (16 tablas); `DbSeeder` idempotente verificado: tenant Balam (GUID fijo), 4 roles, 5 usuarios ficticios `*@balam.dev` (password en user-secrets `Seed:DefaultPassword`).
**Extra:** UI del OpenAPI con **Scalar** en `/scalar/v1` (solo Development). Estado verificado: API arriba con BD, 13/13 pruebas verdes, seed comprobado por consulta directa a Postgres. **Cambios sin commitear** en el repo del cliente — commit pendiente de Johann.
**Efecto en la agenda:** el lunes 20 queda libre para gestión + arrancar B2 (auth JWT + roles + bitácora) directamente.
---
## 49 · Jul 19, 2026 — noche · Desarrollo · B2 completado (adelantado del lunes): auth JWT + policies + bitácora
Continuación de la sesión nocturna asistida por IA (~0.5 h reales registradas en el CSV). Con esto el trabajo técnico planeado para el lunes 20 queda hecho; el lunes queda solo la gestión + arrancar B3 (sync de clientes).
**B2 conforme al plan:** `POST /api/auth/login` (Identity + JWT propio, sin `MapIdentityApi`, sin refresh en E1) y `GET /api/auth/me`; `Jwt:SigningKey` en user-secrets con fail-fast; policies nombradas (`PuedeVerCartera`, `PuedeDispararSync`, `PuedeVerBitacora`, `PuedeOperarEscritura`) con matriz provisional hasta la sesión del 22-jul; roles como constantes (`BalamRoles`); bitácora en dos piezas — `AuditMiddleware` (mutantes + 401/403) e `IAuditLogger` explícito — y `GET /api/audit` (Direccion/Administracion). Decisión aplicada del plan: **BD obligatoria con fail-fast**.
**Verificado end-to-end contra el API corriendo:** login fallido 401 (auditado una sola vez), login Finanzas 200 con token, `/me` 200, `/me` sin token 401, `/api/audit` con Finanzas 403 (auditado), con Dirección 200 mostrando toda la secuencia. 13/13 pruebas verdes.
Repo del cliente: 3 commits locales (`5631f55` Scalar, `6264ea3` B0+B1, `4617070` B2) — **push pendiente por decisión de Johann** (no se hace push sin su orden explícita).
---
## 50 · Jul 19, 2026 — noche · Desarrollo · B3 completado: sync de clientes CONTRA PRODUCCIÓN + hallazgo de datos
Cierre de la sesión nocturna (~0.5 h reales más). **Primer dato real de BIND viviendo en la plataforma:** 16 clientes sincronizados con detalle (días de crédito 0/30/45/60/90), checkpoint registrado y ciclo auditado en bitácora.
**Hallazgo de producción:** hay clientes con `LocationID`/`LoctaionID` **null** — caso que la validación del 6-jul no encontró. Se hicieron nullable todos los GUIDs de referencia de los modelos BIND (commit `fb0f066`); los IDs propios siguen no-nulos. Vale mencionarlo a Pedro junto con las 5 preguntas técnicas.
**B3 conforme al plan:** full-scan de lista + `SourceHash`, detalle solo nuevos/cambiados con tope por ciclo, normalización RFC/nombre, dedup por RFC exacto excluyendo genéricos — verificado en real: el único RFC repetido es `XEXX010101000` (2 clientes extranjeros) y quedó correctamente FUERA del dedup. Idempotencia comprobada: segundo run = 16 sin cambio, 1 sola petición. Consumo total del día: ~42 peticiones de 20,000.
`POST /api/sync/run` (Finanzas/Administración; Operaciones→403 verificado) y `GET /api/sync/status`. 13/13 pruebas verdes. Repo: **5 commits locales, push pendiente por decisión de Johann.**
**Estado de bloques al cierre del domingo: B0 ✅ · B1 ✅ · B2 ✅ · B3 ✅** — el lunes queda gestión + B4 (sync de facturas/cotizaciones + cartera, el bloque más grande) con margen de un día completo vs. el plan.
---
## 51 · Jul 21, 2026 · WhatsApp Erika ↔ Johann · estimación Jira→BIND comunicada (10 h) y alcance confirmado por Erika ⭐
Erika pidió en la mañana la estimación del cambio nuevo "para tenerla a la mano" antes de su sesión con directores. Secuencia clave:
1. **Johann comunicó: ~10 h de desarrollo, a confirmar el miércoles 22 en la sesión con Arturo** (primero cerrar reglas del flujo y validar la escritura de BIND). Quedó por escrito que "no estaba contemplado al inicio; es una mejora que surgió en el Discovery".
2. Erika retó con la §1.4 de la propuesta ("¿no es esto lo de las cotizaciones?"). Aclaración que quedó asentada: **crear cotizaciones manualmente desde la plataforma SÍ está en el MVP** (capa de escritura); lo nuevo es que **los tickets de Jira las generen automáticamente**. Erika encontró ella misma la §1.3 donde Jira dice "Fuera de alcance" y lo confirmó con 👍. Erika lo valida internamente con los directores.
3. Erika preguntó por 2 actividades vencidas en fechas del Excel (backend base y multi-tenant); Johann respondió "esas ya quedaron". Backend base ✅ real (B2); multi-tenant al ~80% — **hacer B6 (RLS real) de inmediato para que la afirmación quede cubierta.**
4. **Nuevo compromiso:** compartir las horas semanalmente por Excel mientras Pedro habilita Jira, **con entregable + actividad + horas de cada etapa** (formato pedido por Erika, lunes de corte).
---
## 52 · Jul 21, 2026 — noche · Desarrollo · B4 completado: sync de facturas/cotizaciones + cartera por moneda + SYNC HISTÓRICO ⭐
Sesión nocturna asistida por IA (~1 h real registrada en el CSV). **La plataforma ya tiene la cartera completa de producción viviendo en Postgres.**
**B4 conforme al plan:** `InvoiceStatusMapper` como **función pura en Domain con 13 pruebas xUnit** (precedencia Cancelada→Pagada→Emitida→Vencida→Vigente; "hoy" en hora MX vía `MexicoTime`; la frontera Emitida/Vigente se ajusta en minutos si la sesión del 22 la cambia). `InvoiceSyncService` con ventana única (delta por `Date` + re-barrido de abiertas viejas, solape 1 día, cursor que solo avanza al completar la pasada) y `QuoteSyncService` con sonda del filtro `CreationDate` + fallback a full-scan. Detección de pagos ADR-004: transición → `InvoiceStatusChanges` con fecha de DETECCIÓN; **facturas nuevas NO generan transición** (el histórico fotografía, no detecta). Campo nuevo `DetailSyncedAtUtc` (migración `DetalleSyncPendiente`) para tope de detalle 50/ciclo + backfill B5. Endpoints: `GET /api/cartera` (por moneda, jamás suma monedas; primer uso de `PuedeVerCartera`), `GET /api/invoices|clients|quotes`. Normalización PPD/PUE desde la etiqueta larga de BIND.
**Sync histórico corrido y verificado esta noche (jamás en demo):** 1,494 facturas y 43 cotizaciones, **detalle 1,494/1,494 (0 pendientes)**, idempotencia comprobada (2ª pasada = 100% sinCambio), `InvoiceStatusChanges` = 0 (cero pagos falsos), 24.5 min, ~1,700 peticiones (~8.5% de cuota; cierre del día ~1,750 de 20,000). **Cartera verificada BD ↔ endpoint exacto:** MXN 17 abiertas $1,568,772.32 · USD 92 abiertas $320,379.06.
**Hallazgos de producción:** (1) el filtro `CreationDate` de Quotes SÍ funciona (pendiente §10 de VALIDACION-API resuelto de facto); (2) ⚠️ **las 1,374 facturas con método de pago traen PUE — ninguna PPD** (120 con el campo vacío). Todo el histórico se factura "pago en una sola exhibición" aunque cobran a crédito 3090 días — preguntar a Arturo en la sesión del 22 (toca la regla PPD-default de la capa de escritura y el riesgo SAT que ellos mismos reportaron).
Commit `2e1ae82`. 26/26 pruebas verdes. **7 commits locales, push pendiente por decisión de Johann.**
---
## 53 · Jul 21, 2026 — noche · Desarrollo · B6: RLS real de Postgres (contractual) — código completo; verificación local pendiente de rol de app
Cierre de la sesión (~0.5 h real). **B6 conforme al plan:** `ITenantOwned` en las 8 entidades de negocio; `ICurrentTenantProvider` + `FixedTenantProvider` (ADR-005: tenant único); `TenantConnectionInterceptor` (`set_config('app.tenant_id',…)` en cada conexión, vías sync y async); filtros globales EF por entidad como segunda capa; migración `RlsPorTenant` a mano con `ENABLE/FORCE ROW LEVEL SECURITY` + política `tenant_isolation` (USING + WITH CHECK, fail-closed sin GUC) en las 8 tablas. Migración **aplicada** (catálogo confirma `relrowsecurity=t, relforcerowsecurity=t` en las 8); app end-to-end igual que antes (login, cartera, sync). Commit `fedb376`.
**⚠️ Verificación de aislamiento local INCOMPLETA:** la prueba psql devolvió filas sin GUC y con tenant ajeno porque `balam` (usuario bootstrap del contenedor) es **superuser con BYPASSRLS** — FORCE somete al *owner*, pero ningún candado somete a un superuser. El fix (pendiente de decisión de Johann, quedó en PENDIENTES): crear rol local `balam_app` (LOGIN, NOSUPERUSER, NOBYPASSRLS), transferirle la propiedad y apuntar la cadena de conexión de desarrollo a ese rol — replica cómo será Azure, donde el usuario de la app tampoco es superuser. Las políticas en sí son correctas; el hueco es del entorno local, no del código.
---
## 54 · Jul 22, 2026 — 7:00 AM · Llamada · Sesión de reglas Etapa 1: alta de clientes, fee bancario y flujo Jira ⭐
> Participan: Noe Rocha (sala de juntas), Arturo Rosas, Araceli (se suma ~min 21 para el tema del fee) y Johann. Erika no participó. Duración ~48 min. Transcripción: `../fuentes/2026-07-22 - Flujo para dar de alta clientes nuevos,_ Transcript.txt`. Agenda preparada en [`../planeacion/Sesion-Etapa1-2026-07-22.md`](../planeacion/Sesion-Etapa1-2026-07-22.md).
**Resumen:** Se resolvieron 3 de los temas de la agenda: **alta de cliente/proveedor en BIND** (demostrada en pantalla por Arturo), **tratamiento del fee bancario** (lo registra el despacho, no Balam) y **flujo Jira de facturación** (estatus, validaciones y confirmación de que Jira ya es parte del proceso). Quedaron fuera: particularidades de envío, la pregunta PUE/PPD y el cierre técnico (repo/Azure/Jira horas).
**1 · Alta de cliente/proveedor en BIND (ASIS, demostrado por Arturo):**
- **Mismo procedimiento** para clientes (módulo Ventas→Clientes) y proveedores (Compras→Proveedores). Botón **Agregar** → 2 pestañas: **Detalle** y **Direcciones**.
- **Detalle:** razón social, RFC, nombre comercial y categoría se toman de la **constancia de situación fiscal**; banco y CLABE del **estado de cuenta** del cliente. **Días y monto de crédito vienen de la negociación comercial** (no de un documento). Además: correo de comunicación, sucursal (solo existe matriz), teléfono, uso CFDI (mayoría "gastos en general", según constancia), régimen fiscal e **idioma de documentos** (p. ej. BICTEX → inglés). Clientes agregan: ventas esperadas, lista de precios, descuento pactado.
- **Direcciones:** país/estado/municipio/calle/CP, también de la constancia. Al guardar, BIND asigna un **ID interno consecutivo** (ej. 1016), exclusivo de la instancia de Balam.
- En **editar** se pueden adjuntar archivos: constancia, carátula bancaria, NDA, contrato marco — todo en un solo lugar.
- **El alta nace del área comercial:** cuando una propuesta pasa a firme, administración da de alta al cliente. Caso reciente: **Frisa**.
- **Extranjeros (ej. Acuntia):** documento legal/fiscal del país en lugar de constancia; BIND propone un **RFC genérico**; uso CFDI = **"sin efectos fiscales"**; la factura al extranjero genera **solo PDF, sin XML ni timbrado SAT** (se registra como gasto/ingreso extranjero sin obligaciones fiscales).
- No se hizo alta en vivo (producción, sin datos de prueba). **Arturo se comprometió a grabar y documentar** los procesos nuevos conforme ocurran (Frisa está por facturarse; hará manuales Word/PowerPoint).
**2 · Fee/comisión bancaria (con Araceli):**
- El fee **NO lo registra Balam: lo registra y deduce contablemente el despacho**, para que la factura quede saldada al 100% sin residual de deuda del cliente. Balam solo concilia estado de cuenta ↔ facturas pagadas.
- El fee **solo aplica a pagos internacionales que mueven dinero hacia México** (ej. Europa→Banorte; varía según banco emisor). Los **pagos nacionales cuadran a centavos**, sin fee. **BigTech** paga de banco americano a banco americano de Balam → sin fee.
- El monto del fee **no es predecible** (no hay reglas conocidas), pero **siempre viene marcado en el estado de cuenta** ("comisión", "IVA sobre comisión"). Por eso es crítico **pedir el estado de cuenta al cliente** — además Accent/Axios tiene **muchas facturas por el mismo monto** y sin estado de cuenta no se sabe cuál pagaron.
- **Regla para la plataforma:** el agente de conciliación solo debe **identificar la diferencia como fee bancario**; quién autoriza saldar la factura con diferencia es **el despacho**, a nivel contable. Hoy el caso vivo es Acuntia.
**3 · Jira (flujo de facturación) — confirmado que SÍ entra en la fórmula:**
- Noe reconoció explícitamente que el alcance inicial decía "sin Jira" pero **el proceso interno evolucionó y hoy todo pasa por Jira**; la integración se pone sobre la mesa como ajuste.
- **Space "Facturación"** separado (hay otros: administración general, GEDEX, RH), con un solo request type hoy (facturación adicional/recurrente) — el universo de tickets de facturación está cerrado y filtrable.
- **Flujo de estatus del ticket:** inicia → abierto → **proceso de facturación** (confirmar monto, cliente dado de alta, constancia vigente, cuenta bancaria) → **validación** (nacional: adjuntar **PDF + XML obligatorios**; internacional: **solo PDF**) → facturado → **resuelto**. El estatus que confirma facturación válida es **"resuelto"** (el anterior solo es validación en curso). Las validaciones nacieron de desaciertos operativos reales ("ya facturé" sin evidencia).
- **Facturación recurrente:** ~30 facturas/mes salen de un flujo recurrente por contratos establecidos — es **proceso de Balam ejecutado en BIND**, no capacidad nativa de BIND, y siempre con intervención humana (los montos pueden variar mes a mes). **Pedirá sesión aparte con Pedro** para entenderlo.
- **Forecast contractual a largo plazo:** BIND solo proyecta sobre lo ya facturado (por plazo de pago); Noe quisiera a futuro proyección por contrato — **explícitamente NO es para ahora**.
**4 · Escritura en BIND / prueba Jira→cotización:** Johann planteó probar el flujo ticket Jira → cotización BIND (cotización→prefactura→factura). Noe accedió a explorarlo pero con advertencia fuerte: **no hay ambiente de pruebas, es producción directa** — "muy, muy medida la prueba… para no hacernos harakiri". La escritura será acordada y controlada llegado el momento.
**Acuerdos / próximos pasos que anotó Noe:**
- [ ] Balam (Arturo/Pedro) — **enviar a Johann el diagrama del flujo Jira** en tamaño legible (el screenshot se veía ilegible en la llamada).
- [ ] Balam (Erika coordina) — **sesión con Pedro (+Arturo)** para: **API de Jira** (explorar conexión), facturación **recurrente** y facturas automáticas vs manuales.
- Confirmado: **mañana jueves 23-jul, sesión de validación del prototipo**.
> **Lectura estratégica:**
> - **Jira→BIND avanza:** Noe aceptó en voz alta que Jira ya es parte del proceso y encaminó API + sesión con Pedro — coherente con la estimación de ~10 h comunicada a Erika el 21-jul ([#51](REGISTRO.md)). El disparador de facturación es el estatus **"resuelto"**; para crear cotizaciones el candidato natural es un estatus previo (a confirmar con Pedro en la sesión de API).
> - **El fee simplifica el MVP de conciliación:** la plataforma NO registra ajustes contables — solo detecta y etiqueta la diferencia como fee bancario en pagos internacionales. El asiento es del despacho. Esto acota el alcance justo donde la agenda temía ambigüedad.
> - **Alta de clientes:** quedó mapeado el ASIS completo, pero **no se decidió** si la plataforma solo detecta clientes faltantes o también los crea — la pregunta del MVP sigue abierta y toca la estimación Jira→BIND ([#51](REGISTRO.md)): un ticket de un cliente inexistente en BIND cruza ambas piezas.
> - **No se tocaron:** la pregunta **PUE vs PPD** (1,374 facturas históricas todas PUE, [#52](REGISTRO.md)) — reintentarla el 23-jul o con Pedro—, las **particularidades de envío** (Excel sigue pendiente de Ara/Arturo) y el cierre técnico (Azure/Jira horas).
> - **Factura extranjera sin XML** confirma el diseño del prototipo (PDF-only para internacionales) y explica por qué la validación de Jira solo exige PDF en ese ramal.
---
## 55 · Jul 24, 2026 — 11:00 AM · Llamada · Validación del prototipo Etapa 0 — APROBADO (queda 1 definición de proceso) ⭐
> Participan: Erika Chávez (abre), Johann (presenta), Noe Rocha, Araceli Sánchez, Arturo Rosas. Duración ~1 h 4 min. La sesión estaba agendada para el **jueves 23-jul 7 am** pero se corrió al **viernes 24-jul 7 am** porque Araceli (dueña del proceso) tuvo un tema personal (reagenda documentada en [#57](REGISTRO.md)). Transcripción: `../fuentes/2026 - 07 - 24 - Validación de prototipo etapa 0- proyec_ Transcript.txt`. Guion usado: [`../planeacion/Guion-validacion-prototipo-2026-07-23.md`](../planeacion/Guion-validacion-prototipo-2026-07-23.md).
**Veredicto: Etapa 0 validada.** Johann recorrió el PDF y luego el prototipo navegable (URL). Ara: *"Johann nos captó absolutamente todo lo indispensable y más… de momento no le pondría nada"*, *"Me encantó", "Sí a todo"*. Arturo: *"yo no le pondría nada más… esto es lo mínimo que necesitamos"*. Ambos aprobaron el MVP tal cual. **Queda pendiente UNA sola cosa del lado de Balam: redefinir el flujo de facturación en Jira** (ver abajo) antes de volver con Johann para hacer el MVP productivo. Erika confirmó que esto **no bloquea** a Johann, que ya está en Etapa 1.
**El único bloqueo real — definición de proceso (no de sistema):** hoy el CIS de Jira exige que la factura se haga **antes** de cerrar el ticket, es decir el proceso de facturación ya no arrancaría desde el sistema. Hay que decidir si la ejecución (prefactura) se **dispara desde la plataforma** (lo deseable, para que el sistema optimice) o se sigue haciendo antes y solo se presenta al sistema. **Arturo pidió explícitamente que sea PREFACTURA, no timbrado automático:** validación previa (nacional vs extranjera, montos, datos fiscales) para evitar cancelaciones que el SAT observa; *"para ir monitoreando la eficiencia de la IA. Tal vez en algún futuro daremos independencia completa"*. **Ara sale de viaje mié/jue/vie; propuso el martes 28-jul para esa sesión; Erika coordina.** Es prerrequisito para que Johann conecte el frontend a la escritura.
**Decisiones y aclaraciones que quedaron asentadas:**
1. **Cotización SIEMPRE, sin excepciones (Ara).** Incluso las **recurrentes** (contrato AXIANS 34 años) deben nacer de una cotización → prefactura/factura. Es un punto de control para cazar cambios (sueldos, viáticos, ajustes) y errores. *"El esfuerzo es el mismo"*: la cotización vive en BIND y se convierte a prefactura/factura con un clic. Noe lo cerró como **3 candados: cotización → prefactura → aprobación humana → timbrado.**
2. **Nada de agente de IA en este MVP** (Noe, muy vocal, lo repitió 3 veces): esto es **reglas de negocio + procesos + integración de sistemas** para homologar pantallas, no LLM. La IA llega después; el candidato claro para agente es **conciliación** (hoy 100% manual). Primero la base de proceso, *"si le metemos IA de inicio va a ser una fiesta"*. Johann alineado: el MVP asienta el proceso para montar los modelos encima.
3. **Roles:** la plataforma ya los soporta; por ahora Ara y Arturo ven todo, se acotan cuando entre un analista.
4. **Dashboard:** las 4 tarjetas son propuesta, todo customizable. *"Qué necesita atención"* se alimentaría de Jira + estatus de facturación. Posible acople con el Power BI de aging de Pedro (no duplicar reporteo).
5. **Fuente única = BIND (Vine) o Jira.** No hay fuente alterna. Cartera vencida sale de BIND; lo que no esté en BIND requeriría carga/capa manual.
6. **Un ticket = una factura (hoy).** Caso ACUNTIA/Accions: un solo ticket con un Excel de 4048 facturas. Queda **abierto** si se maneja como ticket-por-factura o un ticket con múltiples hijos (definición de proceso, va con el punto del bloqueo).
7. **Todo nace en Jira — política de empresa:** *"Lo que no está en JIRA no se procesa."* Ni correo ni mensaje; incluso los correos se reenvían a una dirección que auto-crea el ticket.
8. **Envío con particularidades por cliente:** validado y les gustó (CEMEX bloqueado por faltar Excel de horas; ACUNTIA = zip con PDF+XML+estado de cuenta). El **módulo de configuración** de reglas de envío queda **cerrado/hardcodeado al inicio**; si cambian reglas, se cobra como horas de servicio. No se desarrolla ahora.
9. **NAFINSA / cadenas productivas (solo CEMEX):** facturas ya *programadas para pago* (p. ej. cae 24-sep, 120 días) que **no existen como estatus en BIND**. Quieren una **capa/pantalla extra "programado para pago"** para planeación financiera (Arturo: *"la cerecita del pastel"*). Idea de Ara: **ticket Jira automático cada 15 días** para revisar el portal Nafinsa, adjuntar Excel/pantallazos y alimentar cuentas por cobrar, haciendo match por folio. A evaluar con Johann.
10. **Fee:** tolerancia configurable por cliente (% o fijo); se muestra como *"pagada pero con tolerancia"*. (Consistente con [#54](REGISTRO.md): el asiento contable es del despacho, la plataforma solo detecta/etiqueta.)
11. **Recordatorios internos en el MVP:** D+1 → Arturo, D+15 → Araceli. Los **correos al cliente (D+5, D+30) NO son alcance** ("no está definida la regla"). Excepciones de seguimiento por cliente contempladas.
12. **Bitácora/auditoría:** *"Me encanta, sí a todo."*
**Observaciones que anotó Noe sobre el prototipo:** (a) un ticket rotulado "facturación nacional" era extranjera → pedía XML+PDF cuando extranjera es solo PDF (ajuste menor); (b) los estatus del prototipo son placeholders previos a explorar Jira ("listo para facturar" ≈ "facturado" en Jira real) y se adaptarán al flujo que Balam defina.
**Cierre y próximos pasos:**
- Balam hace **teamback** para separar *must* vs *nice-to-have* y define el flujo de facturación/prefacturación (**sesión martes 28-jul, Erika coordina**).
- Antes del **go-live** habrá una **prueba muy observada de prefacturación** (primera escritura real sobre BIND), paso a paso y validada.
- **Sesión con Pedro para el API de Jira** queda encaminada (se materializó el 27-jul, [#56](REGISTRO.md)).
- Johann: **montar el frontend**, conectarlo al backend ya construido (cliente BIND, auth, multi-tenant, BD) y hacer las pruebas.
> **Lectura estratégica:**
> - **Etapa 0 cerrada en la práctica** con validación entusiasta de los dueños del proceso (Ara y Arturo) y respaldo de Noe. El entregable de Etapa 0 quedó aprobado; el único hilo suelto es una **definición de proceso de Balam**, no una carencia del prototipo.
> - **"Cotización siempre" es una decisión firme** que simplifica la capa de escritura (B7): un solo camino cotización→prefactura→aprobación→timbre, sin ramas de excepción para recurrentes. Elimina ambigüedad que la agenda temía.
> - **PUE/PPD no se retomó** en esta sesión — sigue abierta desde [#52](REGISTRO.md) (1,374 facturas históricas todas PUE). Reintentarla con Arturo en la sesión del 28-jul o con el flujo Jira.
> - **Dos capacidades nuevas asomaron fuera del MVP core:** "programado para pago"/planeación financiera (Nafinsa) y el espacio "comercial" en Jira para generar cotizaciones. Ambas son candidatas a ampliación (horas extra), útiles para el pipeline comercial, pero **no deben inflar el MVP** — es justo lo que Noe pidió filtrar con el teamback.
> - **La prueba observada de prefacturación es el hito de riesgo** antes del go-live: es la primera escritura real sobre producción. Los candados acordados (dry-run, confirmación humana por factura, feature flag) son el seguro.
---
## 56 · Jul 27, 2026 — mañana · Llamada · Sesión API de Jira con Pedro: token comprometido y bandeja "Facturación" (FAC) identificada ⭐
> Participan: Noe Rocha, Erika Chávez, Pedro Ayala (TI, dueño de Jira), Johann. Duración ~12 min. Transcripción: `../fuentes/2026-07-27 - API de conexión con JIRA Transcript.txt`. Es el Discovery de API que quedó encaminado el 22-jul ([#54](REGISTRO.md)) y ratificado el 24-jul ([#55](REGISTRO.md)).
**Objetivo (Noe):** el Discovery mostró que buena parte del proceso de facturación llega por Jira, conectividad que originalmente no se contempló y que ahora **sí será necesaria**. Pedro explica cómo se conecta hoy vía API.
**Lo que confirmó Pedro:**
- Usa el API de Jira para varios tableros de TI (limpieza de usuarios, aprobadores, conectores, SLAs). Funciones: crear y consultar actividades/tickets, aprobaciones, documentos adjuntos, cambio de estatus. **Es de lectura Y escritura — todo accionable** ("cualquier creación que se haría manual se puede hacer por API"). Cubre el CRUD que Johann necesita.
- **Token comprometido:** Pedro genera una API key llamada **"PAF" (Plataforma de Automatización Financiera)**, **expiración a 1 año — 27-jul-2027**. La envía **por correo en TXT** junto con la **documentación de desarrolladores de Atlassian** (informativa). Ya la tenía lista al cierre de la llamada.
- **Límites de consumo:** a diferencia de BIND (20K/día), Pedro cree que Jira **no tiene tope por día**; lo investigará en Atlassian y lo revisa con Johann. Noe quiere saber el límite de transacciones por escritura/consulta para planear la operación.
- Los tokens se generan desde la cuenta de Pedro, diferenciados por nombre; buena práctica rotarlos.
**Identificación de dónde consultar (aclaración importante):** no es "tablero" (eso es Power BI) sino el **Space** de Jira. Los tickets de facturación viven en la bandeja/space **"Facturación", con llave `FAC-`** + número. Otras bandejas: Administración General (AG), ITS (DITCM), Recursos Humanos (RH), Facturación (FAC), HD. **El API es global** (extrae de todas), pero la que importa es **Facturación**, que funciona como **bandeja "padre"**: procesos que se cierran en RH o Administración General **caen en Facturación**. Este es el insumo que Johann pidió el 24-jul para saber de dónde extraer los tickets.
**Próximos pasos acordados:**
- **Pedro** → enviar por correo: token TXT (PAF) + documentación Atlassian; investigar límites de consumo. → **CUMPLIDO el mismo día (ver seguimiento).**
- **Johann** → revisar la documentación de Jira/Atlassian; con la key, integrar la consulta al prototipo. Construir un **script de consulta** y también scripts de **creación/edición/eliminación** sobre un registro de prueba. Noe: no existe un CRUD previo por API; cuando llegue el momento se hace una **prueba en vivo** de creación. **Johann es el checkpoint** — avisa cuando necesite prueba o tenga dudas.
**Seguimiento — correo de Pedro del mismo día (27-jul, 7:40 am; CC Noe y Erika):** `../fuentes/2026-07-27 - Correo - Pedro medicion de consumo API Jira y token.md`. Johann acusó recibo ("Enterado, muchas gracias Pedro! Saludos").
- **No hay límite de volumen** ("X llamadas al mes") ni costo extra de licencia por usar la API. Hay **3 límites de velocidad en paralelo**, cualquiera devuelve **HTTP 429** (`RateLimit-Reason` indica cuál):
1. **Cuota por puntos/hora:** 1 punto base + 1 por objeto de dominio (issues, proyectos) o 2 por objeto de identidad (usuarios, grupos, roles); **las escrituras solo cobran el punto base**. Bolsa por defecto **65,000 puntos/hora**.
2. **Burst por segundo:** 100 req/s GET y POST, 50 PUT y DELETE, bucket por endpoint y por tenant. Consulta de clientes de service desk topada a **5/s**.
3. **Por issue en escrituras:** 20 ops/2 s y 100/30 s sobre un mismo ticket.
- **No existe dashboard de consumo** (limitante de Atlassian): consola de desarrolladores solo muestra el tier de apps propias; el detalle por token exige **Atlassian Guard Premium** (licencia aparte); las apps de Marketplace estiman por muestreo. **Única fuente confiable = headers de respuesta:** `X-RateLimit-Limit/Remaining/NearLimit` (NearLimit se activa con <20% de capacidad) y en 429 además `X-RateLimit-Reset`, `Retry-After`, `RateLimit-Reason`.
- **Token entregado** vía enlace de Google Drive (carpeta compartida). ⚠️ Tratar como credencial: mover a user-secrets/Key Vault, no dejar en texto plano.
> **Lectura estratégica:**
> - **Desbloqueo clave para B7/Jira→BIND:** con token de escritura a 1 año y la bandeja FAC identificada, se habilita tanto la lectura de tickets como la automatización Jira→cotización BIND estimada en ~10 h ([#51](REGISTRO.md)). El API confirmado como read+write despeja el mayor riesgo de la integración.
> - **"Facturación como bandeja padre"** es un dato de arquitectura relevante: consultar solo FAC puede no bastar si el disparador nace en RH/AG y cae en FAC — validar en las pruebas si conviene escuchar la bandeja padre o rastrear los procesos origen.
> - **Límite de consumo resuelto (correo 27-jul):** no hay tope mensual; 3 límites de velocidad (puntos 65k/h, burst/s, por-issue en escrituras) sin dashboard nativo → el sync debe **autorregularse leyendo los headers `X-RateLimit-*`** (pausar en NearLimit, respetar `Retry-After` en 429). **Las escrituras son baratas en puntos** (solo el base), lo que favorece la capa de escritura frente a las consultas de identidad (2 puntos c/u).
> - **Pendiente de proceso aún abierto:** qué estatus de Jira dispara qué (facturación vs cotización) sigue amarrado a la definición del martes 28-jul ([#55](REGISTRO.md)) — la conectividad ya está, la regla de negocio no.
---
## 57 · Jul 2127, 2026 · WhatsApp Erika ↔ Johann · coordinación de sesiones, envío del flujo de facturación y reagenda 23→24 jul
> Hilo de coordinación que **complementa** la parte de fondo del 21-jul ([#51](REGISTRO.md)) y enlaza la sesión de reglas del 22-jul ([#54](REGISTRO.md)), la validación del 24-jul ([#55](REGISTRO.md)) y la sesión de API de Jira del 27-jul ([#56](REGISTRO.md)). Transcripción completa (con imágenes inferidas): `../fuentes/2026-07-21 a 2026-07-27 - WhatsApp - Erika coordinacion sesiones validacion y API Jira.md`.
**21-jul (tarde):** Johann propuso compartir las horas por Excel mientras se habilita Jira; Erika pidió el formato **entregable + actividad + horas por etapa**. Erika cuestionó si lo de las cotizaciones ya estaba (📷 captura) → Johann aclaró que **crear cotizaciones sí está en el MVP** y que lo nuevo (Jira genere la cotización en BIND automáticamente) requeriría acceso técnico a Jira + escritura controlada en BIND. Erika confirmó por su cuenta que Jira dice **"fuera de alcance"**.
**22-jul:** Erika se disculpó por **no asistir a la sesión de reglas** de esa mañana ([#54]; avisó a los ingenieros para que la tomaran igual). Preguntó **dos veces si se ajustará la propuesta** por el cambio de la integración Jira → **compromiso de Johann: enviar el conteo de horas + la propuesta ajustada "entre hoy y mañana" (para el 23-jul).** Erika propuso la **sesión de API de Jira** con Noe y Pedro y confirmó que **ya envió por correo el flujo de facturación de Jira** (2:26 pm).
**23-jul (reagenda):** por un tema personal de **Araceli** (dueña del proceso), la **validación del prototipo** se movió de jueves 23-jul 7 am a **viernes 24-jul 7 am**. La **sesión de API de Jira** se movió de viernes 24-jul 7 am → 7 pm → finalmente **lunes 27-jul 7 am** por disponibilidad de Pedro. Erika preguntó si "esta actividad se acabó ayer" (📷 captura del plan) → Johann: sí, **falta la prueba de escritura en BIND** pero ya está.
**24-jul:** intercambio de arranque; se conectan a la sesión de validación ([#55]).
**27-jul (mañana):** Erika pidió **los avances de la Etapa 1**; Johann preguntó si **ya existe el Jira del proyecto** — justo antes de la sesión de API donde Pedro compromete el token PAF ([#56]).
**Pendientes que deja el hilo:**
- [ ] Johann — **enviar conteo de horas (Excel: entregable + actividad + horas por etapa) + propuesta ajustada** por la integración Jira→BIND. ⚠️ Comprometido para el 23-jul — **verificar si ya se envió.**
- [ ] Johann — **entregar avances de Etapa 1** solicitados el 27-jul.
- [ ] Conservar el **correo del flujo de facturación de Jira** (Erika, 22-jul) como evidencia/insumo.
> **Nota de imágenes:** las capturas no vienen en el volcado; se infieren tres adjuntos por los deícticos ("esto", "esta actividad") — cotizaciones (21-jul 12:58), "fuera de alcance" (21-jul 1:03, confianza media) y actividad del plan (23-jul 11:29). Detalle en el archivo de `fuentes`.
---
## 58 · Jul 2728, 2026 · WhatsApp Erika ↔ Johann · avance de Etapa 1 entregado, Excel de horas para FACTURACIÓN y Jira aún sin licencia ⭐
> Continuación de [#57](REGISTRO.md). Registrado a partir de capturas de pantalla del hilo (4 imágenes). Cubre el envío del avance del 27-jul y los pedidos de Erika del 27 (tarde) y 28 (mañana).
**27-jul, mañana — avance de Etapa 1 entregado por mensaje:** Erika pidió los avances de Etapa 1 (📷 captura del plan, 7:11 am). Johann preguntó si ya existe **un Jira para el seguimiento de este proyecto** —es decir, dónde llevar sus actividades y horas, no la instancia a integrar— (7:14 am) → **respuesta de Erika (7:54 am): "aún estamos viendo lo de alguna licencia... pero estamos viendo una segunda opción y no Jira precisamente".** Johann ofreció trabajar en un Excel compartido; Erika contestó que le comentó a Pedro que **pudiera ser un Drive para subir la documentación, pero están en espera de la validación** (8:57 am).
> ⚠️ **Precisión importante:** este intercambio es sobre la **herramienta de gestión del proyecto** (dónde se registran actividades y horas de Johann), NO sobre la integración técnica. El Jira a integrar es la **instancia productiva de TI que administra Pedro** —bandeja FAC, token PAF a 1 año, API read+write confirmada ([#56](REGISTRO.md))— y ese no está en duda. Consecuencia práctica: **mientras no haya herramienta de gestión, el Excel de horas de Johann ES el sistema de seguimiento del proyecto**, lo que explica la insistencia de Erika en el desglose por etapa.
Johann envió el **avance por actividad en texto** (8:12 am), con 👍 de Erika y "gracias" (8:58 am):
> ✅ Sincronización de clientes — hecho y verificado · ✅ Sincronización de facturas/cotizaciones — hecho, 1,494 facturas cuadran · ✅ Modelo + migraciones + datos de prueba — hecho · ⏸️ Capa de escritura — en la junta del viernes comentaron que iban a definir el flujo de facturación; en cuanto quede, la implemento (Balam) · ⏳ Config. Azure (+ staging) — espera el acceso a Azure de Pedro/Noé (Balam) · ⏳ CI/CD + secretos — depende de Azure (Balam)
**27-jul, tarde — la fila de escritura y la sesión del proceso:** Erika preguntó (3:35 pm) si la capa de escritura *"es la que está pendiente de lo que se mencionó el viernes de que validarían el flujo"* → Johann confirmó. Erika: **"es que lo tengo al 100%"** (3:40 pm) → **Johann corrigió: "lo volví a marcar como pendiente porque se iba a validar el proceso"** y preguntó cuándo podrían tener la junta revisando el proceso validado (3:443:45 pm). Erika: le comentó a Arturo, y como **Ara sale de viaje**, mañana en la oficina ve cuándo **revisarlo internamente y después pasarlo con Johann**; queda en avisar (3:49 pm). ⚠️ **La sesión del 28-jul no quedó confirmada — se movió a revisión interna de Balam primero.**
**27-jul, 4:59 pm — pedido formal de horas:** *"johan un favor, me puedes pasar en un excel tus horas que llevas de cada etapa por favor"***Johann envió `Avance-Balam-2026-07-27.xlsx` a las 6:45 pm** (versión simplificada). Johann ofreció además pasar un Excel para las siguientes etapas; Erika (7:57 pm): *"Y las ya completas más que nada para ver cuántas son"*.
**28-jul, mañana — el propósito del Excel y dos pendientes:**
1. **(8:36 am) ⭐ "es para llevar el conteo de horas de cada etapa sobre todo para la FACTURACIÓN correspondiente de la misma."** → El Excel de horas es el insumo de facturación, no solo seguimiento.
2. **(9:12 am) "johann adicional, ¿pasaste la propuesta con lo adicional de JIRA que no estaba contemplado?"** → Johann (10:58 am): **"Aún no la comparto, te la paso a la brevedad."** ⚠️ Es el compromiso que viene arrastrándose desde el 22-jul ([#57](REGISTRO.md)).
3. **(9:27 am)** Sobre Azure: Johann preguntó si el acceso lo iba a entregar Noé o Pedro → Erika: **"Sip"** + *"deja pregunto"* (11:01 am). Johann pidió contexto de qué se requiere específicamente de Azure (11:19 am).
**Lecturas clave:**
> - **El Excel de horas es documento de facturación** (dicho por Erika, 28-jul 8:36 am). Cambia su naturaleza: ya no es reporte de avance, es sustento de cobro. Refuerza que las 41.58 h estén validadas y trazables.
> - **Erika creía la capa de escritura al 100%** y Johann la corrigió a pendiente. Buena decisión: si se hubiera dejado al 100%, la definición del proceso habría reabierto una actividad cerrada. Valida el criterio de reportar 40% y no más.
> - **Sin herramienta de gestión para el proyecto** (licencia en revisión; Erika evalúa una alternativa a Jira para ese fin). **No afecta la integración técnica** —esa va contra la instancia de TI de Pedro, ya disponible—, pero sí significa que **el Excel de horas de Johann es el registro oficial de seguimiento** y el insumo de facturación. Mantenerlo trazable y al día no es opcional.
> - **La propuesta ajustada por Jira sigue sin enviarse** (comprometida el 22-jul, re-preguntada el 28-jul). Es el pendiente comercial más viejo del hilo y ahora Erika lo pide por segunda vez.
> - **La sesión del flujo de facturación no está agendada:** Balam la revisa internamente primero (Ara de viaje). El desbloqueo de B7 se corre de fecha.
**Pendientes que deja el hilo:**
- [ ] ⚠️🔥 Johann — **enviar la propuesta/adenda ajustada por la integración Jira→BIND** (comprometida 22-jul, re-preguntada 28-jul 9:12 am). Estimación ya comunicada: ~10 h ([#51](REGISTRO.md)).
- [ ] Johann — **enviar el Excel de horas de las etapas siguientes** (2, 3) que Erika pidió el 27-jul 6:46 pm ("las ya completas más que nada para ver cuántas son").
- [ ] Balam/Erika — **avisar fecha de la sesión del flujo de facturación** tras su revisión interna. Desbloquea B7.
- [ ] Balam/Erika — **definir la herramienta de gestión del proyecto** (licencia en revisión). Mientras no exista, el Excel de Johann es el registro oficial.
- [ ] Balam/Pedro/Noé — **entregar el acceso a Azure**; Erika iba a preguntar (28-jul 11:01 am). Johann pidió el contexto de lo que se requiere.
---
## 59 · Jul 30 Ago 10, 2026 · Correo · Balam define el flujo Jira→BIND: disparador, campos y prueba acompañada ⭐🔥
> Hilo `RV: Seguimiento: medición de consumo API de Jira y accesos` (fuente original conservada localmente; no versionada porque contiene cabeceras y adjuntos completos del correo). Continúa [#56](REGISTRO.md). Es **la definición del flujo de facturación que estaba bloqueando B7 desde el 24-jul** ([#55](REGISTRO.md), [#58](REGISTRO.md)).
**Cronología (8 días de latencia):**
| Fecha | Movimiento |
|---|---|
| 30-jul 10:2811:44 am | Pedro confirma su correo, **regenera el token** y comparte la URL `https://balam-jsm-temp.atlassian.net`. Cierra el 401 del 29-jul. |
| 30-jul 1:07 pm | **Johann pregunta las 4 definiciones** (disparador, alcance de request types, fuente de monto/conceptos, y FACTEST vs prueba acompañada) + reporta el hallazgo de que el monto no está en campos estructurados. |
| 3-ago 4:58 pm | Noé **escala internamente** a Araceli y Arturo (CC Pedro), reconociendo el cambio de propósito: *"el flujo de JIRA tenía un propósito claro, validar la actividad y la evidencia, ahora cambiar a ejecutar y automatizar actividades con el desarrollo"*. Entra **Araceli Sánchez** al hilo. |
| 3-ago 4:59 pm | Noé a Johann: *"Estamos definiendo para darte respuesta mañana mismo"*. |
| 4-ago 12:15 pm | **Arturo responde en verde** sobre los tres puntos + adjunta captura del formulario y del filtro de request types. |
| 7-ago 5:34 pm | Noé reenvía a Johann y **contesta la cuarta**: prueba acompañada. |
**Las 4 definiciones, cerradas:**
1.**La cotización BIND se genera al entrar a `En proceso de facturación`.** Y: *"por el momento todo se tramitará como facturación normal, hasta el explorar el módulo de proyectos en BIND"***el caso de facturación recurrente queda fuera de alcance por ahora.**
2.**Se observan TODOS los request types** de la bandeja de facturación, no solo `Facturación adicional`.
3.**Monto y conceptos van como campos de Jira**, no del adjunto. Noé: *"resta rapidez, pero garantiza consistencia de datos"*. Arturo: *"de acuerdo, deben ser los campos de JIRA (omitir el campo recurrencia)"*.
4.**No habrá proyecto `FACTEST`:** *"Preferimos una prueba acompañada sobre un ticket"* (Noé).
**Verificación por API el 10-ago (solo lectura; detalle en `../planeacion/Investigacion-API-Jira.md`):**
-**El acuerdo ya está implementado en Jira:** `Monto sin IVA` existe como `customfield_11556` (number/float, obligatorio) en el request type 83. Desapareció `Periodo de Incidencias`.
- 🔴 **Pero solo 2 de 69 tickets lo tienen poblado**`FAC-100` y `FAC-101`, ambos creados el **4-ago**, el mismo día de la respuesta de Arturo. Sin histórico contra el cual validar el mapeo.
- 🔴 **`conceptos`/partidas NO existe como campo en todo el sitio.** El catálogo completo solo tiene `Monto sin IVA` (11556), `Monto con IVA` (11522, sin usar en el formulario) y `Total forms` (de JSM). **El acuerdo resolvió el monto pero no los conceptos.**
- 🔴 **"Todos los request types" incluye tickets sin request type:** el filtro de la bandeja muestra 6 opciones (las 4 del portal + `Empty` + `Emailed request`). **10 de 69 tickets no tienen request type ni un solo campo estructurado**; nacen de `Automation for Jira` desde HH/SA/IN/RH, con los datos codificados en el `summary`. **No son ruido:** `FAC-91` es uno de ellos y está vivo en `En validación nacional` (`[FACTURA COMPLETA - Staff Augmentation] Axians — RH-36`).
- 🔴 **El estatus disparador dura minutos.** `FAC-100` estuvo **2m44s** en `En proceso de facturación` (11:51:25 → 11:54:09 del 5-ago) y 25 min de punta a punta. Solo 1 de 69 tickets está parado ahí hoy. **Un poller que consulte el estatus actual se pierde la mayoría de los disparos → la detección por changelog pasa de preferencia a requisito.**
-**Hallazgo nuevo: el workflow tiene aprobaciones de JSM**, con **Araceli Sánchez** como aprobadora en las ramas de validación nacional/extranjera (`customfield_10003`/`10025`). El paso a `Facturado` es una aprobación formal, no una transición simple. La plataforma no debe aprobar nunca.
-`FAC-100` cierra con `status = Facturado` **y** `resolution = Done` consistentes (resuelve la trampa documentada el 30-jul).
- ✅ Headers de rate limit confirmados: `X-RateLimit-Limit: 350`, `X-RateLimit-Remaining: 348`, más los estándar `RateLimit-Policy`/`RateLimit`. **El límite observado es 350, no los 100/s que mencionó Pedro** → leer el header, no hardcodear.
- ✅ El origen es **creación por Automation, no move entre proyectos**: sin cambios de `project`/`key` en los changelogs, con `issuelinks` al ticket origen. **Escuchar FAC basta.**
- ⚠️ `Facturación recurrente` sigue siendo obligatorio y se está llenando (`FAC-100`: `Si`, periodo `12`) pese al acuerdo de omitirlo.
- ⚠️ `Nombre del Cliente` es **ADF**, no string, y **no trae RFC** — la llave de match contra BIND queda en el nombre escrito a mano.
- ⚠️ **ACUNTIA ya tiene caso real:** `FAC-100` es `Julio/CONSULTORIA Y SERVICIOS (Eduardo Fiallo CEMEXUSA)/ACUNTIA`, `Helmstone`, USD, 45 días, **un solo `Monto sin IVA` de 7,594.00** — para el ticket que históricamente representa 4048 facturas ([#55](REGISTRO.md) punto 6).
> **Lectura estratégica:**
> - **B7 queda desbloqueado en su mayor parte.** El disparador está definido y el campo de monto ya existe: se puede implementar lectura, detección por changelog, parser de ADF y mapeo. **Lo único que sigue bloqueado es el armado final de la cotización**, por la definición de conceptos.
> - **El acuerdo del 4-ago resolvió el monto y olvidó los conceptos.** Es el hueco más caro del hilo: sin partidas, la cotización BIND sale de una sola línea. Puede ser aceptable, pero tiene que ser una decisión explícita de Balam, no un default silencioso.
> - **"Todos los request types" no es implementable literalmente.** ~14% de los tickets no tiene datos con los que armar nada. Hay que acotar el alcance por escrito o pedir que la regla de Automation propague los campos — y eso es trabajo de Balam.
> - **Sin `FACTEST`, el sandbox propio deja de ser opcional.** Se escribirá en producción una sola vez, acompañado; todo el desarrollo previo tiene que ocurrir en un sitio Jira Cloud gratuito propio.
> - **8 días de latencia en la definición**, con el agravante de que la pregunta se hizo el 30-jul y el escalamiento interno no arrancó hasta el 3-ago. Suma al patrón ya documentado: la definición del flujo lleva bloqueando desde el 24-jul.
> - **Araceli entra al hilo como aprobadora**, tanto en el correo como en el workflow de Jira. Es un interlocutor nuevo para las definiciones que faltan.
> - **PUE/PPD gana evidencia:** hay tickets `Seguimiento del Ticket con pago anticipado:`, lo que sugiere casos PUE reales y refuerza la pregunta que lleva cuatro sesiones sin hacerse ([#52](REGISTRO.md)).
**Respuesta de Johann — ENVIADA el 10-ago, tarde.** Texto completo y borradores previos en `../planeacion/Correo-respuesta-Noe-2026-08-10.md`:
> Buenas tardes, espero se encuentren bien.
> Gracias por las definiciones, quedan claras y ya retomé el desarrollo, ya validé que el campo "Monto sin IVA" está creado y funcionando.
> Para aterrizar los detalles que faltan sería de ayuda que hoy o mañana se cree un ticket de ejemplo capturado "como debería ser", con todos los campos llenos tal como quieren que se capture de aquí en adelante. Contra ese molde llego a la sesión con el flujo ya funcionando.
> Para la sesión, ¿les funciona el miércoles 12 o el jueves 13, a las 7:00 am?
> El ejercicio termina en la cotización en BIND.
> Sigo pendiente del acceso a Azure para publicar el ambiente.
> Quedo atento. Saludos.
**Decisión de enfoque:** en lugar de resolver los tres huecos con otra ronda de correos, se pide **un ticket de ejemplo capturado "como debería ser"**. Balam ya está adoptando el llenado completo de campos, así que el molde resuelve por evidencia lo que la prosa tardaría dos semanas en definir, y permite preparar el script contra datos reales para llegar a la sesión con el flujo funcionando.
**La tarea se dejó deliberadamente sin asignar** ("sería de ayuda que se cree"), para que Balam la ruteé internamente: Arturo no estaba en el CC del correo de Noé, y Noé ya venía haciendo ese papel de router desde el escalamiento del 3-ago. Nombrar a un ausente habría sido peor que dejarlo abierto.
**Alcance del ejercicio fijado: termina en la COTIZACIÓN, no en la prefactura.** Razones: es lo que contestó Arturo el 4-ago; la aprobación de Araceli va entre `En proceso de facturación` y `Facturado`, así que la prefactura pertenece después; Arturo pidió gradualismo explícito el 24-jul; y una cotización se cancela sin efecto fiscal, mientras que en BIND la prefactura es un registro en `Invoices` con `UUID = null` y los shapes de los POST nunca se han probado. Respeta los tres candados de Noé: **cotización → prefactura → aprobación humana → timbrado** ([#55](REGISTRO.md)).
**Lo que el correo final dejó fuera y ahora se resuelve verbalmente en la sesión** (sin constancia escrita previa):
- Que el ejercicio **genera una cotización real en BIND producción** y que se cancela al terminar. **Anunciarlo al abrir la sesión, antes de ejecutar.**
- El compromiso de **compartir el script antes** (condición de Noé del 24-jul). Mandarlo por separado cuando esté listo.
- Que el **disparo es manual** en esta prueba (pipeline `Draft→DryRun→Confirmed` de ADR-001 con flags apagados) y que la versión automática **depende de Azure**.
- **ACUNTIA** y el **supuesto de los tickets de `Automation for Jira`**.
**Pendientes que deja el hilo:**
- [x] ~~🔥 Johann — **responder el correo**~~**Enviado el 10-ago** (texto arriba).
- [ ] 🔴 Balam/Arturo — **definir de dónde salen los conceptos/partidas** de la cotización.
- [ ] 🔴 Balam/Arturo — **decidir qué pasa con los tickets creados por Automation** (10 de 69, sin campos).
- [ ] 🔴 Balam/Arturo — **confirmar si ACUNTIA es un ticket → una cotización** o sigue siendo 4048 facturas.
- [ ] Balam/Noé — **fecha para la prueba acompañada** de escritura.
- [ ] Balam — **¿nacional vs extranjero cambia la cotización** o solo el paquete de salida?
- [ ] Balam/Pedro — **cuenta de servicio** en vez de la cuenta personal de Pedro (planteado el 29-jul, sin respuesta).
- [ ] Johann — **levantar el sandbox Jira Cloud propio** (plan Free) para desarrollar sin tocar producción.
- [ ] Johann — mover el token de Jira a **user-secrets/Key Vault** y borrarlo de disco (ya está gitignoreado).
---
## Resumen ejecutivo del hilo (para contexto rápido) ## Resumen ejecutivo del hilo (para contexto rápido)
### Datos duros confirmados por Balam ### Datos duros confirmados por Balam
@@ -407,9 +1191,12 @@ Erika (PM, contacto principal) confirma que **ya pasaron los temas administrativ
- **BUK:** ✅ tiene API (confirmado 27-may por Pedro). No es prioridad para MVP — habilita Fase 2 post-MVP. Link pendiente de recibir. - **BUK:** ✅ tiene API (confirmado 27-may por Pedro). No es prioridad para MVP — habilita Fase 2 post-MVP. Link pendiente de recibir.
- **Bancos:** 3 bancos, solo PDFs. Banco americano = IBC Bank Texas (confirmado en llamada del 19-may). - **Bancos:** 3 bancos, solo PDFs. Banco americano = IBC Bank Texas (confirmado en llamada del 19-may).
- **Sandbox:** solo producción (BIND y BUK). - **Sandbox:** solo producción (BIND y BUK).
- **Volumen:** 45 colaboradores + 5 freelancers, ~50 facturas/mes. - **Volumen:** 45 colaboradores + 5 freelancers, **~55 facturas/mes de 46 clientes** (el mayor exige 1 factura por colaborador, ~40) — actualizado 6-jul.
- **EUR:** fuera del MVP; solo MXN + USD. - **EUR:** fuera del MVP; solo MXN + USD.
- **Lista blanca cobranza:** ACUNTIA + top 3, configurable. - **Lista blanca cobranza:** ~~ACUNTIA + top 3, configurable~~**ELIMINADA (6-jul):** Ara decidió recordatorios a **todos** los clientes morosos, sin excepciones. (La capacidad configurable se conserva, hoy vacía.)
- **Cotización BIND obligatoria (6-jul):** todo lo que se facture parte de una cotización en el ERP (requisito fijado por Ara).
- **Flujo actual:** Jira ITSM mandatorio (~1 mes) → validación administración (Arturo) → prefactura BIND → CFDI → envío por correo con particularidades por cliente (Excel pendiente de Ara/Arturo).
- **Cobranza actual (mapeada 7-jul):** el cliente avisa el pago por correo/mensaje (estado de cuenta) → el **despacho contable** registra los pagos en BIND **uno por uno** → Power BI de cartera (desactualizado). Se concilia **por folio** (la referencia no distingue facturas); los **fees** generan diferencias contra el total. Quieren **recordatorios proactivos** (15 días de vencimiento).
- **Book = SaaS** (no interno). - **Book = SaaS** (no interno).
- **Jira:** solo gestión de proyectos con clientes. - **Jira:** solo gestión de proyectos con clientes.
- **Nube preferida:** Azure. - **Nube preferida:** Azure.
@@ -425,18 +1212,25 @@ Erika (PM, contacto principal) confirma que **ya pasaron los temas administrativ
1. **Llamada del 19-may** (transcript aparte): Noe pidió textualmente *"no le queremos estar poniendo estrellitas al pino, nada más estrictamente lo que se necesita"*. Foco = facturación + conciliación. 1. **Llamada del 19-may** (transcript aparte): Noe pidió textualmente *"no le queremos estar poniendo estrellitas al pino, nada más estrictamente lo que se necesita"*. Foco = facturación + conciliación.
2. **Correo del 25-may**: Noe pide explícitamente que la **propuesta se recorte a "solo ERP BIND" primero**, dejando bancos/conciliación para fase posterior. 2. **Correo del 25-may**: Noe pide explícitamente que la **propuesta se recorte a "solo ERP BIND" primero**, dejando bancos/conciliación para fase posterior.
### Estado actual (al 30-jun-2026 — kickoff mañana 1-jul) ### Estado actual (al 15-jul-2026 — Etapa 0 en validación, Etapa 1 iniciada en local)
**Contrato FIRMADO (26-jun)** y **proyecto en arranque.** El **kickoff con Noé está confirmado para el miércoles 1-jul, 7:00 am.** Johann entregó el **plan de actividades** (4 etapas, fechas tentativas) en `../planeacion/Plan-actividades.xlsx`. Erika coordina el seguimiento (tablero Kanban en Jira) y es la **intermediaria de todas las sesiones**.
**Contrato firmado, kickoff y Discovery completos.** El prototipo de la Etapa 0 fue entregado por correo el 10-jul y Balam lo revisa internamente. La sesión formal de validación quedó confirmada para el **jueves 23-jul a las 7:00 pm**.
Johann inició en local las actividades independientes de Etapa 1. La sesión para cerrar dudas y reglas quedó el **miércoles 22-jul** con Arturo y la CEO. Deben resolverse alta de cliente nuevo, tratamiento del fee, particularidades de envío y si la automatización **Jira → cotización BIND** se incorpora al alcance.
**Accesos:** token BIND y manual de marca recibidos; repositorio GitHub autorizado por Noé y en proceso de invitación para `Johann-28`; Azure programado para la semana del 21-jul; CI/CD y secretos separados para el 24-jul. Jira técnico no se necesita salvo que se apruebe la integración automática Jira→BIND.
**Comercial:** propuesta v1.2 recibida por Erika, pero la confirmación para emitir la factura de 30 h sigue pendiente mientras Noé y la CEO están fuera del país. No hay rechazo ni pago vencido.
**Seguimiento:** se abrió control local de horas en `../planeacion/Seguimiento-horas.csv`. El Excel de cobranza/días vencidos queda condicionado a la retroalimentación del prototipo; el Excel de particularidades de envío sigue pendiente de Balam.
**Términos vinculantes del contrato:** sin anticipo + firma previa (cumplida) · **facturación semanal los viernes** por horas efectivamente trabajadas, pago a 30 días · garantía 45 días · alcance MVP BIND-first · arranque condicionado a accesos + API de BIND con lectura/escritura. **Términos vinculantes del contrato:** sin anticipo + firma previa (cumplida) · **facturación semanal los viernes** por horas efectivamente trabajadas, pago a 30 días · garantía 45 días · alcance MVP BIND-first · arranque condicionado a accesos + API de BIND con lectura/escritura.
**Calendario tentativo:** kickoff 1-jul · Etapa 0 (Discovery) sem del 6-jul · Etapa 1 1324 jul · Etapa 2 27-jul7-ago · Etapa 3 1021 ago. Las fechas se confirman/afinan al cerrar el Discovery (dependen de los accesos). **Calendario vigente:** Etapa 1 en local desde 13-jul · repo 1516 jul · Azure semana del 21-jul · sesión de reglas 22-jul · validación prototipo 23-jul · CI/CD y secretos 24-jul. Etapas 23 se afinan después de esas validaciones.
**Acciones inmediatas de Johann:** **Acciones inmediatas de Johann:** capturar/reconstruir horas reales; aceptar y validar el repositorio; continuar backend local; preparar las preguntas del 22-jul; cerrar hallazgos/ADRs tras las sesiones; mantener lista la factura sin emitirla todavía.
- **Asistir al kickoff (1-jul, 7am)** con material listo (agenda + lista de accesos a pedir + preguntas de Discovery).
- Cambiar régimen fiscal (para facturar) y confirmar permisos exactos de Azure.
**En espera de Balam:** entregar **accesos** (API BIND vía cuenta maestra ARA / llave de Arturo, Azure con Guajardo/Erika, manual de marca de Pedro) y reglas de negocio + bancos con Arturo. El **Discovery arranca** una vez recibidos. **En espera de Balam:** invitación al repo, acceso Azure, flujo Jira para horas, Excel de particularidades de envío, definiciones de Arturo/CEO y confirmación para emitir la primera factura.
**Pendiente menor:** (opcional) pedir copia limpia del contrato — la cláusula de Firma Electrónica de la última página quedó duplicada y aún dice "EL PATRÓN" (residuo de plantilla, bajo riesgo). **Pendiente menor:** (opcional) pedir copia limpia del contrato — la cláusula de Firma Electrónica de la última página quedó duplicada y aún dice "EL PATRÓN" (residuo de plantilla, bajo riesgo).
@@ -0,0 +1,506 @@
Validación de prototipo etapa 0- proyecto integración IA Balam
Fri, Jul 24, 2026
10:44 - Arturo Rosas Hernandez
Está tranquila, pero constante.
10:46 - Arturo Rosas Hernandez
No ha dejado de llover. No sé, por allá. Por aquí sí está. Mucho, mucho, mucha agua. Pero de a poquito. ¿Qué tal, Araceli?
10:57 - Unidentified Speaker
Buenos días.
10:58 - Unidentified Speaker
¿Cómo estás?
10:59 - Unidentified Speaker
Buenos días, Karol.
11:01 - Unidentified Speaker
Buenos días.
11:02 - Araceli Sanchez Jimenez
Ya, ya sé.
11:03 - Araceli Sanchez Jimenez
Buenos días.
11:04 - Araceli Sanchez Jimenez
Oigan, Noe. Ah, ya está. Bueno. Listo. Ya estamos todos listos. ¿Listo?
11:10 - Erika Chavez
Bueno, este, esta sesión es para ver lo de la validación de la etapa cero, que es el prototipo navegable que aquí mi compañero Johann realizó.
11:24 - Johann
Entonces, el foro es todo, Johann, adelante. De acuerdo, voy a compartir pantalla y voy a presentar el prototipo. Cualquier duda me pueden preguntar. Gracias. Aquí pueden ver mi pantalla.
11:40 - Unidentified Speaker
Sí, ya.
11:41 - Johann
Ok, les voy a presentar el PDF que les compartí, en donde hay capturas del prototipo y una pequeña descripción. Voy a ir explicando cómo es cada pantalla y el proceso que se reflejó en este prototipo. Entonces, este proceso consta de cinco pasos en cuanto a la facturación. Todo comienza en una solicitud en Jira. Después de la solicitud en Jira, se pasa a una cotización en Bind, pasa a prefactura y, antes del CFDI y la facturación, necesita una aprobación humana. Hay algunas reglas que se levantaron durante el Discovery, durante las sesiones, como, por ejemplo, el PPD por defecto, y PUE solo consciente. También la regla prefactura que siempre va a estar antes de timbrar, el IVA de 16% nacional, la cotización al principio de manera obligatoria y un recordatorio interno de monosías de los clientes. Esto es para el proceso de facturación.
12:54 - Noe Rocha
Estamos hablando del proceso de facturación, el primero que se está abordando como parte de la automatización que se está buscándose las diferentes fuentes de información en un punto único de ejecución.
13:12 - Unidentified Speaker
Así es.
13:13 - Johann
Comenzamos por esa pantalla que es la de iniciación. De esta manera, cada persona logueada verá las facturas que le corresponden y podrá ver todo lo relacionado a su cuenta.
13:30 - Araceli Sanchez Jimenez
Aquí ya tengo una pregunta. Aquí en el inicio de sesión, me imagino que hay un solo usuario. O sea, todos vamos a tener, bueno, o los que demos acceso aquí, vamos a ser administradores, ¿no? O sea, no va a haber privilegios. Es nada más, o sea, yo tengo y si yo entro o Juanito o Pedrito, vamos a ver absolutamente todos lo mismo.
13:57 - Johann
Aquí, por ejemplo, como a ustedes les convenga más, necesitan que un usuario tenga más acceso que otro, ya está preparada la plataforma para los roles. Ah, super. OK. Perfecto. Muchas gracias, Johann.
14:09 - Araceli Sanchez Jimenez
O sea, de momento, como somos nada más dos personas que llevamos todo este tema, digo, podemos ver todo. Pero yo nada más viendo a lo mejor en algún momento que a lo mejor tengamos un analista que vea cierto punto, pues no necesita ver todo lo demás, ¿verdad? Es nada más un tema de cultura general para saber qué Ahora comenzamos con este apartado del dashboard, en donde se muestran estos cuatro valores en forma de cartas y que se necesita atención.
14:42 - Johann
Entonces, en esta pantalla se busca que estén a la mano los datos, el resumen de los datos de las facturas y la cartilla de datos. Como por ejemplo, facturado en julio en pesos mexicanos y dólares, cuántas facturas emitidas hay y cuántas pendientes, cuánto, qué cantidad hay en cartera vencida. También aquí hay algunos ítems de qué se necesita atención y qué responsable hay y cuánto tiempo tiene de antigüedad. Además, aquí debajo se muestra en forma de dashboard, la facturación mensual en forma de gráfico de barras y facturas por cliente de mayor a menor. De esta manera se puede ver un resumen de los datos de forma resumida. Aquí habría que validar qué datos ustedes quieren ver. Esta es una propuesta de cómo se vería y algunos datos que podrían interesar. Pero ustedes me comentan qué datos son los que hoy día quieren ver, porque entiendo que también bien comentado que ya tenían un dashboard en Power BI con Pedro, entonces de pronto pudiéramos ahí acoplarlo en esta parte.
16:02 - Johann
Oye Johann, una pregunta.
16:03 - Araceli Sanchez Jimenez
Aquí en los datos que pones, ¿qué necesita atención? ¿Estos los jalaste de Jira? ¿Serían los tickets que los jalas de Jira? ¿O cómo determinas o sacas esta información? Sí, podría.
16:16 - Johann
Jira y el estatus del estado de facturación podría ser un criterio para mostrarlos aquí Ya.
16:22 - Unidentified Speaker
Ya, ok, ok, ok.
16:24 - Araceli Sanchez Jimenez
Y realmente, como tú dices, esto es customizable, ¿no? O sea, nosotros lo podemos decir, oye, Johann, esta información ponla aquí, por ahí, digo, ok, perfecto. Sí, justamente. Pero de entrada, en la propuesta, tú propones mostrarlo así. Así es.
16:41 - Johann
Si ustedes me comentan, de pronto, que estos datos no son los que les interesa ver y ocupan otros, o visualizarlos de otra manera, y lo acomodamos. Mi propuesta es ver en esa pantalla de Dashboard un resumen de los datos que ustedes quieran ver. Pero sí, como me comentas, cualquier detalle a cambiar lo ajustamos sin problema.
17:05 - Araceli Sanchez Jimenez
Oye, a lo mejor me estoy adelantando, pero, por ejemplo, aquí en el tema de la cartera vencida, en este tema nosotros tendremos que alimentarlo manual, o sea, bajar todos los estados se cuenta de VanNorte de manera diaria o cómo está alimentado?
17:25 - Johann
Si no está en Bind, ahorita mismo se puede sincronizar desde Bind, pero si no se puede sincronizar desde Bind, sí tendría que hacerse una carga al sistema.
17:41 - Noe Rocha
O sea, en este momento La cartera vencida es lo que informe Bind. Sí. Específicamente la fuente de información de esto es o es Bind o es Jira. No hay una fuente alterna.
18:00 - Araceli Sanchez Jimenez
Así es. Perfecto. Ya, ya entiendo. Ok.
18:04 - Unidentified Speaker
Gracias.
18:04 - Unidentified Speaker
Excelente.
18:05 - Johann
Después del Dashboard pasamos a esta pantalla de facturación. Aquí estamos en el módulo de facturación. Aquí venían las solicitudes de facturación que vienen desde Jira. Aquí cada registro corresponde a un ticket levantado en Jira, en donde mostramos la información y el estatus que hay en Jira. Y ahora, de esta manera, se pueden ver todos los tickets de Jira en un solo lugar, que es aquí en la plataforma. Y poder llevar el seguimiento desde aquí.
18:44 - Araceli Sanchez Jimenez
Oh, wow.
18:45 - Noe Rocha
Además aclarando que los status son status, no como aparecen actualmente en Jira, porque este prototipo fue antes de explorar los flujos de Jira. Porque, por ejemplo, ese status que dice listo para facturar en Jira es facturado, si mal no recuerdo. Nada más para hacer la observación, pero como prototipo, Esto es una propuesta y se va a adaptar a los flujos que nosotros definamos.
19:15 - Johann
Sí, justamente. Muchas gracias, Noe. Así es. Aquí en estatus iría reflejado el proceso que ustedes ya llevan.
19:23 - Araceli Sanchez Jimenez
Ok. Perfecto. De acuerdo.
19:25 - Johann
Entonces, aquí... Aquí a la derecha hay un botón de ver detalle. Y cuando se le da click, podemos nosotros ver de este ticket, así como se lleva algunos archivos adjuntos. Y desde aquí se va a poder iniciar la facturación. Y ahora, en esta parte, es en donde también necesitaremos ver el API key de Jira y toda esa parte para comenzar a sincronizar las facturas. Y ahora, cuando se tiene esta parte, y cuando ya se revisó el ticket de Jira, ahora sí, aquí también podemos ver este ticket desde Jira, si se quiere ver desde la plataforma de Jira. Y desde aquí tenemos la oportunidad de comenzar la facturación.
20:23 - Araceli Sanchez Jimenez
Yo aquí tengo una pregunta, es como de funcionamiento. Normalmente, o sea, levantamos un ticket en es Jira, un ticket por factura, no? Pero, por ejemplo, en el caso de Accions es un ticket y ese contiene un Excel y ese Excel tiene N cantidad. O sea, ese Excel puede tener un varia el número, pero 40, 45, 48 facturas. Pero no abrimos un ticket por las por Entonces, ¿tendría la guía la habilidad de decir OK, es un ticket, leer el archivo en Excel y decir OK? Entonces, ¿va a ser una factura por cada columna que haga?
21:05 - Johann
No, ahora mismo sería una factura por ticket.
21:09 - Araceli Sanchez Jimenez
OK.
21:09 - Noe Rocha1
Ahora mismo, a ver, ahora mismo, ¿cómo está el proceso, verdad? ¿Hay ciertos asegúnes que habría que ver cómo los vamos a manejar? Por ejemplo ese particular, en donde es un solo ticket con múltiples facturas. Entonces tendría que evaluar cómo hacerlo, si lo vamos a llevar a ticket por factura o un ticket con múltiples facturas, con múltiples hijos. Pero aquí por ejemplo hay un tema que me gustaría platicar con ustedes, porque el proceso como se definió Arturo y Araceli es que cuando Pone el proceso de GIRA para facturar como está en la CIS. La CIS de hoy es que la factura debe hacerse antes de que se cierre el ticket. Por lo tanto, no iniciaría el proceso de facturación desde el sistema, sino que desde antes se tiene que estar haciendo.
22:06 - Araceli Sanchez Jimenez
¿Sí me explicó? No. A ver, más lento.
22:09 - Noe Rocha
A ver un ejemplo. Arturo tiene un proceso de facturación. Ábrete, GIRA, por favor, para ver tus casos. Vamos a pasarlo muy bien. Gráfico. Voy a quitar la pantalla aquí tantito, Johann, Arturo. Entonces, por ejemplo, Arturo recibe un ticket. Ahorita vamos a ver el flujo. ¿Sí? Beta facturación, Arturo. Y esto sí tendríamos que definirlo, ¿verdad? Porque es una definición de proceso, no es una definición del sistema.
22:39 - Araceli Sanchez Jimenez
Ah, mira, justo esta es la que te digo. Tenemos la factura es un solo ticket, pero si tú le das clic son múltiples facturas.
22:50 - Noe Rocha
No, es que ahí yo veo un error porque dice facturación nacional y es extranjera.
22:57 - Unidentified Speaker
Ah, invalidación nacional.
22:58 - Noe Rocha
Entonces te va a pedir el xml y el pdf cuando solamente es el pdf. Bueno, independientemente de eso voy al punto que quiero explicar. Vámonos a cualquier flujo de facturación. ¿Facturación, Arturo?
23:12 - Unidentified Speaker
Dale clic donde dice facturado y dale ver flujo.
23:17 - Noe Rocha
Muy bien, y dale si quieres un zoom. Lo vamos recorriendo hacia arriba. Aquí me va a tratar de explicar gráficamente, a ver si me va a entender. Primero, se genera el ticket para la facturación. Por cualquier área que necesite un proceso o por un proceso ya automatizado de facturación, como son las recurrencias. Segundo, se pasa a un estatus de abierto. Después de eso se va al proceso de facturación. ¿Qué quiere decir esto? Que aquí en esta parte, en este proceso de facturación, ya se fue a Bain a hacer la factura. ¿Se explicó? Entonces, Si nos devolvemos a la pantalla de Johann, Johann tiene desde ahí que se haga la facturación.
24:13 - Araceli Sanchez Jimenez
Entonces... Oye, yo tengo una duda, porque por ejemplo en Vine hay una diferencia entre prefactura y factura. Entonces, en este caso, ¿es ya la factura en sí o es una prefactura? La diferencia es que no está timbrada. O sea, generalmente nosotros hacemos prefacturas para darle un doble Y ya una vez que le dijimos que sí, entonces ya la timbramos con el SAT. Aquí, en el proceso que ustedes están considerando en proceso de facturación, ¿ahí es ya facturarla, ya timbrarla?
24:44 - Noe Rocha
No, porque este proceso es lo que se va a definir con las reglas de negocio nuevas que vamos a hablar, que es el propósito de esto, ¿no? Es decir, ¿cómo la vamos a hacer? Porque si antes dijimos que el proceso de facturación de Jira era, aquí ya tengo que tener la facturación, entonces vamos a tener que hacer un ajuste. O lo hacemos aquí y luego se lo presentamos al sistema, lo cual no sería lo práctico porque la intención del sistema es que el sistema nos ayude a optimizar, a hacer las cosas, ¿no? O definimos que en esta parte del proceso de facturación sea donde se dispare esa ejecución ahora sí. En la pantalla de Johann. ¿Sí me explicó? No sé si me estoy explicando.
25:32 - Arturo Rosas Hernandez
Sí, sí, sí, estoy de acuerdo.
25:35 - Arturo Rosas Hernandez
Nada más que sí es muy importante. Bueno, como dices, ahorita lo estamos definiendo. Sí, sería muy importante que sea prefactura. ¿Para qué? Justo, justo, justo para continuar con este flujo, que es bueno en proceso de facturación. Sabemos que inicia en Bind, pero debe haber una validación de justo de lo que acabas de ver, no de que sí nacional y a lo mejor la generó extranjera o es extranjera y la genera nacional y después pues hacer una validación nacional extranjera y y revisar no revisar que los datos sean correctos que no haya ninguna inconsistencia de que los los el tema fiscal esté registrado correctamente los montos las descripciones etcétera sean todas correctas entonces pero sí que hay una validación previa y que no caigamos en incumplimiento porque se supone cuando generas demasiadas facturas y cancelas demasiadas facturas, también puede ser observado por el SAT. Entonces, evitar en la medida de lo posible la cancelación de facturas como tal. Por eso es necesario que lo que haga la herramienta sea para facturas, para poder revisar. Tal vez en algún futuro ya daremos independencia completa y pediremos que facture directamente. Pero por ahora, para ir monitoreando el uso o la eficiencia de la IA, si tendría que ser ProFacture.
26:57 - Noe Rocha
Es que recordemos algo, este flujo de Jira, no me quiero atorar mucho aquí porque hay más pantallas que explorar, pero sí tenemos que volvernos a Arturo y a Araceli para redefinir cómo va a quedar este flujo, porque dependiendo de cómo quede este flujo es cómo vamos a ejecutar en el modelo que Johann nos está poniendo sobre la mesa, pero no es algo ni que Johann ni mío que definimos es cómo el proceso lo vamos a definir para el uso dentro del área de facturación.
27:30 - Araceli Sanchez Jimenez
Ok, entonces si quieres lo dejemos pendiente y si quieres nada más, ya que Erika nos ayudé a coordinarlo, yo salgo de viaje otra vez el miércoles jueves y viernes no voy a estar, entonces si lo podemos ver el martes estaría perfecto porque el lunes ya lo tengo saturado, para que ya no... Porque de esto depende que Johann pueda seguir avanzando, ¿no?
27:54 - Noe Rocha
Va a avanzar en otras cosas, pero como tal, el prototipo en esta parte está saturado por esta definición de nosotros.
28:00 - Erika Chavez
Ok, de hecho Johann sigue, ya está en la etapa 1, este es lo de la etapa 0, el entregable, entonces en cuanto él ya le... Ya tiene indicaciones en cuanto a él le detenga algo, pues me va a levantar la mano, pero si esto no le detiene a Johann para seguir avanzando en la etapa 1. Sí.
28:18 - Unidentified Speaker
Gracias.
28:19 - Noe Rocha
Esta es una regla de negocio, regla de nosotros. Hay que definirla.
28:27 - Unidentified Speaker
Adelante, Johann.
28:29 - Johann
Aquí, de acuerdo. En esta parte de iniciar facturación, voy a compartir pantalla del prototipo navegable, que es este que les compartí. Entonces, en... Solicitud de gira, al abrir una solicitud, después...
28:50 - Arturo Rosas Hernandez
Creo que no vemos tu pantalla. Yo no la veo.
28:56 - Unidentified Speaker
Listo, ¿la pueden ver?
28:58 - Johann
Listo, ahora sí.
29:00 - Arturo Rosas Hernandez
Ahora sí, pero vemos a nosotros mismos. Listo.
29:04 - Noe Rocha
Este ya es el prototipo navegable.
29:07 - Noe Rocha
O sea, no es el PDF, es como tal el URL.
29:15 - Unidentified Speaker
Así es.
29:16 - Johann
Aquí estoy dentro de una facturación. Me fui aquí a solicitudes Jira y abrí un ticket de Jira. Ahora, aquí, al iniciar una facturación, se me abrirán estos pasos para completar desde la cotización hasta la aprobación humana que timbra la factura. Ahora, aquí, cada ticket tendrá una cotización. En Bind. Puede ser que se cree por parte comercial o del despacho, entiendo que era quien creaba estas cotizaciones o quien las quería, o el sistema puede crearlas automáticamente utilizando... Apenas se crea el ticket, por ejemplo, va a Bind y lo crea. Después se ligan, no? Ese ticket y esa cosa. Eso estaría genial.
30:15 - Araceli Sanchez Jimenez
Quisiéramos un ticket en gira porque, por ejemplo, ahorita ese Johann lo hacemos manual, o sea, yo generalmente este soy la parte comercial, entonces yo me meto y como ya están pre configurados los clientes, o sea, sí debe de haber un pre requisito, verdad que ya estén dados de alta en el RP, pero una vez así te vas a cotización y entonces yo escojo los diferentes rubros y ahí ya yo hago la cotización, que es algo muy rápido y ya con esa cotización generalmente ya en los tickets para facturación anexa esa cotización para que facturación nada más haga la búsqueda y pues la convierte en prefactura lo necesario, pero si con levantar el ticket, ya se genera la cotización en el sistema estaría más que genial.
30:55 - Arturo Rosas Hernandez
De hecho, perdón por la interrupción, pero de hecho ayer, justo ayer en la comida platicábamos Pedro y yo, que yo le decía que en algún momento se fuera preparando porque yo sugería que hubiera un espacio para comercial con su debido proceso en gira. Entonces, si ya tenemos facturación, si ya tenemos cuentas por pagar, cuentas por cobrar RH, etcétera, creo que vamos a tener que crear un espacio para comercial y en ese espacio de comerciales, donde subiríamos los tickets, es donde la IA, que habrá que irle poniendo un nombre a la IA para nombrarla como herramienta. Bueno, a la IA va a ir a buscar los tickets y de donde va a tocar tomar la información para generar la cotización. Eso justo estábamos, se lo prometo, estábamos platicándolo Pedro y yo ayer en la hora de comida. Entonces creo que habrá que considerarlo también como parte de la regla de negocio, como dice Noe. Para dejar todo ordenado.
31:51 - Noe Rocha
Disculpen porque lo mencionan mucho, pero sí quiero ser muy vocal de lo que estamos viendo. Este es un desarrollo y todavía no está dentro de este desarrollo, en dentro, enbebido en este desarrollo, agentes LLM. Lo que están son reglas de negocio de procesamiento de información e integración con diferentes sistemas. ¿Para qué? Para homologarlo a pantallas. Entonces sí quiero dejar muy claro, no es un agente, es un LLM que está haciendo todo tras BarbaLimna. Es un desarrollo que sí está pensado y sí lo hablamos con Johann, que en un cierto momento le íbamos a tener que meter LLMs, pero como esto todavía no está digamos que en el scope inicial todavía no está el agente. Sí está entendido que lo vamos Pero para esto, que es simplemente regla de negocio y proceso, no es IA.
32:50 - Araceli Sanchez Jimenez
Nada más quiero aclararlo. En esto, en todo lo que nos han explicado, o en esto, es de preparación, aprobación y emisión de CFDI.
33:00 - Arturo Rosas Hernandez
En general, en todo.
33:02 - Araceli Sanchez Jimenez
En general, yo fue lo que entendí también. Entonces esto no es IA.
33:08 - Noe Rocha
No, es desarrollo. Es desarrollo... Con integración de pantallas.
33:12 - Araceli Sanchez Jimenez
Ah, y yo pensé que esto era agente de IA. No, no, no, no.
33:17 - Noe Rocha
Esto es desarrollo a la medida que sí, sí va a tener un componente de IA, pero en este momento todavía no va a estar, porque esto se resuelve con reglas y con procesos. Todavía no es necesario meter un agente como tal para hacer, pues, todas las, todo esto. Sí, lo están mencionando mucho. Y nada más aclarando ese punto, Johann, sí tenemos la intención de meter agentes, pero en este momento es regla de negocio con procesos e integración de sistemas. ¿Por qué? Porque ahorita tenemos todo desvinculado y todo lo tenemos que hacer manualmente, con diferentes pantallas, diferentes procesos, diferentes cálculos. Pero esto, como tal, lo que va a venir a hacer es, va a pivotear todos los sistemas para hasta automatizarlo. Ok. A través de reglas y procesos. Sí. Muy bien. No sé si quede claro.
34:12 - Unidentified Speaker
Sí.
34:12 - Unidentified Speaker
Sí.
34:13 - Noe Rocha
Johann, ¿quieres complementar algo de lo que comenté?
34:17 - Johann
Sí, justamente en este MVP se busca asentar el proceso que ustedes tienen para en un futuro implementar los modelos ya sobre este sistema bien fundamental.
34:30 - Araceli Sanchez Jimenez
Esta es la base.
34:31 - Noe Rocha
Sí, necesitamos una base de un proceso bien claro de cómo va a ser, porque si le metemos IA de inicio va a ser una fiesta.
34:41 - Araceli Sanchez Jimenez
Y qué haría la IA que no hace, o sea, qué plus nos daría la IA sobre esto?
34:47 - Araceli Sanchez Jimenez
Ponme un ejemplo.
34:48 - Noe Rocha
A ver, Johann, ayúdame con esta pregunta, porque ahorita de inicio a mí lo único que lo tengo claro que a lo mejor cosas como una gente que yo le pueda mandar información para que me lo procese ya dentro del sistema, ya no que yo tenga que estar interviniendo todo el tiempo manualmente.
35:04 - Johann
Pero con una regla, con una regla de vas a hacer A, B, C, D, E, A, B, C en este sistema, por ejemplo, se pudieran implementar en esta parte de tomar decisiones o saber cuándo, por ejemplo, una cotización lleva mucho tiempo parada, por ejemplo, o tomar decisiones y dejar preparadas facturas para que Araceli y Arturo simplemente tomen la decisión final. En ese apartado de dejar listo para que Araceli y Arturo vean un listado de facturas o de consideraciones que, por ejemplo, puedan estar en el riesgo o en el área de este apartado tiene algo raro, en esa parte la IA nos podría ayudar a prevenir Esos casos. Y eso ahorraría tiempo, por ejemplo, para estar leyendo todas las facturas. Y podría presentarlos, por ejemplo, cada mañana en el dashboard, por ejemplo. O de pronto podemos meterlo en la parte de conciliación como extra. Aparte de esa...
36:41 - Noe Rocha
Ahí sí, por ejemplo, entraría directamente la IA. Oye, ¿cómo hacemos la conciliación ahora? A mano. Sácate un estado de cuenta. Fíjate cómo está Vine, ¿verdad Arturo? Y Concilio, ¿qué se pagó? Bueno, ahí sí metemos la idea, porque es un proceso hoy por hoy que no nos lo resuelve nada manualmente. O sea, todo lo tenemos manual y no hay un proceso que nos ayude muy claramente a machar las conciliaciones. Entonces ahí sí entra, ahí sí entra la parte de un agente. Y después ya con la raíz de la cara clara de es el camino, lo que tiene que hacer para diferentes pasos de facturación. El sistema ya como está hecho, ahora sí, el agente lo puede hacer más automatizado. Ejecútame los pasos de facturación. Básicamente, échatelo, no? Sin que tengamos que estar interviniendo pantalla por pantalla.
37:39 - Araceli Sanchez Jimenez
Perfecto, ya entendí.
37:40 - Noe Rocha
Pero parte de que tengamos claras las reglas, porque si no, sin reglas claras, un agente no es eficiente.
37:50 - Unidentified Speaker
Gracias.
37:50 - Noe Rocha
Ahora yo hago otra observación aquí, muy importante, porque se menciona que la cotización es necesaria para esto que estamos viendo aquí con Johann, el 1, 2, 3, 4 y 5. Pero por ejemplo, y aquí lo pongo solo en la mesa, las recurrencias no existe una cotización para cada factura. ¿A qué voy? Tenemos facturas que son recurrentes porque ya hay un acuerdo y un contrato, Johann. Significa que no tenemos que tener una cotización para facturar porque ya está vendido un proyecto. ¿Te acuerdas lo que te platicaba la sesión pasada? Oye, tengo un contrato de servicio con un cliente y. Pues ese contrato.
38:35 - Araceli Sanchez Jimenez
Como el de AXIANS que está pagando por cuatro años, tres años. Y esperemos que ganemos otro.
38:41 - Noe Rocha
Ahí sí tendríamos que tener. Sí, sí, correcto. Ahí sí tendríamos que tener.
38:45 - Araceli Sanchez Jimenez
tener una una excepción de que no si es recurrente no necesita una cotización si me explicó o a lo mejor que nunca bueno no sé ustedes saben pero a mí me gustaría que nunca hiciéramos excepciones o sea al final del día todo no ha sido una cotización aunque sea recurrente o no entonces podría siempre generarse la cotización y de la cotización siempre se pasa prefactura o factura bueno dependiendo de lo que definamos no Estoy de acuerdo con Ara, porque al final de cuentas son puntos de revisión, oportunidades para revisar y evitar errores o mitigar los riesgos de errores humanos o errores en las configuraciones, sobre todo al inicio, ¿no?
39:28 - Arturo Rosas Hernandez
Al inicio de la implementación de esta herramienta, pues sí estar monitoreando en cada fase, en cada paso, todo lo que suceda para asegurar que todo suceda de manera correcta y o, algunas veces, como en Big Brother, las reglas cambian. Entonces, no obviar que cada mes todo es igual, sino estar asegurando que cada mes, si hay algún cambio en la descripción, en los montos, en lo que sea, ese mes se corrija y se emita conforme el nuevo acuerdo, conforme las nuevas reglas.
40:09 - Noe Rocha
donde entraría algo que no sé si debe vivir aquí y lo pongo sobre la mesa para ver si es algo que más adelante lo ponemos. No ahorita porque si no, no vamos a salir nunca porque va a haber muchos supuestos. Pero por ejemplo, en videos pasados, si tú te acuerdas Arturo, teníamos los contratos. Y ese contrato decía, este contrato por un año vale 12 pesos. Entonces cada orden de compra que yo haga por este contrato me del debe contrato de descontar lo contar que ya se facturó y se pagó de tal forma que si al mes seis yo tengo que ya se facturaron seis pesos y se cobraron seis pesos no puedo cobrar más allá de otros seis pesos porque ese Más o menos, amigo, porque más o menos, porque justo con el ejemplo de Axios, o sea, las personas suben, bajan, los precios cambian, se ajustan, aumentos de sueldo, disminución, nuevos acuerdos, etc.
41:04 - Arturo Rosas Hernandez
Entonces, por eso diría sí, pero no por eso yo digo que sí o bueno, estoy de acuerdo con lo que dijo Ara, de que siempre generemos la conciliación, porque es una oportunidad para revisar de oye, para el empleado, para colaboradora eran 6 pesos, pero acuérdate que esta vez son 5 por RENECOSA o son 6 más 1 que es viáticos o son 6 más lo que sea, ¿no? Entonces, sí debes tener la oportunidad.
41:35 - Noe Rocha
Pero aquí entra mi pregunta, porque esto sería un trabajo adicional. ¿Significa que cada vez que se tenga que facturar vas a hacer una cotización, Araceli? Significa que, por ejemplo, vamos a poner el caso de AXS, para cerrar la pregunta. ¿Sería práctico que cada mes tendría que hacer la cotización?
41:58 - Araceli Sanchez Jimenez
Es lo mismo. Si tú haces una cotización, el esfuerzo es el mismo. Por ejemplo, no hacemos cotización, pero al final del día se captura a mano la factura. Entonces da lo mismo. Porque cuando tú haces una cotización, esa cotización es en el RP, nada más te vas a un menú y esa cotización la conviertes. Nada más le haces un clic a prefactura o a factura. Y cuando tú también, entonces tú nada más es un clic. Y por ejemplo, cuando tú vas a facturar, hace el capturas lo mismo y nada más le haces un clic y lo timbras. Entonces el esfuerzo es el mismo.
42:35 - Noe Rocha
Ah, entonces miren, fíjense que hay un dato importante.
42:38 - Araceli Sanchez Jimenez
No sé si tú lo estás viendo, Johann, pero por no sé si nos explicamos o quieren que les expliquemos porque el esfuerzo es lo mismo, o sea, por eso a mí me hace sentido que todo nazca de una cotización, porque todos los datos son todos los mismos y nada más la diferencia en la cotización que, por ejemplo, cuando es un tema comercial, yo nada más la cotización la convierto a PDF, pero cuando ya se vendió, esa cotización yo la subo y entonces Artur lo que hace es, oye, factúrala y baja, nos da un número de folio, se va el sistema, el número de folio, aparece la cotización y nada más le da un clic factura o prefactura.
43:20 - Noe Rocha
Entonces es lo mismo. Entonces aquí es un arreglo interesante. Si la cotización sirve para que se convierta en factura o prefactura, entonces en estos pasos hace sentido. Primero cotización, los datos, los conceptos y luego ya validado, ya conocido información, se va a prefactura, no a se va a ir a prefactura, se va a tener una aprobación humana que va a ser una... Esa aprobación y después, después ya se timbra. Entonces tenemos candado 1 cotización, candado 2 prefactura, candado 3 aprobación y ya al final pues la factura como tal. Entonces son 3 candados para validar que esa factura tiene que salir pues como tenga que salir, ¿verdad?
44:10 - Unidentified Speaker
De forma correcta.
44:12 - Noe Rocha
Sí. ¿Hace sentido ese flujo entonces?
44:15 - Unidentified Speaker
Sí.
44:16 - Noe Rocha
Ok, de acuerdo. Gracias. Valente, Johanna. Ok, de acuerdo.
44:20 - Johann
Ahora, en esa parte donde comentan, así como comentario extra, también para tenerlo presente, ¿va a haber cotizaciones y, bueno, facturas que no van a vivir en Gira? O si esas cotizaciones o esas facturas que no tienen cotización a día de hoy están reflejadas en Gira, porque ahorita este ejercicio comienza desde un ticket de Gira. Entonces, si hay alguna cotización. Que no esté en Gira, no va a ser reflejado, entonces pregunto para, por ejemplo, considerarlas aquí para la regla.
44:58 - Araceli Sanchez Jimenez
Si no, no, Johann, ya por regla y política de la empresa, los únicos y Lo que no está en JIRA no se procesa, ya sea en facturación, cobranza u otras solicitudes de la operación de la empresa. Entonces, ahora sí, el único punto de inicio en donde realmente se detonan los procesos es JIRA. Entonces, todo debe de estar contenido ahí para que no nos vayamos por otro. Nada más es JIRA. Sí, que no sea un correo, que no sea un mensaje. Si no está en JIRA, no es oficial. Sí, y de hecho, por ejemplo, en mi caso, que luego me llegan correos con facturas cosas así como para yo no capturar de manera manual y un ticket en gira y yo ya tengo una dirección establecida de correo yo lo reenvío ese correo aún y a una dirección de gira y giren automático me hace un ticket entonces todo está por girar ya aquí aquí entiendo muchas gracias Ahora, continuando con estos pasos, así como comentan, sí, aquí los candados serían primero la cotización, después la prefactura, la aprobación y por último el timbrado, que es lo que sucede cuando avanzamos con este proceso de facturar.
46:18 - Johann
Entonces, primero vemos los datos que tiene la factura. Aquí se selecciona el método de pago, está por defecto el PPD. Ajá. Los conceptos EIVA de esta factura, bueno, de esta cotización. Después, se ve una previsualización de la prefactura. Aquí se puede dejar y guardar para validarla después, o podemos enviarla directamente a aprobación. Y ahora cuando se envía a aprobación, aquí, por ejemplo, se puede dejar lista para que o Arturo o Araceli la aprueben desde su cuenta una vez se apruebe ya se puede timbrar, primero se aprueba y luego se timbra y después pueden o emitir otra factura o continuar y enviar la factura con los documentos para esta parte del correo te tendría que dar un buzón o algo por el estilo, ¿verdad? Sí, ocuparemos un buzón de.
47:33 - Noe Rocha
Sí. Así es.
47:35 - Araceli Sanchez Jimenez
Oye, Johann, yo por ejemplo, aquí ya ves que tenemos algunos asegúnes, es decir, hay algunos que nada más le mandamos la factura, es decir, le echa un rollito ahí el por ejemplo, en el en el tema de Accions, le mandamos las cuarenta y tantas facturas en una carpeta zip, o sea, no le mandamos un correo por factura, pero además de de mandárselas todas en un en un solo correo, nos pide el estado de cuenta de esas facturas, es decir, les mandamos así y entonces se le manda un archivo que eso también se se saca de del sistema de entonces veinte y cincuenta, estas son tuyas y corresponde veinte, veinte, Araceli Sánchez del Perú, no sé qué, cinco mil y algo, o sea, se les manda todo eso, o sea, además de la factura. Aquí, por ejemplo, nada más se adicionaría en la factura, y nosotros a este correo le podemos anexar cosas o.
48:45 - Johann
Sí, sí, justamente, por ejemplo, tenga sus propios requisitos y, por ejemplo, aquí en el ejemplo de Cemex, me parece envío bloqueado porque me faltan las horas, el Excel de horas.
48:59 - Araceli Sanchez Jimenez
Sí, órale, sí, me gusta. Yay, jubilados, Artur, ya. Ya. Bueno, está en la playa. Exactamente, así desde la playa, autorizar, enviar. Mira, pues de hecho ahí está, ¿eh?
49:13 - Noe Rocha
Ahí no menciona. ¿Dónde estaba el zip? Acuntia. Ahí viene, .zip, pdf.xml, más estado de cuenta. Ya lo menciona.
49:21 - Araceli Sanchez Jimenez
Andale, super, sí. O sea, decirlo con particularidad por cliente. Sí, Johann, y ya ves que aquí luego los clientes es como el Big Brother, las reglas cambian. Entonces, por ejemplo, si de repente nos piden otra cosa por sistema, se puede anexar esa o quitar o poner la nueva regla, ¿verdad?
49:41 - Johann
Ok, habría que desarrollar ese módulo de configuración? Al principio esto estaría cerrado, directo, cerrado, sí, pero si se puede, nada más que ahora mismo sería desarrollar el módulo.
49:52 - Araceli Sanchez Jimenez
Sí, no, no, y si no, pues te contactamos, nos cobras unas horas de servicio y nos haces el ajuste, ¿no? Sí. Ok, sí, digo, de momento yo creo que no es necesario desarrollar el otro de configuración porque realmente, pues, es pequeño, pero yo nada más porque luego nos cambian la y si sí, nada más saber que la podemos poner ahí, porque al final del día esto nos libera mucho, Johann, porque luego, de entrada, la curva de aprendizaje nos las hace muy laxa o muy soft porque por ejemplo a lo mejor ya le dimos la capacitación a alguien y lo quiere mandar y va a decir ah si cierto tengo que mandar a b c d entonces así quita también mucha vigilancia humana no o acompañamiento de cierta forma gracias así es ok entonces esta parte es todo el proceso por la parte de facturación.
50:55 - Johann
¿Aquí hay alguna duda? Porque seguiría después cobranza. No. Yo ninguna, no sé si ustedes.
51:02 - Noe Rocha
No, nada más las reglas, nada más arrañar un poco nosotros para la regla específica de lo que comentamos antes. Pero de ahí en fuera el módulo es bastante, creo que se ve muy visual e intuitivo.
51:19 - Unidentified Speaker
Sí.
51:20 - Araceli Sanchez Jimenez
Me encantó.
51:21 - Johann
De acuerdo, continúo. Ahora, esta parte de cobranza. En el módulo de cobranza vamos a tener las facturas abiertas y los estados de cuenta. Entonces, toda esta información del módulo de cobranza, aquí la podemos ver, tendrá los estados de cuentas asociados. Y ahora aquí, nosotros tenemos dos pantallas. En la primera vamos a ver las cuentas por cobrar. Y aquí se pretende que el segundo reemplazo, no reemplazo, pero que sea el equivalente al Excel que compartió Arturo, en donde pueden ver las facturas y cuánto tiempo llevan de morosidad por cliente.
52:17 - Johann
Johann, esto se alimenta de Vine, ¿verdad?
52:19 - Noe Rocha
O sea, si Vine no está conciliado en algún dato, pues no nos va a dar la información. Al día. Si primero no está en Vine. Porque la fuente oficial de información es Vine. Así es. Ok.
52:35 - Johann
Sí, justamente como mencionas, viene desde Vine.
52:38 - Arturo Rosas Hernandez
Aquí tengo una duda y es la parte en la finza. Digamos que están los estatus obvios, ¿no? Por pagar, pagada, cancelada o... No veo el resto de estatus. Ok, entonces, pero hay unas facturas especiales que digamos que ya están programadas para pago, que de cierta manera las estamos ahorita categorizando de otra manera, ¿no? Entonces ahorita justo unas facturas que ya están programadas para pago, es decir, hoy mismo me apareció una factura que dice que se va a pagar el 24 de septiembre. Esas le llamamos NAFINSA y las categorizamos con esa tipificación, NAFINSA. La pregunta es, para este módulo de cuentas por cobrar, ¿habría la posibilidad de categorizar de manera diferente este tipo Si no está en Bind, no.
53:43 - Noe Rocha
Si el estatus no existe en Bind, no. Pero ahora sí ya. Sigue tú Johann. ¿Qué Workaround podemos tener? Muchas gracias Noe.
53:54 - Johann
Así es como esta información se jala de Bind. Si no existe en Bind, nosotros habría que agregar una capa extra aquí en el sistema. A lo mejor añadirle o o un campo de estatus o agregárselo aquí.
54:12 - Noe Rocha
Nada más que ahí tendríamos que definir la regla Arturo. Hoy por hoy, ¿cómo se define el estatus de una factura con un estatus diferente en Vine? Para visualizarlo y ponerle esa capa que dice Johann, oye esto no existe en Vine. ¿Cómo lo queremos ver y cuál es la regla para tipificarlo? Para entonces ponerle sobre lo es una capa adicional, es decir, y estas facturas las necesito ver así, pero es una capa arriba de.
54:43 - Araceli Sanchez Jimenez
Si son solo las de Cemex, el único cliente que tiene cadenas productivas, que es Nafinsa y Cemex. Entonces, por ejemplo, cómo es el proceso de Cemex? Cuando un proveedor está dado de alta en cadenas productivas, nosotros vemos todo el proceso y entonces Cemex dice ok, ya está, se pasa a aprobar a pago y lugar de que nos se nos tenga y porque nos paga 120 días lo que hace es pasar esa factura ya autorizada pago a la finza y entonces nosotros en la finza vemos todas las facturas que ya están en firme en pago sí entonces las cadenas productivas bueno no sé si ustedes sepan pero bueno sino cadenas productivas es es un apoyo que se le da a los proveedores porque es decir si Yo necesito bajar ese dinero antes de los 120 días. Yo lo bajo y me cobran un interés respectivo diferente, dependiendo del banco el que yo decida. Verá, entonces al final del día es como una ayuda, un apoyo al proveedor de crisis. Oye, yo no puedo esperar 120 días, lo bajo ahí. Entonces todas las facturas que nos aparecen en la finza ya están en pago en firme. Entonces, pero, están en pago en firme, en Bain a nivel contable, no se registra hasta que cae en la cuenta. Entonces, este dato nosotros ni siquiera si lo compartimos al despacho contable, porque nos va a decir a mí de qué me sirve, o sea, a mí no me des algo que esté en el aire. Pero para nosotros, de manera interna, sí nos sirve, porque entonces sabemos que ya tenemos ahí en firme el pago de dichas facturas, y las que no aparecen en la finza, entonces sí empezamos a correr porque quiere decir que no están autorizadas. Pero nada más pasa eso para CEMEX. De ahí en fuera, para ningún cliente tenemos NAFINSA o cadenas productivas.
56:38 - Noe Rocha
Y ese dato, como nada más para ver y pensarlo con Johann. Estos son los datos de Vine. Y la capa siguiente para ver esto, ¿cómo les serviría o cómo lo ven hoy? ¿Cómo les funciona ver ese dato?
56:55 - Araceli Sanchez Jimenez
y a la mejor nosotros lo podríamos alimentar o manual o por ejemplo nosotros tenemos un portal, un usuario de una contraseña y ahí en ese portal le damos emics, le damos consultar y nos explica todas las facturas con el el cfdi y a cuántos días nos los van a pagar, de hecho nosotros tenemos ahí ya parece el día exacto 4, 3 de agosto, septiembre, entonces este nosotros lo que hacemos por eso le con Artur una capa adicional porque esas no están pendiente de pago o sea si están pendiente de pago pero ya están programadas pero no han caído en la cuenta a fin de cuentas no han caído no han caído entonces nada más yo como lo veo esta pantalla nos dice lo que ya cayó necesitarían otra pantalla para ver lo que está programado para pago cuentas estos son cuentas por cobrar estas son las que no han pagado, o las que no nos han pagado.
57:56 - Noe Rocha
Sí, las que no se han pagado. Esto solamente nos dice si está pagado o no está pagado. Y cuántos días tiene desde que no se ha pagado a la fecha. Como dice aquí, tiene de 1 a 30 días vencidas, de 30 a 60 días vencidas, etc. Esto no nos dice eso, pero no nos dice o no viene, y como no existe en Vine, también es necesario definirlo. ¿Podemos tener una pantalla para ver lo que ya está programado?
58:25 - Arturo Rosas Hernandez
Mi respuesta corta, si me permite interrumpirte, Ara, es sí. Sí, porque en algún momento tenemos que ser preventivos o podemos planear nuestras finanzas a futuro. Y poco a poco pudiéramos hacerlo con los clientes. Yo estoy pensando, me estoy imaginando un futuro Balam, que por cierto, ahí viene otra pregunta porque falta el resto de empresas, pero bueno, ahorita voy a enfocarme con Balam, estoy pensando que vamos a crecer en la cantidad de clientes, en la cantidad de facturación, etcétera, etcétera. Y tal vez esos clientes ya van a empezar a tener portales. O sea, caso Frisa, caso Frisa ya tiene su portal, ya tiene un portal de proveedores. Y entonces, si ya tiene el portal, ya nos va a decir o ya nos va a permitir saber cuándo están programadas nuestras facturas. Como con este, con estos casos que mencionara de ya, ya es seguro, o sea, ya es seguro. Que el 24 de septiembre me va a caer una factura y con eso nosotros podemos planear nuestras finanzas, es decir, si tomo del ahorro o tomo de un préstamo o no considero pago para esa semana o la considero para la siguiente o para ese mes o para el otro mes, o sea, poder planear nuestros pagos porque ahorita estamos siendo reactivos, estamos reaccionando a las necesidades financieras de la empresa Y sí, estamos adelantando en unos cuantos meses en el futuro, pero yo quisiera que pudiéramos adelantarnos un poco más, pero de manera por proceso. Que en algún momento alguien nos diga o una pantalla nos diga cuánto dinero tenemos programado en los siguientes meses y qué podemos hacer con ese dinero con base a la facturación que tenemos, a las cuentas por cobrar, qué tenemos, a los ingresos, etcétera. O sea, una planeación financiera. Y ese es el último toque, la cerecita del pastel, diré yo. Adelante, perdón.
1:00:23 - Noe Rocha
Entonces sería entonces, a mí se me ocurre lo siguiente, muy rápido, nada más antes de perder la idea. A mí se me ocurre lo siguiente, y dígame si les funciona, que de esto, y ya lo veo con Johann, se pueda seleccionar qué factura ya la tenemos por lo menos programada en un portal de algún cliente, este es el que sea, y que manualmente le podamos poner un estatus que diga programada y con la fecha, como para poder decidir mínimo, por lo menos, ya sé que el mes de julio me van a pagar el 50% de las facturas vencidas. Pero yo creo que eso sería para ponerlo en otra pantalla diferente a esta. Esta sería nada más como que, o me pagaste o no me pagaste. Y en la otra, qué es lo que sí tengo programado. No sé si le sirva.
1:01:13 - Araceli Sanchez Jimenez
Oigan, a mí se me ocurre algo. Yo pensando en que cada vez dependamos menos de nosotros. O sea, de nosotros meternos al portal así. También lo que puede hacer es, por ejemplo, que cada 15 días se genere un ticket en Jira automático de checar portal Nafinsa, no sé, desde Jira, ¿no? Entonces, ese checar que diga, oye, ¿sabes qué? Y que pongas un Excel y que a lo mejor se haga un ticket para que se vaya directamente a cuentas por cobrar. Entonces, al menos cada 15 días, porque tampoco es tanta la transaccionalidad que tenemos con SEMED, como para decir, oye, es que hay que checarlo diario, porque, o sea, no. Entonces, a lo mejor cada 15 días que nosotros se genere un ticket en automático, pongamos lo que nos aparezca en Afinsa, el pantallazo, los FDIs, y ya se cierre. Y ese ticket automático lo jalen ustedes y lo meten en cuentas por cobrar. Y puedan hacer el match, si me entiendes, porque es el número de folio. El número de folio que nos aparece en Afinsa es el mismo número de Entonces que tú digas, ah, mira, en Cemex está el follow 100 y está en Afinsa, ah, ok, entonces aquí, en automático, en Afinsa. No me gustaría que quedara tan manual porque se nos va a ir otra vez de las manos.
1:02:35 - Noe Rocha
¿Podría ser eso o no?
1:02:37 - Arturo Rosas Hernandez
Lo veo con Johann.
1:02:39 - Noe Rocha
Bueno. Sí.
1:02:40 - Unidentified Speaker
Gracias.
1:02:40 - Unidentified Speaker
Muy bien.
1:02:41 - Johann
Adelante, Johann.
1:02:42 - Johann
Ok. Entonces. En cada factura se ve el detalle de las facturas. También aquí tenemos consideradas la tolerancia por fees. Por ejemplo, si tienen una diferencia que sea considerada un fee, eso se tendría que configurar. Por ejemplo, si es el 5% o una cantidad así fija de fee por cliente, aquí se configuraría y entraría aquí en pagada pero con tolerancia. Esto es por esta pantalla y en la siguiente pantalla de pagos y recordatorios, aquí es para informar o para ver, por ejemplo, los pagos detectados que han ocurrido últimamente en Bind, por ejemplo, hoy. Y aquí se verían los pagos de las facturas que se han hecho hoy y el resultado que se ha hecho. También aquí vemos algunas reglas de recordatorio. Por ejemplo, todas las alertas por el momento serán internas. Aquí, por ejemplo, si lleva un día vencido de la factura, se le avisará a Arturo. Si lleva 15 días, ya se enviar un mensaje a Araceli y también por el momento no está desarrollado pero podría ser en un proceso posterior de si lleva cinco días se le envía un correo al cliente y a 30 otro correo al cliente.
1:04:26 - Araceli Sanchez Jimenez
¿No está configurado porque no es el alcance?
1:04:30 - Noe Rocha
No está definida la regla todavía.
1:04:34 - Araceli Sanchez Jimenez
Gracias.
1:04:34 - Johann
Y aquí abajito ya aparecerán las alertas internas, que son estas reglas de recordatorio.
1:04:42 - Johann
Entonces, por ejemplo, si estoy aquí como el usuario de Arturo, aquí me aparecerán todas las facturas que tengan más de un día vencidas.
1:04:55 - Araceli Sanchez Jimenez
OK.
1:04:55 - Johann
Y aquí, por ejemplo, esta parte iba para lo de las excepciones de seguimientos está pensado para por ejemplo si había un cliente que no se le quisiera enviar un correo porque era un cliente que ya pagaba pero también esta parte puede no estar ok gracias esto por esta parte y como último este módulo de auditoría Es una bitácora de los movimientos que se han hecho y qué usuario los hizo, a qué hora los hizo. Entonces, de esta forma, por ejemplo, se puede llevar un seguimiento de las facturas que se hicieron, las aprobaciones que se hicieron, las cotizaciones que se vincularon y todas las acciones que se hicieron dentro del sistema. Aquí se puede ver para llevar una transabilidad.
1:05:57 - Araceli Sanchez Jimenez
OK. Me encanta la idea. Sí a todo.
1:06:02 - Noe Rocha
Ahora, este MVP y lo importante de la definición del MVP, qué significa MVP? Y lo vuelvo a repetir, porque ya lo habíamos dicho hace tiempo, pero nada más para no perdernos. El MVP es lo mínimo necesario para operar. Yo sé que ahorita vimos muchos temas, muchos segundos, muchos detalles, pero yo sí los invitaría a decir sí, si el cielo, esto nos funciona para empezar a operar algo el día de hoy, lo ideal sería hacerlo. ¿Por qué? Porque ¿qué pasa? Cuando se le da una revisada a un sistema, empiezan a salir muchos hacegúnes, como ya lo hemos visto. Y en esos hacegúnes empezamos a sumarle, sumarle, sumarle. Y al final de cuentas, cuando llegamos ya al momento de querer operarlo, pues nos damos cuenta de que hay cosas que se empiezan a decir. Ah, ¿sabes qué? Esto no, esto sí, esto lo ocupaba así, esto ya no. Entonces El MVP tiene como propósito salir rápido, operar rápido y descubrir sobre eso lo que, si bien ya documentamos ahorita, cosas que a lo mejor ni siquiera habíamos visto porque no lo estamos operando. Entonces. Hay cosas que sí son de reglas, que sí, definitivamente las tenemos que definir para que queden dentro del sistema. Y hay otras cosas, son como los nice to have. Oye, estaría padre que tuviera esto. Entonces, si los nice to have ahorita, nos impiden o no serían impedimento para poder salir a operar con algo. Yo sí les pediría que hagamos team back, veamos los puntos que mencionamos en esta sesión y digamos qué es nice to have y qué es un must. Si es un must, volver con Johann o Johann, esto es must. Por favor, vamos a quitar, poner, subir, bajar, lo que tengamos que hacer. Y lo que no, podamos empezar a avanzar para que Johann en un tiempo corto nos pueda empezar a dar ya algo operativo. Y lo que sí pasa mucho es que ya cuando sales a operación con algo, ahí es cuando se descubren muchos asegúnes. Muchísimos más de los que estamos viendo ahorita, porque ahorita ni siquiera lo estamos operando, nada más lo estamos viendo.
1:08:12 - Araceli Sanchez Jimenez
¿Sale? Mira, yo tengo la respuesta rápida. La verdad que Johann nos captó absolutamente todo lo indispensable y más o sea a mí me parece fabuloso yo lo único que de mi lado queda es que revisemos el proceso de facturación prefacturación nada más para no hacer si revisamos ese proceso de mi lado está o sea está perfecto porque justo lo como ya habíamos tenido otras sesiones con Johann nos captó súper bien entonces para mí esto se me hace algo súper maravilloso yo de momento no le pondría nada más o sea es como y ya obviamente entiendo que ya después él montaría la IA para pues obviamente ya que nos dé otra analítica y otras cosas. Pero de momento a mí me parece excepcional, o sea, siento que tiene absolutamente todo. ¿Tú qué opinas, Artur?
1:09:00 - Arturo Rosas Hernandez
Sí, la verdad es que lo dijiste muy bien. Yo no le pondría nada más. Incluso el reporteo está muy bueno, que es lo que nos va a permitir dar visibilidad de lo que falta, lo que se hace, lo que no se hace, etcétera, incumplimientos o omisiones. Entonces, yo lo veo bien, como lo dice Noe, lo conecto con el MVP. Sí, esto es lo mínimo que necesitamos y obviamente esto va a ir creciendo con todo esto que dijimos y más porque sabemos cómo somos, ya nos conocemos para que nos invitan. Sí, le podemos agregar muchas cosas porque sí, seguramente hay muchas cosas por mejorar, pero también dependen mucho de nuestros procesos, ¿no? De los procesos, de cómo los estamos creando o cómo lo estamos mejorando día a día. Entonces, yo también lo dejaría así como está. Sobre todo el tema de la facturación. O sea, si el tema de facturación me va a permitir hacerlo en segundos y no en horas o en minutos y no en horas, yo voy y ya estoy de acuerdo. O sea, con que nos reduzca el tiempo que dedicamos a la facturación, que tampoco es mucho. Y al reporteo, está genial.
1:10:12 - Araceli Sanchez Jimenez
Sí, sobre todo como tú dices, yo creo que la consolidación, o sea, el tenerlo, porque vamos de uno a otro, y luego agarras el giri, y luego agarras esto, y luego el vine, y O luego sea, no son sé muchos qué, temas y y luego, luego abrimos el archivo de Excel de la cobranza y luego esto. Entonces, yo creo que aquí y además que tengamos los dos o una sola previsualización. Por ejemplo, yo cuando apruebo cosas me tengo que meter al portal de JIR en aprobación y no sé qué. Y aquí ya está todo consolidado. Entonces, no me tengo que. Y luego, por ejemplo, veo las aprobaciones y porque apruebo no nada más las de administración, sino otras. Entonces, cuando veo la lista de aprobaciones, siempre le doy prioridad a facturación y a pagos. Entonces, yo ando seleccionando. Entonces, aquí ya sé que si yo me meto en el portal, yo nada más priorizo esto, ¿no? O sea, desde un solo dashboard, porque en el Jira, pues, sí, yo tengo que, por los títulos me dejo llevar y, bueno, este sí, ahorita este lo veo y cosas así. Entonces, a mí me parece que todo está bien, nada más hagamos Timback para rechecar el flujo de facturación o prefacturación. Y con eso, Johann, muchas gracias. Creo que, este, le decía, no, de que tú tienes, yo veo que tú tienes, digo, tienes muchas cualidades, pero de la cualidad que tiene que ver con lo laboral y que yo he visto que tienen pocas personas, hablas poco y escuchas muchísimo. Y eso hace que nos entiendas mucho. Generalmente la gente te interrumpe. Mucho entonces yo tú eres o sea yo puedo estar hablando una hora y tú jamás me interrumpes y ya al final que termino oye y ya me haces entonces generalmente las personas que que son así tienen mucha capacidad de de percibir y de de atención y de entender y tú eres una de ellas muchas gracias nos entendiste aquí está el ejemplo y el bebé y el bebé balama ahí está de ejemplo exactamente entonces está perfecto yo la verdad lo veo super bien. Muchas gracias. Pues listo, Johann.
1:12:19 - Noe Rocha
Queda pendiente de nuestro lado nada más una parte de definición del proceso y ya para volver contigo y hacer este MVP ya algo productivo. Que, ojo, nada más Ara y Arturo, vamos a tener que hacer una prueba y esa prueba va a ser muy muy observada, muy segura de lo que sería un flujo normal para la prefacturación. Porque eso ya implicaría ir a escribir sobre Vine, pero eso ya lo haríamos sobre... Ahora sí queda, como dices ahora, bien plenito, ¿no? Bien, paso por paso, valida. Oye, sí está súper seguro de que lo que estamos haciendo esté funcionando y no está afectando a otra cosa.
1:13:07 - Araceli Sanchez Jimenez
Ok, sí, me late.
1:13:08 - Noe Rocha
Ese ya sería el final, ya cuando cuando tengamos toda la fase definida del proceso, antes de hacer un go live del sistema.
1:13:19 - Unidentified Speaker
Ok, perfecto.
1:13:20 - Noe Rocha
Johann, ¿comentarios?
1:13:21 - Johann
Muchas gracias, Arturo, Araceli, por sus palabras, las aprecio mucho. Justamente, me han servido mucho las explicaciones que me han dado. Me han dejado espacio para dudas. Entonces, ha sido muy valiosa la información que me han brindado. También cómo mostraban ejemplos, cómo traían casos que no eran tan comunes también para considerarlos, cómo explicaban el proceso porque lo vio en día a día, fue muy útil y fue muy cómodo para mí trabajarlo y entender qué les iba a servir. Me alegra mucho que esta solución, este MVP, les haya agradado, les haya sido de gusto y vamos a trabajar sobre ello. Entonces, pues, mis siguientes pasos serán ya montar o comenzar con el desarrollo de la parte visual. En ese tiempo, he estado trabajando en la parte que va por detrás. En el backend, sí. He estado trabajando en el cliente de cómo se va a conectar con Bind, en la parte de usuario, en la parte de soportar el multitenant, en la base de datos. Entonces, falta conectar a CloudFrontend y hacer las pruebas que comentan hoy. Entonces, esos, por mi parte, serán los siguientes pasos. Y con mucho gusto de seguir trabajando en este proyecto, en el Bebé Balán, como dicen.
1:14:45 - Araceli Sanchez Jimenez
Ya sé. Muy bien, Johann. Muchas gracias a todos.
1:14:48 - Noe Rocha
Ya tenemos que ir, porque la parte de gira, pues, ya habíamos, tenemos una sesión pendiente con Pedro, ¿no?, para hacer ese Discovery. Sí, es correcto. En un principio, pero ahora, dado la necesidad del proceso, hay que incluirlo. ¿Vale?
1:15:03 - Johann
Vale, ok.
1:15:04 - Araceli Sanchez Jimenez
Bueno, ya está. Gracias, gracias. Feliz viernes y igualmente. Gracias, bye. Bye.
@@ -0,0 +1,362 @@
Kick off-Proyecto integración Balam
Wed, Jul 1, 2026
0:02 - Pedro Alberto Ayala Elizondo
Buenísimo el juego, buenísimo.
0:03 - Unidentified Speaker
¿Lo viste?
0:04 - Unidentified Speaker
Sí, claro.
0:05 - Pedro Alberto Ayala Elizondo
No manches, estaba bien emocionado. Estaba salte y salte.
0:09 - Erika Chavez
Sí, se puso muy bueno. Muy bien, gracias.
1:07 - Unidentified Speaker
No sé si está el link aquí.
1:19 - Unidentified Speaker
No, ni yo.
1:24 - Pedro Alberto Ayala Elizondo
Igual déjame, le mando un mensajito.
1:34 - Pedro Alberto Ayala Elizondo
No, así que se metió en la reunión y salió.
1:39 - Erika Chavez
Hola, buenos días, Johann.
1:40 - Johann
Hola, ¿qué tal? ¿Cómo están? Buenos días.
1:43 - Erika Chavez
Muy bien, ¿y tú?
1:45 - Johann
Buenos días. Buenos días. Muy bien, me alegra. También bien.
1:49 - Erika Chavez
Qué bueno. Qué bueno. Nada más, dame chanza porque creo que el INGE tuvo que pararse. Entonces, déjamelo, mando un mensajito que ya estamos listos, ¿va?
2:00 - Johann
Va, sin problema.
2:19 - Noe Rocha
Buenos días.
2:20 - Erika Chavez
Hola, buenos días, Inge. ¿Me escuchan?
2:23 - Noe Rocha
Sí. A ver, espérame, porque está muteado esto, no quiere hablar.
2:29 - Erika Chavez
Ah, ya.
2:30 - Noe Rocha
Corazón, no los había escuchado.
2:33 - Unidentified Speaker
¿Listo?
2:33 - Noe Rocha
¿Qué tal, Erika, Johann y Pedro? ¿Cómo están? Buenos días.
2:38 - Erika Chavez
Muy bien, gracias.
2:40 - Johann
¿Qué tal, buenos días?
2:42 - Pedro Alberto Ayala Elizondo
Bueno, México.
2:43 - Unidentified Speaker
Bueno, México.
2:44 - Pedro Alberto Ayala Elizondo
Bueno, México.
2:47 - Erika Chavez
¿Quién se fue a festejar?
2:51 - Pedro Alberto Ayala Elizondo
¿Con la familia?
2:53 - Noe Rocha
¿Ya vieron los reels de cómo se puso Ciudad de México?
3:02 - Pedro Alberto Ayala Elizondo
El ángel. Ni una marcha política convoca tanta gente.
3:09 - Noe Rocha
Y de protesta, como un partido mundial. Esos son los intereses de la mayoría de nosotros. Sí.
3:20 - Noe Rocha
Muy bien.
3:21 - Noe Rocha
Oye, Johann, pues gracias. Pues vamos a arrancar ahora sí. La verdad es que tenemos mucha expectativa de esto. Queremos empezar a hacer, ya en menos de seis meses, algo muy robusto con la plataforma. Obviamente, lo que estamos diseñando no es para hacerlo en seis meses es para poquito menos por el tiempo que traemos pero en seis meses nosotros ya tenemos que tener procesos muy robustos dependemos de esta herramienta de muchas cosas y hay una parte muy particular que ahorita quisiera adelantar contigo de lo que esperamos que ya lo establecimos en el PRD pero posiblemente le estemos colgando hasta temas de CRM porque no tenemos CRM entonces hay un tema ahí que más adelante conforme avancemos, vámonos por partes, como dice Chuck, el destripador. Vámonos por partes, resolvemos esto y vamos construyendo lo que para nosotros sería una plataforma integrada de soluciones. Ahora bien, ahorita vamos a entrar a la parte de ley y Discovery, que de ahí se van a definir varias cosas. Tenemos mucha expectativa por también el tema de conciliación, pero sabemos que va a depender de qué tanto te vas a tardar con el discovery en primera instancia, que aquí lo traíamos establecido en el documento. Déjame nomás ponerlo así. Aquí está. Vamos a verlo. Ahí está. Entonces en esta parte de discovery ya se iba a establecer en las horas totales que se iban a ocupar. Probablemente a partir de aquí ya podemos saber si van a ser 112 o 136. ¿Estoy en lo correcto, Johann?
5:06 - Noe Rocha
Sí, así es.
5:08 - Noe Rocha
Para entonces, si se nos adecua el presupuesto actual y las horas como tú las estimas, también te estaremos pidiendo el módulo que viene más abajo, el de conciliación. Porque fíjate, ahorita lo estamos resolviendo de una forma, pero la verdad es que quisiéramos integrarlo. Conciliación, ¿dónde está conciliación? Suelto de cobranza.
5:33 - Johann
Sí, está en el Alexo B.
5:37 - Noe Rocha
Está más abajito. Ya pasé, ¿no? Porque usted habla de cotizado. Ahí está, ¿no? Conciliación bancaria por PDF. Módulo. Ándale.
5:51 - Pedro Alberto Ayala Elizondo
Sí.
5:51 - Noe Rocha
Esta parte de la conciliación es la que nos interesa también resolver. Entonces, ya dependiendo de cómo vaya a salir Discovery, vemos si lo integramos de una vez en esta primera, junto con esto que vas a hacer para avanzar. Porque lo estamos haciendo muy manual y la verdad es que sí nos quita mucho tiempo. Nos quita mucho tiempo y si bien lo estamos resolviendo ahorita con algo de IA, la verdad es que si quisiéramos tenerlo integrado. Pero bueno, entonces, ahora sí, para arrancar, Johann, yo sé que necesitas algunos accesos, algunas visibilidades, platícanos con qué arrancamos para que puedas poner manos a la obra con la parte del discovery, empezar a ver cómo está. Pues ahora sí que ver las tripas del asunto, determinar cosas, evaluar Disculpe que le esté escurriendo tanto, pero no quiero llegar a la parte donde decía el Discovery, ya me pasé. No sé por qué me pierdo en tu cotización. La verdad es que es de las pocas cotizaciones que no alcanza... O sea, está muy bien estructurada, pero por alguna razón no me ubico de repente en las... Ay, bueno. Discovery, Discovery... Aquí está. Muy bien. Entonces, yo sé que necesitas algunos accesos. Recuérdame cómo empezamos para que empieces a tener visibilidad. Los accesos y demás. Inicialmente sería pura visualización, ¿verdad Jovan? No nada de edición, me imagino que por temas ahorita de revisión.
8:02 - Unidentified Speaker
Cuéntame.
8:03 - Johann
Sí, así es. Esta primera etapa pretende descubrir, por ejemplo, qué se puede o qué nos ofrece el API de Bind. Entonces, primeramente, entiendo que necesitaría un token para poder utilizar esta API y poder utilizar, por ejemplo, los endpoints de consulta para saber qué datos son los que exponen los endpoints. Entonces, eso serviría. Además, el paquete de diseño de estilos que tiene BALAM también sería mucho de ayuda para el prototipo. Además...
8:47 - Noe Rocha
Ok, esta gente los da a Pedro y ya los tiene.
8:52 - Johann
Ajá. De acuerdo. Y también sería útil poder tener una llamada con quien hoy lleva el proceso para poder saber cuál es o qué sería útil o cómo es que se podría...
9:07 - Noe Rocha
o cómo organizar el prototipo de manera que sea útil en manera de experiencias Ya, ese sería con Arturo, pero también no hay que dejar fuera, incluir tal vez en esta llamada, yo sé que por el tiempo es muy limitado, pero Araceli, porque el proceso como tal lo conoce mejor ella. Y Arturo, aunque lo conoce, todavía no está en condiciones de definir muchas cosas, porque pues tiene apenas tres meses en la orientación. Sí tendría que ser sí o sí una llamada con Arturo y con Araceli para organizarla.
9:42 - Erika Chavez
Sí, de hecho, Johann, ahí en la facturidad me los pusiste, ¿verdad? Y es que ya traigo lo que son las actividades de la primera etapa en el GAN. Para que vaya viendo, entre esas solamente viene esa sesión con el acercamiento de nuestro equipo con Johann para ese tema.
9:42 - Unidentified Speaker
Ok.
10:07 - Noe Rocha
Ok, entonces aquí traemos el GAN. ¿Qué sería primero?
10:12 - Noe Rocha
¿La sesión de Kikom?
10:14 - Erika Chavez
¿Qué es hoy?
10:15 - Noe Rocha
Etapa 1 y etapa 2. Ok, vamos a salir Discovery.
10:20 - Johann
¿Sesión de Discovery?
10:21 - Unidentified Speaker
¿Dos días es suficiente, Johann?
10:23 - Johann
Sí, bueno, igual las fechas son tentativas.
10:26 - Erika Chavez
Sí, son tentativas. Le puse un aproximado.
10:29 - Noe Rocha
Ok, entonces, sesión de Discovery. Ya que dentro de esa sesión de Discovery, supongo que viene dentro ese entendimiento la sesión con la que tú mencionas, Johann, o viene más abajo? Está adentro? Sí.
10:45 - Erika Chavez
Sí, es el proceso actual, ¿verdad? Sí, es aquí. Ok.
10:50 - Noe Rocha
Y luego viene la entrega de evaluación de accesos. Bien, hay un manual de marca. Ok, eso sí que es como responsable las primeras? Sí. Pues sería Arturo. Y Araceli. En la segunda es Pedro.
11:08 - Pedro Alberto Ayala Elizondo
De ese tema para el API de Bind, actualmente los únicos que tienen cuenta o usuario en Bind es Ara y Arturo. Habíamos acordado que los tokens que usáramos salieran de la cuenta mayor para tener todos los permisos ya habilitados desde un principio.
11:30 - Noe Rocha
Ahí tengo nada más un playas de seguridad y no es tema contigo johan este es como es token no sé si lo que te va a dar también es edición y me preocupa un poquito el tema de cualquier edición este ahí si no estoy seguro pero si es edición o es visualización los tokens tengo entendido que es pura consulta porque así como los tres los como yo lo he usado los endpoints es pura consulta de invoice facturas, pagos, toda esa consulta como tal. Muy bien, entonces tendría que ser uno de la cuenta de Arturo de preferencia. ¿Ahorita los que estás usando son de qué cuentas? ¿De Arturo y de ARA?
12:14 - Pedro Alberto Ayala Elizondo
El que yo uso es el de ARA.
12:18 - Noe Rocha
Ok, muy bien. Vamos a probar con el token de Arturo en inicio para ver si tiene todo lo que necesita ver. Y con eso avanzar con Johann. Sí, porque la particularidad de Bind es que es un token por usuario.
12:35 - Pedro Alberto Ayala Elizondo
No es como una herramienta que puedes generar varios tokens y puedes ganarlos o caducarlos.
12:41 - Noe Rocha
Vamos por el token de Arturo, que no se ha usado, ¿verdad? Todavía. No. Ok. Para que tú dejes el token de Ara en donde está ahorita para el tema de los tablets. Sí. Muy bien. Luego. Validación técnica del API Bind con la cuenta relada, pues sería esa misma de Arturo. Ponle ahí Pedro, Erika. Configuraciones de infraestructura Azure es Pedro y yo, porque Pedro sí tiene limitantes en ciertas cosas, le voy dando permisos. Ahí, este repositorio de SID y gestiones secretas, ¿a qué te refieres, Johann?
13:31 - Johann
Sí, eso sería para después, en la fase 1, en la fase 2, poder montar lo que sería el backend y frontend en este repositorio.
13:44 - Noe Rocha
Y hablamos de un repositorio como tipo GitHub, Ah, sí. Ah, entonces nosotros la creamos.
13:53 - Unidentified Speaker
Ok.
13:53 - Noe Rocha
Sí, entonces ponle ahí, Pedro. Oye, ¿un Github normalito funcionaría o sugerirías otra cosa?
14:00 - Johann
Sí, un Github normal funcionaría. Podríamos tenerlo en privado.
14:05 - Noe Rocha
Ok, entonces ahí, Pedro, también para que lo traigas tú. Y luego, ¿prototipo visual navegable? ¿Ese ya es tuyo, Johann? ¿Supongo? Sí. Y sesión de validación de prototipo ya sería Johann y Balán. Y documentos de hallazgos, ADR, CIPLAN, también otra vez ya sería tuyo, ¿verdad, Johann? Así es.
14:31 - Noe Rocha
Ok, entonces con esto completamos la etapa uno.
14:35 - Noe Rocha
Es la cero. La etapa cero. Ah, la etapa cero. Sí. ¿Cuántos días aproximadamente? ¿Cuántos? Dieciocho días.
14:44 - Erika Chavez
Eh aquí es de ocho días, aprox una semana. Eh dieciocho es entre la cero y la uno.
14:52 - Noe Rocha
Muy bien. Bueno, entonces ahorita hasta aquí lo dejamos con las este responsabilidades y los y las actividades y cada ¿Cuándo vamos a tener sesión Erika?
15:02 - Erika Chavez
Eh pues yo creo que voy a agarrar el mismo corte con los otros chicos para tener el le comentaba a Johann en algunos mensajitos que se había trabajado con Gira, porque aparte del GAN, pues lo poco mucho que a lo mejor sea algo informativo, no meramente un entregable o un documento, pues que me lo suba en el Gira también para la de sus horas. También se va a llevar igual que los otros chicos, ¿verdad Inge?
15:33 - Noe Rocha
Sí, para que quede muy transparente las horas invertidas.
15:37 - Erika Chavez
ahorita voy a poner el documento si con el cámara nada más sería ahorita también bueno si termina Pedro enseñarle cómo se maneja con los demás consultores a Johann para tener la misma línea y entonces voy a tener también avance yo creo que lo que es el lunes para reportar con ustedes a final de semana muy bien digo puede ser a esta hora Johann si no te preocupes o sea yo también me adapto todos los lunes yo tengo sesiones de con los demás consultores, con los demás proyectos de otros clientes que traemos. Entonces, digo, quiero manejar la misma línea para no perderla.
16:16 - Noe Rocha
Igual para los avances que se les da, obviamente, pues, en este caso, a dirección. De acuerdo. Sí. Muy bien. Bueno, pues ahora sí, de nuestro lado quedaría el API y, bueno, primero la sesión. ¿Ya emitiste la factura? No la he emitido.
16:49 - Unidentified Speaker
¿Necesitan que ya la emita?
16:59 - Noe Rocha
programar pago dentro de estos primeros días, o sea, los primeros 30 días que establecimos, pero ya para que vaya corriendo el tema de pago de la primera parte, que es como lo estableciste en el documento. No lo recuerdo, lo dejamos ya abajo, ¿verdad? Recuérdame... O lo manejamos por correo. Lo que era la la primera parte de la facturación, Johann.
17:57 - Pedro Alberto Ayala Elizondo
¿Por correo? Se manejó por correo, Inge.
18:02 - Noe Rocha
Déjame ver si lo encuentro.
18:06 - Pedro Alberto Ayala Elizondo
No, pero si lo adecuamos en la cotización. Creo que es esta propuesta...
18:17 - Johann
es donde adjuntaste la propuesta, ¿no, Johann?
18:22 - Pedro Alberto Ayala Elizondo
viene todo en ese mismo hilo sí a ver, ¿ya lo encontraste, Pedro?
18:31 - Noe Rocha
sí, el logoproyecto sí, el proyecto es lo mejor Bueno, bueno.
19:08 - Johann
Esta parte de aquí, no?
19:11 - Noe Rocha
Sí, pero hablamos de la... No, pero espérame. Había una parte que tú habías manejado como anticipo yo, que es la que trato de ubicar en tu documento, para un momento. Y yo te dije, oye, no manejamos el pero factúrame y ya que vaya corriendo el monto de ese anticipo. No sé si me Es Sí. La O que sea, quiero ubicar en tu documento. ¿Te acuerdas dónde está? Mira, te voy a proyectar.
19:54 - Unidentified Speaker
Nomás para ser muy transparente.
19:57 - Noe Rocha
Aquí está. Es que en alguna parte... Solución... Contexto... Entendimiento... A ver, déjame ver aquí. No sé si es en la página, es 4. A ver si quedó definido ahí.
20:19 - Pedro Alberto Ayala Elizondo
Es que es sin anticipo y pago a 30 días, que es facturo las 30 horas de la etapa 0.
20:36 - Noe Rocha
Sí.
20:36 - Erika Chavez
Dicen el número once. Página once.
20:38 - Noe Rocha
No, en el número once de él es la página catorce.
20:43 - Erika Chavez
Es el punto número cuatro. Bueno, yo lo veo en próximos pasos y lo dice firma del contrato u orden del trabajo, prestación de servicios y confidencialidad, emisión de la factura de etapa cero o inicio de descubre y pago a treinta días naturales y lo arranque del proyecto con la entrega del MVP en seis a siete semanas.
21:07 - Noe Rocha
Esta etapa cero es la que quiero ubicar en tu propuesta, nomás para ser bien claros. La etapa cero está en la...
21:18 - Erika Chavez
¿Dónde habla el monto al facturar de esta etapa cero?
21:23 - Johann
Porque sí la mencionaste.
21:25 - Erika Chavez
Bueno, la etapa cero viene en lo que es la inversión en la... Página 10, viene 0, Discovery, las horas, que son 18 a 22, la inversión y arriba menciona más la etapa 0 con los entregables de la etapa 0. Arriba, arriba, ¿dónde? En la página 6, a menor a bajo, viene etapa 0, Discovery, infraestructura y prototipo visual, semana 1 de 18 a 22 horas o el objetivo y entregables. Validación de la API de Vine, cuenta real si lo encontró en la página 6 y 7 arriba ahí es ahí está parte está para hacer hoy yo ya me perdí explícame cómo estuvo el tema la etapa cero y lo que tú anticipabas o vías como anticipo.
22:32 - Noe Rocha
Porque aquí no lo ubico, que es lo que yo te digo que se va a facturar.
22:41 - Johann
Pero nada más quiero ubicarlo en tu propuesta. ¿Lo explicó? Sí. Sí, esa parte está, como comenta Erika, en la tabla en donde están las facturaciones. En la página 10.
22:57 - Noe Rocha
Ok, entonces, nada más para estar claros, lo que se estaría manejando ahorita como etapa cero, ¿son qué? ¿18 o 22 horas? ¿Cómo lo estableciste? Porque sí me acuerdo que hubo una parte donde mencionabas una inversión de 30 horas iniciales?
23:22 - Unidentified Speaker
Sí.
23:22 - Johann
Sí, eso fue por correo. Son 30 horas iniciales de la etapa 0. Ajá.
23:28 - Noe Rocha
Bueno, que no necesariamente son las 30 horas. Puede ser más o menos, pero digamos que era... Pero eso aquí, ¿dónde lo tenemos para poderlo vincular con la facturación que nos vas a dar? Esa factura que nos vas a generar. No sé si me explico. Tú mencionas una parte donde dice, oye, ¿sabes qué? Para iniciar, creo que es en la página. ¿Sabes qué, Johann? Como recomendación, cuando hables de términos comerciales, déjalo en una sola sección. Porque como está un poco disperso todo, tienes que subir y bajar para entender un poco la parte de... Aquí dice, oye, emisión de la factura la etapa cero. Pero yo me acuerdo que tú mencionabas, me anticipo, que si ya no está mencionado aquí, ¿verdad? Entonces, nada más para estar claros. La emisión de la factura de la etapa cero, ¿por cuántas horas la vamos a facturar ahorita?
24:31 - Johann
Por treinta. Treinta horas. Sí, y esas horas, las que no se...
24:35 - Noe Rocha
Ok, entonces, nada más ayúdame a vincular. Si son treinta horas, ¿dónde dice aquí treinta horas? Yo sé que lo dijimos por pero ¿dónde lo vi con el documento? Porque me van a cuestionar el área de pagos, me van a decir ¿dónde dice que son 30 horas?
24:54 - Johann
¿sí me explico?
24:55 - Noe Rocha
sí, entiendo si viene en el correo, ya lo vi entonces, como no está aquí necesito que sea muy vinculante al tema del pago con lo que dice el documento porque acá, si yo me voy a la etapa aquí dice 18-22. Pero yo recuerdo que si se manejó la versión anterior 30 horas de anticipo. Pero vamos a manejar 30 horas a 30 días de pago. Ah, mira, aquí está. Tarifa, facturación, sin anticipo. Pero mira, se emite la factura de la etapa 0.
25:39 - Johann
De acuerdo, ajusto la tapa cero a que diga 30 horas.
25:44 - Noe Rocha
Ajá. Mejor, en lugar de poner tapa cero, ponle este... ¿Cómo lo manejamos? Ponle... ¿Cómo lo dejamos por correo? A ver, ¿puedes ponerlo, Pedro? ¿Tú que lo traías?
25:56 - Erika Chavez
Mire, yo aquí tengo esa donde viene en el correo, si quieres, Pedro. Es una partecita que dice aquí, sin anticipo y pago a 30 días. De acuerdo, me ajusto a su política, facturo las 30 horas de la etapa cero al inicio y el pago corre a 30 días, igual que los avances. Lo único que pediría para arrancar sin anticipo es dejar firmado el contrato orden de trabajo antes de iniciar. La firma formaliza el compromiso de ambas partes y me permite comenzar de inmediato.
26:30 - Noe Rocha
Mira, aquí el tema es que tenemos que ser muy vinculados lo que dice el documento y lo que se va a facturar porque si no compra me va a decir oye dónde sacas que se tiene que pagar 30 horas a este monto si en la etapa cero el documento dice que son 18 horas entonces si me explico entonces si necesito y nada más eso ayuda a validarlo Erika que lo que el contrato esté vinculado al acuerdo a qué documento está vinculado o cómo está redactado porque entonces lo tendríamos que disculparnos si es mero pero es para para porque así me lo pide el área administrativa. O sea, tiene que ser muy claro. ¿Qué voy a pagar? ¿Con respecto a qué? ¿Y dónde dice que se tiene que pagar eso? Entonces, nos vamos, nos llevamos esto antes de que nos factures, nomás para aclarar cómo lo resolvemos internamente, y si tienes que hacer el ajuste, te lo vamos a pedir ya por de nuevo por correo para que nada más sea muy muy claro en la redacción del del documento, ¿No? Este para que ya factures, porque si nos interesa que ya vaya corriendo el tiempo de estas horas que se establecieron de pago inicial. De acuerdo, sí, sin problema. Ayúdame a revisar eso, Erika, con Pau, cómo lo tienen por contrato. Si no hay algo muy explícito, si ya viene ahí explícito, ya nomás le pedimos entonces a Johann que la propuesta sí mencione que esa para cero va a completar o bueno o ese pago anticipado programado primer pago ya pues no ponerle tapacero porque si le ponemos el tapacero se contrapone con lo que dice arriba primer pago por 30 horas que comprendería tapacero y un cachito de otras horas vale sí entonces ayúdame a revisarlo con pago como lo tienen en el contrato si no está tan vinculado nada más sería entonces vincularlo con johan si está vinculado pues hay que hay que moverlo Ok. Sale para arrancar el tema de pago con Jokan, me refiero. Sí, sí.
28:34 - Unidentified Speaker
Bueno, ¿dudas, comentarios?
28:36 - Unidentified Speaker
Ninguna.
28:37 - Pedro Alberto Ayala Elizondo
Ahorita yo te envío lo que es el template del branding de Balam, Jokan. Si quieres, te lo comparto por correo.
28:49 - Noe Rocha
Muy bien. Ayúdame a organizar la sesión con Ara y con Arturo, con Johann, y ahora sí que avanzar rápidamente con ese tema.
29:03 - Erika Chavez
Sí, ahorita me ajusto para que me pasen sus horas disponibles.
29:10 - Noe Rocha
Bueno, pues buen día a todos, gracias por su tiempo y nos vemos. Gracias. Gracias.
29:19 - Unidentified Speaker
Bye.
@@ -0,0 +1,58 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · coordinación sesión "Proceso actual de facturación y cobranza"
**Canal:** WhatsApp (+52 1 81 2353 5803) · **Fechas:** 12 jul 2026
**Tema:** Confirmación de conexión al kickoff, agendamiento de la sesión de Discovery (proceso de facturación/cobranza) con las personas involucradas, y preparación de agenda/materiales para esa sesión.
---
## Bloque 1 — 1-jul, 7:01 AM — confirmación de conexión al kickoff
> **Erika:** Buenos días johann
> **Erika:** ya estamos en la sesion, te podras conectar?
> **Johann:** Hola buenos días Erika
> **Johann:** Claro, estoy en eso
> **Erika:** gracias :)
*(Corresponde al arranque de la llamada de kickoff — ver `2026-07-01 - Transcript - Kick off-Proyecto integración Balam.txt` y REGISTRO #22.)*
## Bloque 2 — 1-jul, 1:451:46 PM — solicitud de agenda para sesión de proceso
> **Erika:** Hola johan
> **Erika:** disculpa te parece que pueda pedir agenda de las personas invulucradas al proceso de facturacion y cobranza el lunes 06 y martes 07 de julio a las 7 am para ver el proceso?
> **Johann:** Hola Erika
> **Johann:** Sii, sin problema
> **Erika:** va, deja mando correo a ver que me dicen
> **Erika:** gracias te confirmo va
> **Johann:** Vava
## Bloque 3 — 1-jul, 6:096:39 PM — confirmación de la sesión del lunes 6-jul
> **Erika:** hola
> **Erika:** me acaba de confirmar la reunion del lunes 06 a las 7 am va
> **Erika:** ya te mande meet
> **Johann:** Hola, de acuerdo, muchas gracias
> **Erika:** A ti
**Convocatoria recibida (Outlook/Teams):**
- **Título:** "Proceso actual de facturación y cobranza- Balam"
- **Fecha/hora:** lunes 6 jul 2026, 7:008:00 AM
- **Organiza:** Erika Chávez (erika.chavez@balamtalentoestrategico.com)
- **Invitados:** Johann; Araceli Sanchez Jimenez; Arturo Rosas Hernandez (+1 más sin identificar) · **CC:** Noe Rocha
- **Canal:** Microsoft Teams — enviada 1-jul 6:09 PM
> Nota: solo quedó confirmada la sesión del **lunes 6-jul**; no hay evidencia de que se haya agendado la del **martes 7-jul** que Erika mencionó en el Bloque 2.
## Bloque 4 — 2-jul, 4:184:41 PM — preparación de agenda/materiales
> **Erika:** Hola johan
> **Erika:** espero y te encuentres bien
> **Erika:** disculpa, para la sesion del lunes necesitaras algun documento, ejercicio o algo de nosotros para lo que veremos?
> **Erika:** para irles anticipando a las personas
> **Johann:** Hola Erika, todo bien, gracias 🙌
> **Johann:** Espero te encuentres bien también
> **Johann:** Claroo, te comparto los puntos que considero serían útiles:
> - Proceso de facturación en BIND (PDF/XML), incluyendo ejemplos en USD y MXN.
> - Revisión de cobranza y reglas de crédito.
> - Confirmación de la "lista blanca" de clientes (sin recordatorios).
> - Cualquier otro tema operativo que tengan en el radar.
> Y si ya se tienen el token de BIND también sería útil para comenzar con lo técnico
@@ -0,0 +1,46 @@
# Correo — Pedro Ayala → Johann · entrega del token de BIND
**De:** Pedro Alberto Ayala Elizondo (pedro.ayala@balamtalentoestrategico.com)
**Para:** Johann · **CC:** Noe Rocha, Erika Chávez
**Fecha:** lun 6 jul 2026, 12:38 PM
**Adjunto:** `bind_token_api.txt`
---
> Buenas tardes, Johan,
> Espero te encuentres bien.
>
> Te comparto en el archivo adjunto (.txt) el token de Bind que se necesitará para comenzar con la construcción del proyecto.
> Como dato este token fue generado con el usuario **Arturo Rosas**, cualquier duda o comentario podemos validarlo directamente.
>
> Quedo al pendiente si se necesita algo más.
>
> Saludos,
> Pedro Ayala — ITSM Analyst / Consultor de Gestión de Servicios TI
**Respuesta de Erika (12:39 PM, a Johann y Pedro, CC Noe):** "Gracias pedro. Cualquier cosa quedo a sus órdenes. Saludos!"
**Respuesta de Johann (~3:28 PM, a Erika y Pedro, CC Noe):**
> Buenas tardes, Pedro:
> Muchas gracias, recibido el token. Tomo nota de que se generó con el usuario de Arturo, así lo documento.
> Con esto ya puedo comenzar a trabajar con la API. Cualquier duda que me surja se las hago saber, gracias.
> Saludos,
> Johann
---
**Respuesta de Noé (4:33 PM, a Johann y Pedro, CC Erika — ⚠️ importancia alta):**
> Buenas tardes Johan,
>
> Pedro va a revisar si el acceso es de lectura o también de escritura, por lo que te pido mientras tanto **las salvaguardas necesarias para evitar alguna afectación operativa**.
>
> @Pedro Alberto Ayala Elizondo, si es necesario crea un usuario específico de solo lectura en Bind para esta etapa de exploración, si la única forma de dar lectura es crear un nuevo usuario y token adelante; la cuenta de Arturo tiene algunos privilegios elevados que creo que no serían necesario en este momento.
>
> Saludos.
**Notas:**
- Confirma que el token salió del **usuario de Arturo Rosas** — conforme al acuerdo del kickoff (token de Arturo para desarrollo; el de Ara para Power BI). Cierra el pendiente de documentar cuál llave es para qué.
- El token viaja en `.txt` adjunto al correo → pasarlo a **gestor de secretos** y no conservarlo en el buzón/descargas.
- Firma de Pedro revela su rol formal: **ITSM Analyst / Consultor de Gestión de Servicios TI** (coherente con que él construyó el portal Jira ITSM mostrado en el Discovery).
@@ -0,0 +1,87 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · sesión de Discovery + seguimiento del token de BIND
**Canal:** WhatsApp (+52 1 81 2353 5803) · **Fecha:** 6 jul 2026
**Tema:** Coordinación previa a la sesión de Discovery de las 7 am y, después, seguimiento de Erika al pendiente de accesos: pregunta si para BIND solo se necesita "el token tal cual".
---
## Bloque 1 — 6:536:59 AM — previo a la sesión
> **Erika:** Buenos días johan
> **Erika:** como estas?
> **Johann:** Hola Erika, buenos días
> **Johann:** Bien muchas gracias, y tú?
> **Erika:** muy bien gracias :)
> **Erika:** ya listo?
> **Johann:** Listo!
## Bloque 2 — 8:08 AM — cierre posterior a la sesión
> **Erika:** gracias johan
> **Erika:** cualquier cosa me dices
*(La sesión "Proceso actual de facturación y cobranza" se realizó 7:00~8:05 am — ver `2026-07-06 Proceso actual de facturación y cobranz_ Transcript.txt` y REGISTRO #27.)*
## Bloque 3 — 9:019:54 AM — seguimiento al token de BIND
Erika revisa el plan de actividades (línea: **"Entrega y validación de accesos (BIND, Azure, manual de marca) · 2 días · lun 06/07 → mar 07/07"**) y pregunta:
> **Erika:** disculpa johan respecto a este punto solo necesitas el token tal cual?
> **Johann** *(9:53)*: Sii, para BIND solo necesito el token tal cual
> **Johann** *(9:54)*: Lo de azure no me urge hoy y el manual de marca ya lo tengo, gracias:)
## Bloque 4 — 10:2610:37 AM — Erika solicita el token y pregunta por la validación técnica
> **Erika** *(10:26, citando a Johann)*: okey deja lo solicito
> **Erika** *(10:28)*: y sobre esto, se necesita una sesion?
> **Johann** *(10:37)*: No, esa validación la hago yo por mi cuenta ya teniendo el token
> **Erika** *(10:37)*: ah okey
La pregunta de las 10:28 refiere a la línea del plan: **"Validación técnica de la API de BIND con la cuenta real · 2 días · mar 07/07 → mié 08/07"**.
## Bloque 5 — 12:1012:19 PM — token generado; entrega por correo
> **Erika** *(12:10)*: johan ya solicitaran el token ahorita te lo comparto
> **Erika** *(12:10)*: desconozco si tiene vencimiento
> **Erika** *(12:18)*: me comentan que tienen el txt o que como lo necesitas
> **Erika** *(12:19)*: por correo te sirve?
El token ya fue generado dentro de Balam (lo tienen en un .txt); Erika pregunta el formato y ofrece enviarlo por correo. *(Nota: según el kickoff, los tokens de BIND no caducan — 1 por usuario, no caducable.)*
## Bloque 6 — 12:2512:40 PM — token ENTREGADO por correo
> **Johann** *(12:25)*: Sí, por correo y .txt está bien
> **Erika** *(12:25)*: Okey
> **Johann** *(12:27)*: Muchas gracias, comentenme a qué usuario pertenece ese token para poder documentarlo porfavor
> **Erika** *(12:27)*: Okey
> **Erika** *(12:40)*: ya se compartio por correo
> **Erika** *(12:40)*: cualquier cosa me dices
> **Johann** *(2:33)*: De acuerdo, muchas gracias
> **Erika** *(2:33)*: de nada / me avisas cualquier cosa
**Token de BIND entregado por correo (12:40 PM).** Queda pendiente que Balam confirme **a qué usuario pertenece** (Johann lo pidió a las 12:27; Erika quedó en verlo).
## Bloque 7 — 3:013:02 PM — Johann propone sesión de cobranza (martes 7-jul)
> **Johann** *(3:01)*: oye y otra cosa, hoy nos alcanzó el tiempo para facturación y el envío, pero nos faltó ver la parte de cobranza (cómo le dan seguimiento a los pagos y cuentas por cobrar) / ¿Crees que se pueda mañana a las 7am como habías comentado? O cuando se les acomode esta semana
> **Erika** *(3:01)*: Deja revisar la agenda con las personas va
> **Johann** *(3:02)*: Va, muchas gracias
Erika queda en **revisar la agenda** con los involucrados y confirmar.
## Bloque 8 — 4:345:03 PM — salvaguardas sobre el token (eco del correo de Noé)
> **Erika** *(4:34)*: referente a lo del token que se te compartio
> **Erika** *(4:34)*: para evitar complicaciones operativas
> **Johann** *(5:01)*: Hola, listo, por el momento estaré haciendo operaciones solo de lectura
> **Erika** *(5:03)*: gracias por el entendimiento
Erika transmite por WhatsApp, en versión breve, la instrucción que Noé envió por correo a las 4:33 pm (ver REGISTRO #31). Johann confirma de forma informal que ya opera en modo solo-lectura.
## Bloque 9 — 6:366:40 PM — confirma el meet de la sesión de cobranza
> **Erika** *(6:36)*: Listo mande el meet de mañana
> **Erika** *(6:36)*: Si lo recibiste?
> **Johann** *(6:40)*: Listo, ya me llegó
Erika envía la convocatoria de Outlook/Teams **"Proceso actual de cobranza- Balam"**, martes 07/07/2026, 7:008:00 AM. Organiza Erika Chávez; invitados: Johann, Araceli Sánchez Jiménez, Arturo Rosas Hernández (CC: Noé Rocha) — los mismos perfiles que Johann sugirió el 6-jul a las 3:01 pm (bloque 7). Confirma la sesión propuesta en REGISTRO #30.
@@ -0,0 +1,236 @@
Proceso actual de facturación y cobranza- Balam
Mon, Jul 6, 2026
0:07 - Araceli Sanchez Jimenez
Hola, buenos días, ¿Cómo están? Buenos días, bien, gracias. Que bueno, disculpen ahí el minutito de de retraso, pero ya, estoy lista. Ya somos todos, ¿Verdad, Erika, o no?
0:23 - Erika Chavez
Sí, ya, estamos todos, digo, el ingenuo era como opcional, este, pero, pues, los importantes eres tú y Arturo, ¿Va? Este, bueno, este, Johann, pues, ustedes equipo Balam y pues el foro es todo tuyo Johann, ¿sí?
0:41 - Johann
Hola, ¿qué tal? Sí, tenía esta llamada principalmente para ver o si me pudiesen explicar el cómo hoy llevan el proceso de facturación, si me pudiesen mostrar de pronto con un ejercicio de cómo es hoy que realizan una factura, me sería muy útil para saber los Ok, gracias.
1:05 - Araceli Sanchez Jimenez
Si quieres, Arturo, compárteles JIRA y mientras yo te voy diciendo el proceso. Fíjate, Johann, que antes metimos un paso adicional al proceso porque antes no usábamos para facturación JIRA y ahorita tiene como yo creo que dos quincenas o como dos quincenas, ¿no, Arturo? Que empezamos a usar el ITC Entonces, ¿qué pasa? Ahorita que te muestre, nosotros tenemos un portal de servicios dentro de la empresa. Y dentro de ese portal de servicios está, si quieres ahorita que te comparta Arturo, no sé si tú puedes compartir todo el portal. Ándale, sí. Dentro del portal de servicios que nosotros tenemos, hay un módulo que se llama Administración General. Dentro de esa parte, general, pues hay muchas categorías. Entonces, las personas que quieren tramitar, pero aquí vamos a facturación, Arturo, no apago. No, vete al Help Center y debe de estar en facturación, hay un módulo de facturación. Entonces, mira, este es nuestro centro de Entonces, hay diferentes módulos que engloban subtareas o actividades. Dentro del módulo hay un módulo que se llama facturación. Si nosotros le damos clic en ese módulo de facturación, ahí sí se pone, hay dos bajas y facturación adicional. La facturación, ahorita te explico las bajas. La facturación adicional es la persona facturar, que generalmente es la parte comercial, le da clic ahí. Si quieres, dale clic, Arturo. Y tenemos que llenar varios campos. Dentro de ese campo, por ejemplo, aquí ya está impresa origen. ¿Por qué? Porque el ITCM lo utilizamos ya para facturar varias empresas. Entonces, estaba LAMP, Regiotour y Elmstone. En este caso, nos vamos a enfocar a BALAM, ¿sí? Y luego el summary le pones pago, factura o emitir factura, proyecto, le pones el proyecto que identifique a esa factura. Luego tenemos cliente nuevo, ahí seleccionamos sí o no. En caso de que seleccionemos sí, si quieres ¿Sí, Arturo? Nosotros lo que tenemos que hacer es agregar el nombre del cliente y también aquí dice abajo, para cliente nuevo adjuntar la cédula de identificación fiscal y la cotización. Adicional, si son clientes recurrentes, pues solo adjuntar la cotización. Entonces, ya después seleccionamos el tipo de moneda de la factura nosotros nada más facturamos ahorita en dos monedas que es pesos y dólares después que seleccionamos pesos o dólares los días de crédito nosotros de entrada solo damos 30 días de crédito a menos que haya otra negociación son 45 sin embargo tenemos casos especiales como CEMEX, que en teoría nos pagan a 90 días, ¿sí? Ahí no hay manera de negociar, o sea, ellos, eso es, y ya. ¿No? Entonces, este, generalmente aplicamos 30 o 45 días. Después de seleccionar los días de crédito, aquí este, el periodo de incidencias, ¿por qué se puso? Porque como nosotros hacemos Staff Aumentation, hay muchas personas que hacen horas extras, trabajan en domingo, en días festivos, y entonces ahí se ponen todos esos comentarios. O, por ejemplo, generalmente cuando yo levanto una factura de la parte comercial, yo pongo, oigan, ¿saben qué? Este periodo es de la mesa de servicio o una póliza de servicio de 22 de junio al 27 de julio. Por favor, este periodo ponerlo en comentarios, ¿no? Ahí ponemos como más granularidad y si no hay nada que poner, pues nada más le ponemos sin comentarios o no aplica. Y luego también tenemos si la facturación es recurrente, porque generalmente, por ejemplo, el Staff Aumentation nos los contratan a veces por tiempo indefinido, ¿sí? O sea, hay proyectos que sí sabemos que que tienen un término tres, seis, cinco meses, y ahí sí le ponemos la recurrencia exacta. O también hay factura que no necesita recurrencia, que es nada más en una sola exhibición. Entonces, cuando es una facturación recurrente, nosotros ya el equipo de tecnología está trabajando para que las recurrencias en automático se detonen cierto día que nosotros le indiquemos, del día que se necesite facturar. Y ya para finalizar está el periodo de la recurrencia, es decir, si ya sabemos que va a ser un proyecto por seis meses, le ponemos seis para que la recurrencia, la parte de la tecnología, del área de tecnología, sepa cuántos meses va a detonar esa recurrencia, ¿no? Entonces, una vez que ya le damos o alguien levanta este ticket, que ahorita lo levantamos desde cero. Este ticket aparece en la bandeja de entrada de administración, sí, de administración y también tuyo, Arturo, ¿verdad? De los dos, ¿no?
7:26 - Arturo Rosas Hernandez
Sí, correcto. Así es.
7:28 - Araceli Sanchez Jimenez
Entonces, estos ya están preconfigurados, se les asignan a las personas de la Y estas personas lo que hacen es en la bandeja del ticket de Gira, pues hay muchos tickets para facturar. Sí, entonces toda esa lista. Ah, bueno, la vas a hacer, verdad? Pero bueno, mientras te avanzo toda esa lista o no sé si pudiéramos también mostrarles unas que ya facturamos del mes pasado. Entonces se genera una lista, Johann, y sobre toda la lista de factura. Administración, administración hace un doble check, ¿sí? Por ejemplo, que estén todos los datos, la cédula fiscal, el estado de cuenta, o sea, o este, que si hay alguna duda en la descripción o lo que sea, pues ya se toca con el área correspondiente. Entonces, si una vez que nosotros en la lista está todo validado, ahora sí, lo primero que se hace es hacer una siempre hacemos una prefactura y después con esa prefactura que ya está validado, ahora sí ya la facturamos.
8:40 - Arturo Rosas Hernandez
Estos son los tickets, por ejemplo, de facturación adicional. En este caso tenemos dos facturaciones adicionales y una baja, pero bueno, hasta ahorita ya hemos conversado asignados a mí. Básicamente todos los tickets actualmente de facturación adicional tienen una regla para que se asignen a una sola persona, a un solo correo. En su momento era el área de administración y finanzas, pero actualmente es a mí. Entonces, por eso es que todos los tickets por ahora se asignan a mí y por ahora tenemos estas facturas adicionales.
9:25 - Araceli Sanchez Jimenez
Y también explicarte, Johann, que, por ejemplo, nosotros o la persona que necesite facturar se mete al módulo, como te expliqué. Sin embargo, también hay otras maneras indirectas de generar También factura. Nosotros Es utilizamos decir, este ITSM para generar las peticiones cuando hay un nuevo proyecto con un cliente, hay un tema de headhunting, o sea que la parte comercial cierra un tema de headhunting y entonces yo en lugar de mandar un correo, genero un ticket de headhunting. Entonces también así como tú viste el tema de la facturación, llenamos diferente información y esa información le llega a la parte de recursos humanos, en donde le avisan que la parte comercial ya vendió a un tema de headhunting. Entonces la parte de RH lleva todo el proceso y generalmente en el tema de headhunting siempre se genera una factura de anticipo. Entonces cuando yo le doy una factura de anticipo, si quiere a ver, Arturo, ahora pásate a Headhunting. Ese de factura de anticipo levanta un ticket en automático de factura adicional. Sí, mira, tenemos aquí el dashboard de recursos humanos y todos, por ejemplo, este de Headhunting, que hay algunos en que normalmente sí cobra anticipo, pero hay otros que no, Pero independientemente, si yo cobro anticipo, se genera una facturación adicional y cuando se termina o ya tenemos a la persona y el cliente ya la firmó para contratarla a él, en ese momento se genera el 50% del resto de la facturación o el 100%, dependiendo de lo que se haya pactado. Entonces, de Headhunting al final del día detona en un tema de facturación, pero pues obviamente ya no se llenan todos los campos, porque ya se llenaron en el tema de Headhunting. Entonces, este ticket le aparecería asignado, en este caso a Arturo o a la persona que esté en administración, para que se facture. Y es el mismo sistema que utilizamos para Staff Augmentation. Si alguien quiere un ingeniero por una cantidad de meses, la parte comercial debe de levantar un ticket y cuando ya se buscó, se recluta y el personal ya está dando servicio en la oficina del cliente, también se genera un ticket de factura y ese ticket también le aparece a quien tal área correspondiente, que en este caso es administración. No, entonces esa es una y la La última es por proyectos generales, ¿sí? Es decir, yo levanto un ticket con una actividad general. Ah, no, pero ese no, el de proyectos generales nada más es facturación directa. No tenemos un flujo. Y el otro que no nada más esos generan factura, porque el de bajas resta facturación, no lo suma. Sí. Entonces, Pues Johann, estos son nuestros tres maneras de generar factura. Desde el mes pasado ya estamos adoptando la cultura en Balam, que si no hay algo que se levante a través de Jira en un ticket, no se da el servicio de facturación. Entonces sí o sí, si necesitamos que algo se facture en la empresa, debe ser a través de ITCM, siendo pues ya no principal o detonador de base de información y ya después de esto pues ya procedemos a facturar entonces no sé si si haya alguna duda ahorita cómo iniciamos nosotros el proceso para facturar porque pues bueno ya luego te puede ahorita explicar a Arturo luego para facturar nos metemos en el RP y luego el mandar y todo eso pero así es como empieza la de la factura.
13:51 - Johann
OK.
13:52 - Johann
Ya me quedó muy claro cómo es que inicia todo este proceso. Muchas gracias. Me quedó una pregunta acerca de esta parte de llenar el GIRA para iniciar el proceso. ¿Qué departamento lo hace o quién es el usuario quien inicia esto?
14:10 - Araceli Sanchez Jimenez
Soy yo, que es el departamento comercial. En teoría, a lo mejor en un futuro hay más vendedores. Entonces, pronto vendes un producto o servicio, tú tienes que detonar avisando que ya se vendió ese producto. Entonces, siempre es de la parte comercial. Muy pocas veces le pido yo apoyo a Pau para que levante los tickets de headhunting. A veces estoy muy saturada y le explico a ella generalmente a veces el mismo cliente nos pide reclutar más y ella excepcionalmente me ayuda a levantar el ticket, pero el deber ser es que la parte comercial siempre levante el ticket.
15:01 - Unidentified Speaker
Oh, de acuerdo.
15:02 - Johann
Ok, ya me quedó muy claro. Y después de esto, sería de entrar al BindRP y crear la factura, ¿cierto?
15:12 - Johann
Sí, cierto.
15:13 - Araceli Sanchez Jimenez
Si quieres, Arturo, te cedo la palabra, te dejo ese proceso que Arturo es quien lo domina.
15:21 - Arturo Rosas Hernandez
De acuerdo, aquí previo, no sé qué tanto convenga que dentro de cada ticket también hay un flujo de subprocesos dentro del proceso macro de facturación. Hay actividades que hay que ir cumpliendo y tienen sus tiempos, tienen sus SLA medibles evitar que el ticket o el pendiente se quede sin atender de manera indefinida. Entonces, solo voy a mostrarte el flujo, por ejemplo, de este último. Está así macro, es un poco difícil de leer, a veces pero tenemos desde que se crea y en cada subproceso hay tiempos que se deben cumplir. Entonces, se abre la solicitud y una vez que se abre, pasa al proceso de facturación. En caso de que en el proceso de facturación hay alguna validación que no se esté cumpliendo, podemos pasarlo en espera del colaborador o pasarlo o al recuesta cancelado. Si en el proceso de facturación se decide que debemos avanzarlo, incluimos un PDF y un XML forzosamente como evidencia de que la factura debe avanzar y se corre una pequeña validación. Esa validación requiere un botón para autorizar, digamos, para avanzar o no avanzar en el proceso. Y una vez que se da o que se acepta el ticket o la factura y se revisa que en realidad hay un PDF y un XML y una factura como tal a un cliente, pues se pasa en proceso facturado. Hay un proceso alterno, que es el de facturación extranjera, que ese no necesita un XML, solo requiere una invoice, en este caso, que es solo un PDF. Entonces, en esos casos se hace una validación extranjera o la estamos filtrando como validación extranjera. Y en esa validación extranjera solo debe haber un PDF como tal, como evidencia de la factura. Entonces, este es nuestro pequeño diagrama de flujo. Son los subprocesos que en el proceso de facturación general estamos siguiendo. Y ahí, pues bueno, con esto tenemos la intención de que no se queden ahí pendientes todo el tiempo. Una vez que ya dice proceso de validación o facturado, ahí sí ya entramos a esta herramienta que se llama Vine. Y era por eso que mencionaba la parte de flujo, para entender desde dónde venimos, ya lo comentó muy bien Ara. Sin embargo, creía que era importante, o creo que más o menos entender qué pasos debemos seguir dentro del ticket abierto. Disculpa, ¿podrías repetir los últimos segundos?
18:37 - Johann
Es que se trabó un poquito. Se me trabó. OK.
18:42 - Arturo Rosas Hernandez
Decía que al final me parece importante mencionar el tema del flujo y que vieras cómo tenemos nuestros flujos de A, B, C, hasta que la facturación sea más dice status facturado, porque este flujo conecta con el uso de la herramienta Vine, que ahorita estás viendo en mi pantalla. Por eso me parecía que era importante, porque en algún momento si automatizamos ciertos aspectos, estos botones, estas aprobaciones, estas fases de flujo de facturación general, servir para continuar en el proceso y para que tal vez los agentes pudieran llegar a esta fase del uso de la herramienta Bain, que es aquí justo donde realmente se generan las facturas, ¿no? Alantera. Gracias. ¿Sabes qué, Johann?
19:43 - Araceli Sanchez Jimenez
Y también, a lo mejor me arranqué muy pronto, pero como cuando dicen, oye, ¿y tú por qué estás viniendo al doctor? Te vamos a decir, te voy a decir cuáles son nuestros dolores y algunos cuáles fueron, que de cierta manera ya los estamos mitigando. Como te digo, tenemos muy poco tiempo, o sea, dos quincenas o máximo, yo creo que máximo dos quincenas, haciendo mandato que todo lo que se facture sea a través del ITCM, también porque este proceso no estaba. También hay muchos procesos que estamos apenas implementando y estamos mejorando con base a lo que lo estamos usando en la empresa. Entonces, el principal dolor que era es que había muchos errores en la facturación, porque como no había un control, la persona que llevaba la administración a lo mejor tenía un Excel, ¿sí? Y entonces en ese Excel a veces no se le notificaba que se había vendido otro proyecto, otro headhunting, otro staff. Entonces de repente a los dos o tres meses nos dábamos cuenta que no se había facturado lo del mes de enero, ¿no? O ella a lo mejor había entendido que era en otra moneda y facturaba en otra. Entonces teníamos procesos desde el arranque muy manuales, ¿sí? Y dependíamos de que esta persona tuviera actualizado el Excel. Entonces, ¿ya qué hicimos? Pues abordar, desarrollar el flujo de ITCM para que no sea un supuesto y que se nos pierdan en correos o si la persona no leyó el correo de administración o se le olvidó ponerlo para facturar, pues ya, ¿no? Entonces, ese tema ya lo abordamos con el tema de JIRA, porque todo tiene que estar aquí en JIRA. Pero el otro tema también que queremos es, aunque es un proceso que ahorita te va a enseñar este Arturo, sencillo, no complicado, sigue siendo un proceso manual y todos los procesos manuales generan errores. Entonces, nosotros qué queremos, pues mitigar ese error en las facturas, en los montos, en las descripciones y también adicional, Como ya estamos sumando más empresas, digo, ahorita lo vamos a dejar en Balam, pero lo que nos gustaría es que se facturara también para las demás empresas. Entonces, pues definitivamente tampoco el objetivo yo como dirección general es engrosar la nómina para nada más tener más gente que capture, sino la propia IA que aguanta mucha carga de trabajo, que la verdad tampoco es de que facturamos muchísimo, o sea, yo creo que máximo facturamos 55 facturas al mes en promedio. Entonces, realmente el volumen es muy poco, pero más de ayer el volumen es la incidencia, que todo el tema es manual, que nos podemos equivocar y que nosotros estamos en un francocrecimiento y yo quiero enfocar a los recursos en actividades que me genere más valor que la facturación. Entonces, ese es lo que nosotros queremos atacar. Y además de que obviamente tengamos el reporteo de cuánto se facturó esa granularidad, que de cierta manera ya la podemos tener porque tenemos Power BI. Pero si necesitamos esa independencia de que a lo mejor nada más la persona de administración valide que las facturas estén bien antes de ser mandadas a Entonces, ese es como el dolor o los dolores principales que queremos atacar con esta automatización. OK, entiendo.
23:36 - Johann
Esta parte de automatización sucedería en esta parte en la que estamos ahorita en este paso de Vine RP. Ahorita, con el paso que me mencionan, que ahorita es mandatorio de llevar las facturaciones, por Gira, ya solucionaron el dolor de tener las facturas en orden, ¿cierto? Sí. Y ahora, en esta parte, en la que me mencionas que lo que quieres que haga los agentes o que se automatice, es después de esta parte de Gira, ¿cierto?
24:12 - Araceli Sanchez Jimenez
Sí, cierto. OK.
24:13 - Unidentified Speaker
Correcto.
24:14 - Arturo Rosas Hernandez
Es exactamente así como lo dijiste, Johann. Creo que lo estás entendiendo muy bien. Aparte, ahora lo está explicando de manera excelente. Sin embargo, es importante entender cómo se conectaría con Jira, ¿no? O sea, este botón de aceptar, este botón de proceso, este botón de validación, deberían de los, o bueno, yo creería que pudiera ser de mucha utilidad el que los agentes estén observando hacia Jira para saber en qué momento accionar, ¿no? Seguramente ya tú nos dirás si es correcto lo que menciono, ¿no? Una vez que ingreso mis credenciales en esta herramienta que se llama Bind, que es la que nos sirve para facturar y para dar seguimiento a las cuentas por cobrar y las cuentas por pagar, aparece esta pantalla, esta pantalla de inicio. Y una vez que estoy en esta pantalla de inicio, ingreso al área de finanzas, al módulo de finanzas y al módulo de cuentas por cobrar. Una vez que genero o que selecciono cuentas por cobrar, me aparece todo el listado de facturación que tengo. Ahí lo puedo consultar. Sin embargo, cuando tengo que generar una venta, es decir, una factura nueva, tengo que venirme aquí al módulo de ventas y en el módulo de ventas ingresar al módulo de Aquí es donde voy a generar en realidad los datos de la facturación o los datos que me estén poniendo en el ticket. Desde el proveedor, el monto, la descripción, la cantidad de horas, el precio unitario, etcétera. Aquí es donde lo voy a llenar. Tal vez necesitaríamos más tiempo para correr el proceso completo, pero en este caso vamos a partir de que ya está generado el proveedor, de que ya tiene cuentas configuradas, de que ya tiene su moneda configurada, etc. Hay ciertos prerequisitos que ya están previamente cargados. Entonces, ahorita vamos a partir de que ya tiene estos prerequisitos cumplidos. Sin embargo, en el tema de la automatización, ¿qué va a suceder cuando no haya estos requisitos cargados? Habrá que definir cuáles proceso y ese sería otro proceso completamente diferente de qué hacer cuando el proveedor no esté dado de alta. Entonces, aquí elijo la opción del documento que voy a generar. Como bien decía Ara ahí en la explicación que nos dio, normalmente ahora estamos generando prefacturas. Esta prefacturación nos está permitiendo poder corregir en nuestro proceso de revisiones, corregir datos que no son precisos, desde la descripción, desde la cantidad, desde el precio unitario, desde los datos del proveedor, la moneda, los días de crédito, etcétera. Entonces, en este caso voy a hacer una prefactura, como decía...
27:27 - Araceli Sanchez Jimenez
Y nada más, perdón, Arturo, para profundizar, te voy a decir, Johann, a lo mejor tú sabes, pero para no obviar, ¿por qué hacemos una factura, porque la prefactura no la timbramos ante el SAT, y si nosotros nos vamos directamente a una factura y está mal, tenemos que cancelarla, ese timbre se cancela también del SAT, y administrativamente y contablemente es un retrabajo. Entonces, lo que hacemos es hacer la prefactura, no tiene ninguna validez oficial, pero para nosotros nos ayuda a hacer un último es muy visual, queda como muy limpio. Entonces, ya con la prefactura, nos volvemos a hacer un doble check, que efectivamente ya cuando esté el timbrado, pues ya va a estar todo en orden, ¿no?
28:22 - Arturo Rosas Hernandez
Por eso es. Correcto. Una vez que tenemos definida el tipo de documento, seleccionamos el cliente, en este caso vamos a utilizar a Kuntia. Una vez que tenemos seleccionado el proveedor, Revisamos la matriz. Aquí nos permite seleccionar diferentes sucursales. Esto pudiera servir para decir o configurar si Balam tuviera varias sucursales como Puebla o México, Yucatán, etcétera. Si en algún momento tuviera otra sucursal y nosotros quisiéramos estar monitoreando la cantidad o la facturación de cada unidad de negocio, Bueno, podríamos nosotros configurar previamente y una vez que esté configurado previamente, aquí es donde elegiríamos la ubicación que queremos, desde donde queremos facturar. Obviamente, como mencionaba, tenemos las opciones de la moneda. En este caso es pesos y dólares principalmente. Sin embargo, hay más monedas disponibles en la herramienta. Por ahora no las utilizamos, solamente facturamos en pesos y dólares. No sé si ibas a comentar algo, tal vez me adelanté.
29:38 - Araceli Sanchez Jimenez
No. Oye, es que ahorita también que me estoy acordando es, eh, mira, Johann, eh, el deber ser que todavía no lo hacemos al cien por ciento es que, eh, por ejemplo, el área comercial, todo el jeton tiene esta fomentation y todo lo demás. El deber ser es que genero una cotización en este sistema, en el ERP. ¿sí? ¿Por qué me regreso? Porque cuando hay una cotización, desde la cotización se pueden convertir, no sé si a prefactura o a factura directamente, Arturo, no sé si haya la opción de prefactura.
30:20 - Arturo Rosas Hernandez
Lo que yo sé es que las dos, como tú decidas.
30:24 - Araceli Sanchez Jimenez
Sí. Y entonces, por ejemplo, si si viene la cotización ya desde generada desde el área comercial a la parte de administración y ahorraríamos todo esto, no para los los temas recurrentes, en la recurrencia, pues sí tendrían que hacer esto, ¿verdad? Para que no todos los meses la parte comercial esté, esté levantando la recurrencia de que vendió hace un año, ¿no? Pero para, para el Headhunting o esta Fomentation o cualquier proyecto nuevo, el deber ser es que se emita una cotización. Y entonces tú cuando ya levantes el ticket de que quieres facturar, anexas la cotización de, del RP. Entonces esa cotización, la cotización, lo que haría administración o el agente para no hacer esto uno por uno, busca la cotización, le da clic, es nada más un clic, lo convierte en prefactura y esa prefactura se manda a una validación humana, ¿verdad? Entonces, ese proceso lo tenemos que, si así, hacer mandatorio. Entonces, pero todavía no, no lo hacemos. Entonces, que normalmente pasa es lo que Arturo te está diciendo. Sin embargo, sí te lo menciono porque sí me gustaría no tener como demasiadas aristas desde donde atacar el tema y decir, sabes que sí o sí debe haber una cotización. Y entonces si hay una cotización, pues también se vuelve más efectivo porque todo este tema ya no se tendría que llenar a menos que fuera una recurrencia, o sea, dentro de las recurrencias ahí sí no te salvas, ¿verdad? Porque ya la recurrencia, quien se encarga de facturarlo es administración y no la recurrencia la levanta la parte comercial. Correcto.
32:21 - Arturo Rosas Hernandez
Sí, definitivamente es una necesidad que seguramente vamos a estar atacando en el corto tiempo por el beneficio del proceso. Al final de cuentas, es un proceso muy robusto ya actualmente. Entonces, eso nos va a permitir también ver más áreas de oportunidad y áreas de mejora. Entonces, una de ellas es definitivamente la cotización. Entonces, continuamos con los días de crédito. Esta parte es manual, es totalmente manual. También se define como prerequisito. Una vez que configuras el proveedor, tú defines cuál es el plazo de pago. Sin embargo, es editable aquí. Aquí puedo ponerle 30. Puedo ponerle 45 o 90. Sin embargo, pues normalmente lo dejamos en el default. La cuenta aquí podemos, si tenemos contablemente una cuenta contable o alguna cuenta de gastos que nosotros querramos afectar, bueno, se puede hacer. Por el momento no lo estamos utilizando como tal. Y lo mismo que dice ARA en el caso de adicional de las cotizaciones, podríamos tener una orden de compra asociada ya del proveedor. Pues bueno, aquí es el campo en donde pudiéramos estar poniendo esa orden de compra generada por el proveedor, porque en teoría en el proceso de facturación deberíamos de tener como prerequisito una orden de compra autorizada por el proveedor para nosotros arrancarnos a facturar. Y justo lo que comentaba previo al tema de SAT, pues no caer en ese retrabajo de cancelar una factura porque el proveedor dijo que la orden de compra ya no va o se modifica o es diferente a lo que habíamos acordado tal vez en manera inicial. Entonces aquí se puede definir esa parte. Tenemos varios usos de CFDI. Principalmente utilizamos los gastos en general y el de sin efectos fiscales. Es principal, digo, podemos utilizar cualquiera, pero principalmente utilizamos gastos en general para todos nuestros servicios o para la mayoría de nuestros servicios y sin para perdón para facturación mexicana o para facturación que va a tener un pdf y un xml que debe cumplir con las reglas y condiciones ante el fisco en México. Utilizamos gastos en general en la mayoría de los casos, sus excepciones y sin efectos fiscales para todas las facturaciones extranjeras. Todas las facturaciones extranjeras que no deben de cumplir, por decirlo de alguna manera, las normativas mexicanas, que generan solamente una invoice como tal, estamos eligiendo sin efectos fiscales. El método de pago también básicamente es PPD y PUE. Para PUE es los pagos que te hacen en efectivo o en el momento, con transferencia, pero que solo en ese instante, en ese momento, tal vez con una terminal, tal vez en efectivo, en ese momento, que no cambian de día, tiene que ser en el mismo día, pues bueno, elegimos la opción PUE, perdón. Si es PPD, que es Pago Diferido en Particialidades, si no mal recuerdo, elegimos esta opción para cuando el proveedor nos va a pagar días después, ¿no? Como este es el caso, en este ejemplo vamos a utilizar de 45 días. Después de un día, ya aplica PPD por temas de fisco y temas de cumplimiento normativo. Una vez que pasamos el método de pagos, llegamos a la parte del concepto. En este concepto ya tenemos algunos conceptos precargados. Sin embargo, esos conceptos precargados son editables. Entonces, voy a elegir, por ejemplo, de consultoría y servicio, que es el que he visto que hemos utilizado más veces, es el 029. Una vez que generas, que tienes el código 029, el concepto ya viene lleno, ¿no? Este puede servir para recurrencias o para nuevos, como base, ¿no? Entonces, imagínate que es consultoría y servicios, está aumentación, julio, 2026. Si normalmente ahora estoy sugiriendo poner el nombre del recurso o del servicio específico, entonces aquí pudiéramos poner el nombre de la persona. Voy a poner mi nombre.
36:57 - Unidentified Speaker
Y el costo, ¿no?
36:58 - Arturo Rosas Hernandez
Aquí pueden ser 10, 20, 15 pesos, lo que sea. Ya viene, una vez que se llena este dato, en automático se guarda. No hay un botón de guardado ni nada. Simplemente cuando sales de la casilla, ya está guardado el dato. Por ahora no hay que darle guarda para que este renglón, digamos, se respete. Podemos agregar n cantidad de servicios.
37:31 - Unidentified Speaker
Siempre tratando de seguir la misma estructura.
37:35 - Arturo Rosas Hernandez
Lo mismo, 2026, es decir que aquí es él. Ejemplo. Y a lo mejor aquí son 20 pesos. Ok. Como decía, aquí ya viene precargar la dirección fiscal del cliente. Este no cambia, no podemos poner varias direcciones fiscales, seleccionar, perdón, pero sí podemos configurar varias direcciones fiscales. Sobre todo si el proveedor tiene diferentes RFCs, sobre todo. Sin embargo, serían proveedores diferentes, pero en este caso la dirección fiscal es esta. Podemos agregar comentarios. Estos comentarios vienen también de las incidencias sobre el ticket. Si ellos están comentando algo adicional, aquí podemos poner el nombre del ticket. Aquí podemos poner de la descripción del ticket en general, como para hacerlo coincidir en los reportes que pudieran estar generando. Después de generar la factura, obviamente vamos a llegar al módulo de cuentas por cobrar, que fue el primero que les quise mostrar, porque en ese cuentas por cobrar vamos a ver las facturas que están en proceso y las que están vencidas, las que están pagadas, las que no se han pagado, etcétera, para poder dar seguimiento a todos los pagos de nuestras facturas. Entonces aquí en los comentarios pudiera servir para poner el dato del ticket que estamos generando. En este ejemplo tenemos la opción de descuento. Hasta ahorita no he utilizado el módulo. No he visto que en facturas anteriores se utilice. Sin embargo, está la opción también de de venir con base en la información que se designe, ya sea en la cotización, en la orden de compra y o en el ticket. También tenemos el apartado del IVA. Ya que somos una empresa de reclutamiento, algunas veces nuestros IVA son diferentes. No solamente facturamos el IVA, sino el ICR o alguna retracción de impuestos, etcétera. Bueno, pues aquí podemos seleccionar ¿Podemos usar la opción de notificar vía correo electrónico? Actualmente, adelante.
40:09 - Araceli Sanchez Jimenez
Arturo, yo una duda que tengo que es como con respecto al funcionamiento del ERP. Este, por ejemplo, nosotros, el grueso de nuestra facturación es hacia una empresa extranjera. Entonces, este, se hace sin efectos fiscales. Eso no quiere decir que no se timbre ante el SAT. Eso quiere decir que a esas personas o a esa empresa no le cobramos el IVA. O sea, sale con el cero por ciento. Entonces, mi pregunta, Arturo, es aquí. Si tú en Bind le pones sin efectos fiscales, en automático el IVA te lo pone en cero, ¿verdad?
40:48 - Arturo Rosas Hernandez
En algunas ocasiones debería, o sea, diría que sí. Sin embargo, en este ejemplo, por alguna razón, lo puse en cero, lo puse en 16.
40:58 - Araceli Sanchez Jimenez
Sí, nada más para que también la gente no asuma. Y en este caso, siempre que son sin efectos fiscales, efectos fiscales o que es en una moneda extranjera es con cero ¿verdad? Y siempre que sea en pesos debe de llevar el el dieciséis por ciento ¿verdad? Nada más para hacerle un doble check porque pensé que yo también porque dije ay qué raro si lo agarraste con efectos fiscales yo debería yo asumí que pues el el RPN automático le quitaba el IVA pero bueno no es así y tenemos dos opciones de facturación PPD y PUE, nosotros siempre damos crédito, entonces la manera o la forma del negocio, nosotros no cobramos nada con terminal, todo es con transferencia, entonces el PUE pues se utiliza casi nunca, a menos luego los que sí nos pasa y son las excepciones antes del cierre del año, que los clientes les urge pagarte y es de que mándame ya la factura y ahorita mismo te hago el depósito. Pero esas son ocasiones ya pactadas, acordadas en el tema comercial. Pero de base nunca utilizamos PUE, ¿verdad? Porque también si uno selecciona PUE en lugar de PPD y te pagan al crédito, el SAT tienes un incumplimiento y también son cuestiones graves. Entonces, sí es muy delicado escoger PPD o PUE Por ejemplo, ¿por qué? Porque te digo, porque tuvimos un error hace dos años, que la parte de administración no puso atención en esta selección y ponía PUE, y tuvimos un requerimiento del SAT. Sí, entonces sí es un tema muy delicado, porque el SAT está asumiendo que te tiene que caer esto en ese mes, y entonces tú estás incumpliendo en los impuestos, porque pusiste que te cayó y tú estás registrando el pago en otro mes. Entonces, sí hay que poner ahí una nota, porque sí tuvimos un tema ahí con el SAT por no haber elegido bien el PPD o el PUE.
43:12 - Arturo Rosas Hernandez
Correcto. Y adicional, pues recordar que también las facturas PUE exigen que haya un complemento de pago timbrado en ese día, porque también es un timbrado, no es un complemento de pago, una hoja cualquiera. Sino también es un timbrado que notifica al SAT que hubo un ingreso o que hubo una factura pagada ese mismo día, y ahí hace coincidir, una vez que coincide la factura con el complemento, dice, ah, está bien, ya se subsanó, está correcto. En el caso de que haya un error, si la factura es PUE y el cliente no genera complemento de pago en un incumplimiento, y si así sucede varias ocasiones, es más o menos normal que el SAT venga a revisar qué está pasando, porque alguien está diciendo que está recibiendo diario dinero. Sin embargo, no hay complementos de pagos del cliente. El cliente no está emitiendo nada. Entonces, ahí hay un incumplimiento. Entonces, qué bueno que lo mencionara, porque sí es un tema muy, muy, muy delicado, muy importante. Y te detiene la operación de facturación y la operación de una empresa de más o detalles de este tipo que no se entiendan de manera correcta. Entonces, sí, qué bueno que lo mencionó. Qué bueno que también lo mencionamos nosotros. PUE en pocas ocasiones se puede dejar como opcional. El grueso está en PPD. Sin embargo, si en algún momento se genera PUE, pues sí entender que tenemos que sí o sí en ese mismo día perseguir el complemento de pago para que es como la evidencia para cerrar el proceso de un método de pago PUE. Ok, entonces estábamos en la parte del IVA, la opción para, como decía, para usos de CFDI sin efectos fiscales, como este ejemplo, es 0% y después simplemente damos guardar. No sé si quieren que haga el ejercicio, pero básicamente no hace más que generar la factura como tal y ya se genera un PDF, ya lo puedes descargar, etcétera, lo puedes revisar, evaluar y después ya timbrar. ¿Quieren que hagamos el ejercicio? Digo, es básicamente sin efectos.
45:30 - Unidentified Speaker
¿Lo hacemos, Johann?
45:32 - Unidentified Speaker
¿Te parece bien?
45:34 - Arturo Rosas Hernandez
Sí, si no hay problema de timbrado o algo así, me serviría.
45:42 - Johann
Sí, no, no hay problema.
45:45 - Arturo Rosas Hernandez
Ahorita solo lo voy a a eliminar, una vez que le de guardar.
45:52 - Arturo Rosas Hernandez
Ahí está.
45:52 - Arturo Rosas Hernandez
Esto es lo que hace toda la prefactura. Y una vez que se genera la prefactura, se habilitan todos estos módulos en los que puedes emitir un CFDI, que este es el principal, ¿no? Es el que comentaba Ara. Una vez que validas todos los datos, quien lo capturó, la dirección, los días de crédito, el tema de PPD que ya vimos que es muy importante, que la descripción de los servicios es correcta, que la cantidad, el precio unitario, el descuento, el deporte, el IVAE son correctos. Una vez que se revisan todos estos datos, podemos emitir el CFDI. Este sí no lo puedo hacer porque se timbraría una factura y después tendría que cancelarla, pero esa sí tiene efecto. Entonces, esa parte no. También podemos registrar el pago de una prefactura. Obviamente, una prefactura no tiene un pago como tal. Sería extraño. Lo que sí tendría un registro de pago es un CFDI timbrado. Sin embargo, aquí está la opción. Podemos agregar una nota de crédito, es decir, asociar una cancelación o una devolución del importe de la prefactura o de la factura sobre todo estas son opciones de una factura que nos sirven para cuando una factura ya fue timbrada. Nos permite editar, obviamente una vez que corremos nuestro proceso de validación y si encontramos una deficiencia o un área de oportunidad, pues bueno, obviamente tenemos la opción de editar. Esta parte es importante porque seguramente la vamos a usar en cantidad de veces. Actualmente estamos tomando la parte de la facturación, hemos encontrado muchas áreas de mejora, sobre todo en esta parte de las recurrencias, facturas que se están emitiendo mes a mes. Estamos encontrando cosas que se pueden mejorar desde el nombre, desde la descripción, desde el puesto, etcétera. Entonces estamos mejorando lo mes a mes. Podemos copiarla, es decir, de esta misma prefactura yo puedo generar otra prefactura idéntica y o en las recurrencias es lo que hacemos y modificar lo que sea modificable. Podemos obviamente cancelar que en un momento la voy a cancelar sí o sí. Podemos exportar las partidas en una tableta en Excel, por si necesitamos el dato por algún motivo. Podemos enviar esta prefactura vía e-mail. Este envío por e-mail es a los correos que están configurados previamente en la cuenta de proveedor. Podemos descargar el PDF. Este te permite tener un documento PDF con todas estas características. Podemos descargar un tipo de hoja de salida por si tuviéramos un proceso de abasto, un almacén físico o un proceso de logística. Pues bueno, esta hojita de salida es la que nos permitiría extraer el material. En este caso son servicios, pues no, no aplica. Imprimir un ticket y ver la póliza contable. Entonces, Estos son dos módulos que son de poca utilidad, sin embargo, ahí están disponibles y solamente los menciono si es necesario considerarlos, para que sepa que se tienen en esta herramienta. Hasta aquí es la parte de la prefactura. Obviamente, el siguiente paso, como decía, es emitir el CFDI. Y una vez que se mete el CFDI, vienen todas estas mismas opciones, exactamente las mismas opciones. Simplemente es como si viéramos este título, esta titular y estas descripciones, pero solamente que aquí va a decir Facture. Es la única diferencia y esa ya tiene efectos fiscales. Entonces, una vez que yo dé clic en el botón de emitirse FDI, cambia a Facture, este prefijo, y se emite y tengo exactamente las mismas opciones. Ok, Johann, no sé si hasta aquí hay alguna duda, ¿Hay información suficiente, relevante? Dime, amigo. OK, entiendo. También tenía una pregunta.
50:14 - Johann
Bueno, de pronto es lo de la lista blanca. Recuerdo que habían comentado que había clientes a los que sí querían que les llegaran los correos y a clientes a los que no. Pero antes de continuar por esa parte, me comentaban que el reverser era comenzar con una cotización. Entonces, ¿les gustaría que después de lo de Gira, aterrizara aquí a Bind como una cotización y después seguir el flujo de prefactura y factura?
50:51 - Araceli Sanchez Jimenez
Sí, la verdad que yo creo que sí, o sea, debería de ser, un deber ser, a menos que Porque, por ejemplo, la cotización, yo o el área comercial tiene acceso a ciertos módulos y, por ejemplo, es nada más levanta la cotización. Pero en caso de que fuera cliente nuevo, sí sería mandatorio que corriera un proceso de gira para que la parte de administración que tiene el privilegio de dar de alta a los proveedores, FDI, todo eso levantara al cliente, para que una vez que tú levantes el cliente, pues, al área comercial le aparezca. Porque cuando yo levanto una cotización, si quieres, Arturo, me puedes mostrar, por favor, te vas a ventas y luego cotización. Ándale. Porque aquí, por ejemplo, yo le pongo en agregar, ponle en agregar, y ahí me genera una nueva cotización. Pero aquí, cuando yo le doy cliente, buscar cliente, aquí solo aparecen los que están ya dados de alta con todos los temas. FDI, entonces, si es un cliente nuevo, yo tendría, o el área comercial, que levantar un ticket para que administración me avise que ya ha estado de alta en el sistema y yo pueda generar una cotización. Pero si no es ese caso, yo creo que, Arturo, ya lo vamos a poner para que también no me gustaría que empezáramos un desarrollo con parchecitos, sino como el deber ser. Entonces, el sí o sí es que debe de haber una cotización para cada cosa que se desee facturar, ¿sale? Entonces, sí vamos a empezar, sí puedes tomar, Johann, como un requisito de que vamos a partir de una cotización del sistema, ¿no? A menos la otra excepción que te comenté.
52:51 - Unidentified Speaker
Entiendo.
52:52 - Johann
En ese caso, cuando un cliente es nuevo, tiene que crear el cliente, notificarte y después crear la cotización.
53:00 - Arturo Rosas Hernandez
Justo así.
53:01 - Araceli Sanchez Jimenez
Entiendo.
53:02 - Johann
Y también esta cotización sería inmediatamente después, en el caso claro, de que el cliente ya sea existente. ¿Sería inmediatamente después de que se hace el ticket en gira o tendría que pasar, por ejemplo, por alguien que apruebe ese paso de desde Gira hasta aquí a Bind. No sé si me explico.
53:26 - Araceli Sanchez Jimenez
No, a ver, otra vez.
53:28 - Johann
Sí, claro. Se crea el ticket primero en Gira, ¿verdad?
53:32 - Unidentified Speaker
Sí.
53:33 - Johann
Y cuando se completa ese ticket en Gira, ¿se pasa como cotización o hay un paso intermedio?
53:39 - Araceli Sanchez Jimenez
Ya, ya te entiendo. Sí. Mira, el deber ser es que el área comercial, como ya sabe en qué precio lo pactó, debe una cotización. Sin embargo, sí tenemos una excepción. Por ejemplo, si yo levanto un tema de headhunting, yo ya sé qué salario se está ofertando para esa posición y entonces pues yo ya sé cuánto va a ser generada la factura. Entonces ahí yo sin tema me puedo meter a una cotización, también en esta fomentation y otros proyectos. Sin embargo, hay unas ocasiones, Johann, en que el cliente nos da un rango salarial puede ganar de cinco pesos a siete pesos y depende de la aptitudes y actitudes del colaborador que lo paga lo pacta mejor en seis pesos y yo le haré comercial no sé qué voy a cerrar hasta que ya haya el cliente me haya dicho le vamos a dar seis pesos sólo en ese caso yo como comercial yo no podría generar una factura una cotización disculpa ¿Sí? Pero normalmente sí sé cuánto se va a pactar. Pero para generar la factura sí necesito que, por ejemplo, yo no pudiera generar una factura hasta que el cliente haya cerrado al colaborador. Entonces, ahorita que tú me lo preguntas, pues sí, siempre sé, siempre podría yo generar la cotización, porque yo me tendría que esperar para hacer la cotización para detonar el proceso de facturación. Sí, la respuesta es que sí, siempre debe de ir acompañado de una cotización del sistema. Ok, ok, entiendo. Muchas gracias.
55:32 - Johann
Mi pregunta es la de si pudiéramos ver acerca de esa lista blanca o si tú ¿Tienes algo más que comentar respecto a esos temas antes de continuar?
55:46 - Araceli Sanchez Jimenez
Sí. Este, mira, no, lo de la lista blanca es los clientes que no queremos que reciban recordatorios de morosidad, ¿verdad?
55:56 - Unidentified Speaker
Sí.
55:57 - Araceli Sanchez Jimenez
Fíjate que nada más tenemos a uno y sería la gente de Acuntia. Pero, Arturo, ahorita se me hace que podríamos tomar todo parejo en qué sentido. ¿La lista blanca es para el tema ya de cobranza, Johann? ¿Lo estás viendo el tema de cobranza?
56:20 - Unidentified Speaker
Sí.
56:21 - Unidentified Speaker
Ah, ok.
56:22 - Johann
¿Sabes qué?
56:23 - Araceli Sanchez Jimenez
Yo creo que deberíamos de demandar siempre a todos. ¿Por qué? Porque, por ejemplo, lo que luego pasa, que aunque, por ejemplo, nuestro cliente más grande nos paga a veces hasta unos días antes, también pasa que cuando hacemos la conciliación no nos paga el 100% de las facturas y luego vamos arrastrando facturas. Por ejemplo, ahorita tenemos arrastrando una factura del mes de febrero. A lo mejor es una factura pequeña con respecto al grueso de la facturación y luego tenemos otra de abril. Entonces, como no le hemos mandado el recordatorio de manera como muy proactiva, a los pocos días. Ahorita, ya que estamos en julio, se nos vuelve más complicado la cobranza. Entonces, yo lo estuve pensando y yo había dicho que no, o sea, que no le mandáramos nada a este cliente porque es muy pagador, sí, pero ahorita que lo estoy viendo, yo creo que le deberíamos de mandar al 100%, o sea, porque obviamente depende mucho del mensaje de cobranza que le mandes, ¿verdad? Entonces, no, Johann, ya no consideraría como tener excepciones. Entonces ahorita sería a todos los clientes que estén en morosidad, ¿no?
57:38 - Arturo Rosas Hernandez
A final de cuentas, perdón por la interrupción, pero a final de cuentas tenemos o hemos entendido que el uso de las herramientas, dígase Jira, dígase Vine, dígase Power BI, nos sirve para automatizar o los recordatorios o para estar observando cosas que en el proceso se nos olvidan como personas y que las herramientas en automático están viendo, simplemente que no están reportando. O sea, justo ahorita, si nosotros hubiéramos tenido esos recordatorios de una factura en incumplimiento, tal vez no hubiéramos llegado hasta julio con una factura emitida en febrero, porque hubiera habido recordatorios tal vez en una cadencia muy cercana a a la fecha de incumplimiento y actualmente alguien hubiera podido accionar algo, no? Tanto de nuestro lado como como proveedores, como del lado del cliente. Bueno, le llegó recordatorio. Arturo, qué es esto? Me están llegando recordatorios todos los días. Qué es esto? Ah, bueno, pues es una factura que tienes pendiente. Pero como no hubo esa recurrencia automática, pues bueno, dependió de una persona y las personas cometemos errores. Entonces omisiones también. Entonces hubo una omisión en este caso y no se hizo el recordatorio en tiempo y forma. Entonces creo que sí, creo que va a dar la pena incluirlo, incluir a todos. Sí, exactamente. No te escucho, Johann. Ah, es que estás en mute, Johann.
59:17 - Araceli Sanchez Jimenez
No te preocupes. Gracias.
59:18 - Johann
OK, con esto me queda muy claro cómo es que llevan el proceso de ¿Esto abarca desde el principio hasta el final? ¿Después de esto seguiría el proceso de cobranza? No, el proceso de envío de factura.
59:38 - Araceli Sanchez Jimenez
Este es otro proceso que, por ejemplo, cuando se levanta un ticket. Digo, hay muchos procesos que ya sabemos, porque cada cliente tiene... Hay Aquí aquí, sí, por Johann, ejemplo, creo que es el principal reto, porque hay unos clientes que mandas. Por ejemplo, Axie nos pide estado de cuenta de todas las facturas más las facturas. Sí. Que ese es un cliente extranjero. Pero, por ejemplo, Cemex, tenemos que mandarle la factura por correo a un hub adicionado de un archivo validado de las horas que trabajó el colaborador, ¿sí? Por ejemplo, eso es uno. Luego, si es un tema de proyectos, se manda de, por ejemplo, Dilo, se manda la factura más la cotización del proyecto. Sí entonces aunque todos los envíos es por correo si hay como ciertas particularidades entonces no sé cómo programar o ya tú nos dirás esas particularidades ¿verdad? Ok entiendo y esto varía por cliente ¿verdad? Sí sí por cliente por cliente y también por Porque, por ejemplo, con el tema de Staff Aumentation, al día de hoy, los clientes no nos piden, no todos, nada más con la factura está bien, pero Cemex, que tenemos Staff Aumentation, sí nos pide que agreguemos el visto bueno y las horas que trabajó en un Excel el colaborador, ¿no? Entonces, sí hay como asegúnes por clientes, pero lo más natural es que nada más podamos la factura, pero sí podríamos programarlo porque, por ejemplo, para enviar la factura a Cemex no la podemos enviar si no tenemos el archivo en Excel del colaborador con el visto bueno de su jefe. Y eso ya no depende de la gente, pero habría que como que nos revalidara o nosotros si el agente dice, oye, está lista la factura, la mando, mándame el archivo con cierta cosa, ¿no? Y, por ejemplo, Cemex tiene cierta nomenclatura para el envío del correo. Tiene que ser el número de proveedor, el mes, el número de factura, o sea, tienen unas posiciones específicas y también la redacción del correo, que, bueno, eso yo creo que ya es sencillo. Pero sí, dependiendo de los clientes, pues sí tenemos nuestros asegurantes. Entonces, realmente la facturación terminaría hasta que se manda al cliente, ¿no? Y ese es el proceso que nos hace falta. No sé si quieras que ese proceso te lo expliquemos, porque, pues, es un proceso para cada cliente. Lo que sí tenemos es un Excel, por ejemplo, en el que digamos Cemex y a quién se manda. Acuntea a qué se manda. ¿A quién se manda? ¿Qué correo o correos? Porque hay unos que es uno. Y otros que son varios. Lo que sí creo que no hemos anotado, Arturo, es la peculiaridad de qué con qué tiene que ir adjuntado, ¿no? Cemex con el archivo en Excel del visto bueno del jefe. Acuntia el punto zip sin más el estado de cuenta. Y así, esa singularidad no la tenemos, pero la podemos llenar porque, como te digo, o sea, yo creo que facturamos al mes entre 4 y 5 clientes diferentes. Son mucha cantidad de facturas porque nuestro cliente mayor nos pide que hagamos una factura por colaborador y con ellos tenemos casi 40 colaboradores. Por eso son tantas facturas, porque si la pudiéramos englobar serían cinco facturas, o sea, al mes, o seis facturas, ¿no? Nada más es eso lo que nos hay que hacer a mucho.
1:03:51 - Johann
Ok, entiendo.
1:03:53 - Araceli Sanchez Jimenez
entonces de eso no sé si quieres que te pudiéramos nosotros compartir un excel con las particularidades y adonde para que pues tú tú supieras verdad cómo se manda sí me sería útil ok bueno si quieres lo lo trabajamos y el día de hoy lo podemos mandar no artur ¿Cómo ves? Sí, claro.
1:04:19 - Arturo Rosas Hernandez
Ya lo tenemos avanzado en cuanto a los correos de envío y la forma de envío. A lo mejor las particularidades de formato, qué datos, qué archivos. Bueno, eso habría que trabajarlo. Pero sí, yo creo que hoy mismo podemos compartirlo.
1:04:38 - Unidentified Speaker
OK.
1:04:39 - Unidentified Speaker
Gracias.
1:04:39 - Unidentified Speaker
OK.
1:04:40 - Johann
Con esta parte me quedó muy claro cómo es que llevan la y ya me da una idea más clara de cómo trabajar el prototipo que les mostraré.
1:04:54 - Araceli Sanchez Jimenez
Ok, excelente Johann. Pues no sé si de esta sesión falte algún dato más adicional a lo que te vamos a mandar de las peculiaridades de cada cliente.
1:05:09 - Johann
Creo que por esta parte es todo, me quedan las dudas que tenía acerca del proceso que llevan, así que igual si me queda alguna duda le escribo a Erika y me ayuda a contactarlos, pero por mientras, por el momento me quedaron, me recibieron las dudas, muchas gracias.
1:05:31 - Araceli Sanchez Jimenez
No, muchas gracias a ustedes, gracias chicos y que pues tengan muy bonito Gracias, buen día. Gracias, bye.
@@ -0,0 +1,38 @@
# Notas — Sesión "Proceso actual de cobranza - Balam" · 7 jul 2026, 7:008:00 AM
**Canal:** Microsoft Teams (convocatoria de Erika del 6-jul, ver REGISTRO #34). **⚠️ Sin grabación** — estas notas las reconstruyó Johann de memoria el mismo día. Tratarlas como memoria, no como transcripción: nada aquí es cita textual.
**Mostró el proceso:** Arturo Rosas (administración / cuentas por cobrar). Convocados además: Araceli Sánchez y Erika Chávez (CC Noé); la asistencia exacta no quedó registrada.
---
## Exceles de control (mostrados en pantalla)
- Llevan Exceles con el control de **facturas abiertas**, **facturas canceladas** y **cuánto tiempo llevan de morosos** los clientes — es el aging de facto del proceso actual.
- Johann quedó en pedirle esos archivos a Arturo (no se compartieron en la sesión).
## Flujo actual de un pago
1. El cliente avisa el pago por **mensaje o correo**, adjuntando su **estado de cuenta**.
2. Ese estado de cuenta se comparte con el **despacho** (contable externo), que **registra los pagos en cuentas por cobrar (BIND) uno por uno**.
3. Tienen un **Power BI conectado — según mostró Arturo, con su token** — donde ven los gráficos de cartera, pero **no están al día**.
## Por qué conciliar es difícil
- Hay clientes cuyo pago **cubre decenas de facturas** a la vez ("10 pesos divididos en 40 facturas") — consistente con el cliente mayor que exige una factura por colaborador (~40, ver REGISTRO #27).
- Los avisos/comprobantes llegan **todos bajo el mismo nombre/patrón de referencia** (algo como `num_referencia.pdf`), así que la referencia bancaria **no distingue facturas****se concilia por folio** de factura.
- Los montos **no siempre cuadran exactos**: al recibir el dinero hay un **fee/comisión** que genera diferencias contra el total facturado — hay que tenerlo en consideración.
## Caso Acuntia (mostrado en vivo)
- Arturo pidió a Acuntia por correo la relación de pagos realizados; Acuntia respondió con un **Excel pago ↔ folio de factura**. El control existe de ambos lados, pero **los totales diferían por el fee**.
## Casos límite mencionados
- Clientes que pagan **facturas viejas que venían arrastrando** (la aplicación de pagos llega fuera de orden).
- Facturas ya pagadas cuyo **registro no está al día** (el estatus en sistema va atrás de la realidad).
## Lo que buscan
- Ser **proactivos**: poder establecer **recordatorios** — pasados **15 días** (de vencimiento), mandar un correo, o al menos que el atraso **esté visible**.
- Evolución en sus palabras: antes eran **reactivos** ("ya hace rato que no me paga"), hoy son **activos**, y quieren ser **proactivos**.
@@ -0,0 +1,37 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · seguimiento del pendiente de BIND
**Canal:** WhatsApp (+52 1 81 2353 5803) · **Fecha:** 7 jul 2026
---
## Bloque 1 — 9:28 AM
> **Erika:** no
*(Fragmento suelto — el mensaje o pregunta al que responde no está incluido en lo reenviado a Claude. Pendiente aclarar contexto.)*
## Bloque 2 — 12:27 PM — seguimiento a la línea de BIND en el plan de actividades
> **Erika** *(12:27)*: johan respecto a este punto, es para hoy y mañana, todo bien, necesitas algo?
Se refiere a la línea del plan de actividades **"Validación técnica de la API de BIND con la cuenta real"** (mar 07 → mié 08 jul) — la misma actividad que Johann ya adelantó y cerró el 6-jul (ver REGISTRO #32 y `../bind-api-sandbox/`).
## Bloque 3 — 3:56 PM5:49 PM — seguimiento al usuario de lectura de BIND
> **Erika** *(3:56)*: okey
>
> **Erika** *(4:10)*: Hola Erika, todo bien, solo sería el usuario de lectura qué comentaba Noe pero mientras tanto estoy usando el usuario de Arturo a modo de lectura, no me bloquea por esa parte
> este usuario de lectura que comento el inge noé te lo iban a crear o como?
>
> **Johann** *(5:12)*: Noe le había comentado a Pedro que revisara si era necesario crear un usuario específico
>
> **Erika** *(5:23)*: ah okey
> deja lo reviso con ellos entonces, como no estoy familiarizada con eso por eso no le entiendo y una disculpa eh
>
> **Johann** *(5:37)*: Sii ntp, de igual manera no me bloquea
>
> **Erika** *(5:49)*: ah bueno esta bien
*(Nota: el saludo "Hola Erika" del mensaje de las 4:10 es un lapsus de Erika — dirigido a Johann.)*
Erika confirma que, mientras se resuelve si Pedro crea el usuario de solo lectura que pidió Noé (ver REGISTRO #31), ella sigue operando con el **usuario de Arturo** a modo de lectura, sin bloqueo. Johann aclara que la decisión de crear o no ese usuario específico quedó en manos de Pedro (por instrucción de Noé), no de Erika. Erika queda en darle seguimiento con el equipo técnico.
@@ -0,0 +1,75 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · datos ficticios de cobranza y avance de Fase 0
**Canal:** WhatsApp (+52 1 81 2353 5803) · **Fechas:** 810 jul 2026
---
## Bloque 1 — 8-jul, 10:09 AM10:16 AM — validación interna antes de compartir los Exceles de cobranza
> **Erika** *(10:09)*: Buenos días johan, espero y te encuentres bien
>
> **Erika** *(10:10)*: estan validando la informacion que solicitaste tecnicamente para poder compartirlo contigo ya que como sabras es informacion delicada, en cuanto me den luz verde te lo hago saber
>
> **Erika** *(10:10)*: gracias por el apoyo
>
> **Johann** *(10:13)*: Hola Erika buenos días
>
> **Johann** *(10:15)*: Sí sin problema, de igual manera si gustan pueden ser datos ficticios, me es útil la estructura que siguen
>
> **Erika** *(10:16)*: ah super, entonces deja se los comunico por si pudieran hacer un ejemplo ficticio y proporcionartelo para efecto de visualizar el prototipo va
>
> **Johann** *(10:24)*: Va
Se refiere a la solicitud de los **Exceles de cobranza** a Arturo (control de facturas abiertas/canceladas/morosidad, Excel tipo Acuntia pago↔folio, estado de cuenta ejemplo — ver REGISTRO #35 y PENDIENTES.md). Balam está internamente validando si puede compartir la información real por ser delicada. Johann ofrece una alternativa de bajo fricción: **datos ficticios**, ya que lo que necesita es la **estructura**, no los datos reales — coherente con la salvaguarda ya acordada de mantener datos reales fuera del repo/documentos.
## Bloque 2 — 8-jul, 10:50 AM — Balam pide internamente ejemplo ficticio
> **Erika** *(10:50)*: ya mande mensaje que si se les hace mejor mandar la estructura con datos ficticios solo para efecto de visualizar el prototipo de entregable de la fase 0
>
> **Erika** *(10:50)*: espero comentarios y te comento va
>
> **Erika** *(10:50)*: gracias por el apoyo
>
> **Johann** *(10:54)*: De acuerdo, muchas gracias
>
> **Erika** *(10:55)*: a ti
Erika traslada la propuesta de datos ficticios al equipo interno (Arturo/Araceli) y queda en avisar cuando tenga respuesta. Sin fecha comprometida.
## Bloque 3 — 9-jul, 7:20 PM9-jul 9:10 PM — Erika pide avance de Fase 0
> **Erika** *(9-jul, 7:20 PM)*: Buenas tardes johan espero y te encuentres bien, me puedes pasar como vamos con las acts de la fase 0
>
> **Johann** *(9-jul, 9:10 PM)*: Hola buen día, sí claro, cómo te lo comparto?
Erika (como intermediaria de seguimiento del plan de actividades) pide un corte de avance de las actividades de **Etapa 0**. Johann responde ya entrada la noche, preguntando el medio preferido para compartirlo — queda sin resolver hasta el día siguiente.
## Bloque 4 — 10-jul, 8:41 AM9:39 AM — instrucción de envío y disculpa por sesión de validación no agendada
> **Erika** *(8:41)*: Así nomas dime que acts y porcentaje de avance ntp
>
> **Johann** *(8:42)*: Hola buenos días
>
> **Johann** *(8:44)*: Disculpa, tengo preparado el prototipo visual y hoy estaba agendado para validarlo con ustedes, ayer ya no te recordé y ya no pudimos agendar una reunión una disculpa, si hoy no tienen disponibilidad para revisarlo pudiera compartirles el prototipo con mis comentarios si les funciona
>
> **Erika** *(8:59)*: Ntp
>
> **Erika** *(9:00)*: Si manda correo del prototipo con imágenes copia a Pedro al inge Noe y Araceli por favor
>
> **Johann** *(9:21)*: De acuerdo, te lo envío a ti verdad?
>
> **Erika** *(9:21)*: A mí y al inge y cc a Pedro nada más
>
> **Erika** *(9:22)*: A Araceli no
>
> **Erika** *(9:28)*: Es más
>
> **Erika** *(9:28)*: Solo a mí y al inge por favor
>
> **Erika** *(9:28)*: Nosotros se los pasamos internamente
>
> **Johann** *(9:39)*: De acuerdo
>
> **Johann** *(9:39)*: Esto te lo paso por aquí? *(pregunta sobre el % de avance de la Fase 0 pedido en el Bloque 3, aún sin responder)*
Johann reconoce que no confirmó la sesión de validación del prototipo del **viernes 10-jul** (la fecha objetivo que él mismo se había puesto — ver PENDIENTES.md) y, ante la falta de agenda, ofrece compartir el prototipo por correo con sus propios comentarios en vez de esperar a una reunión. Erika acepta y da instrucción de destinatarios, **cambiando de opinión dos veces en el mismo intercambio**: primero pide copiar a Pedro, Noé **y Araceli**; 20 segundos después corrige — sin Araceli; y a los pocos minutos vuelve a acotar más — **solo a Erika y al Ing. Noé, con Pedro en copia**, sin nadie más ("nosotros se los pasamos internamente"). Queda pendiente la respuesta de Johann sobre el % de avance de Fase 0 (pedido desde el 9-jul) — pregunta si lo reporta por este mismo canal.
@@ -0,0 +1,60 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · seguimiento de prototipo, sesiones y accesos
**Canal:** WhatsApp
**Periodo:** 1315 jul 2026
**Evidencia:** capturas compartidas por Johann el 13, 14 y 15-jul.
---
## 13-jul — prototipo, sesión con Arturo y primera factura
Johann informa que, mientras Balam revisa internamente el prototipo, avanzará con trabajo de backend de la Etapa 1 que no depende de esa validación: base de datos, autenticación/roles y cliente de consulta de BIND. Propone recibir retroalimentación el miércoles para incorporar ajustes sin detenerse.
Erika responde que la CEO está fuera del país y que la diferencia de horario dificulta validar el prototipo en ese momento. Johann confirma que seguirá trabajando y avisará si fuera necesario ajustar el orden de las actividades.
Johann pide confirmar una sesión con Arturo para cerrar tres puntos abiertos del Discovery:
- Flujo de alta de clientes nuevos.
- Registro en BIND de las diferencias por comisión/fee.
- Excel de particularidades de envío por cliente.
Erika se compromete a contactar a Arturo. Sobre el Excel de particularidades, confirma que continúa en preparación y que Balam espera entregarlo durante la semana.
Johann también retoma la propuesta v1.2 enviada el 2-jul y solicita confirmación para emitir la factura inicial de 30 horas. Erika confirma que vio la propuesta, pero explica que tanto la CEO como Noé están fuera del país por trabajo, con aproximadamente ocho horas de diferencia. Queda en revisar cómo pueden validar la emisión.
---
## 14-jul — agenda de sesiones y dependencias de Etapa 1
Erika informa que Arturo puede reunirse el día que sea más conveniente para Johann. Johann propone martes o miércoles a las 7:00 am.
Posteriormente, Erika comunica que la CEO desea participar y que la sesión solicitada se moverá al **miércoles 22-jul**, cuando ella se encuentre de regreso en el país.
Erika propone una segunda sesión, distinta de la anterior, para la **validación del prototipo de la Etapa 0**, el **jueves 23-jul a las 7:00 pm**. Aclara que:
- La sesión del 22-jul corresponde a dudas y definiciones de la Etapa 1.
- La sesión del 23-jul corresponde a la validación del prototipo de la Etapa 0.
Johann confirma ambas y Erika envía la convocatoria del 23-jul.
En el seguimiento del plan, Johann aclara que para la Etapa 1 requiere:
- Un repositorio privado de GitHub creado por Balam, con acceso de escritura.
- Acceso acotado a Azure para la infraestructura posterior.
Se mantiene el ajuste previamente conversado: repositorio primero; Azure durante la semana del 21-jul; CI/CD y gestión de secretos como actividad separada.
Erika pregunta si aún se necesita la estructura del Excel de cobranza con días vencidos que se había solicitado a Arturo. Johann responde que, si Balam considera que la estructura del prototipo refleja correctamente su operación, ya no será necesario prepararlo; si identifican ajustes, sí servirá como referencia.
---
## 15-jul — repositorio GitHub autorizado
Erika solicita el usuario de GitHub de Johann y confirma que Noé autorizó la creación del repositorio privado de Balam.
Johann comparte:
- **Usuario:** `Johann-28`
- **Perfil:** `https://github.com/Johann-28`
**Estado al cierre:** repositorio autorizado y en proceso de creación/invitación. Falta recibir y validar el acceso efectivo con permisos de escritura.
@@ -0,0 +1,67 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · invitación Git, procedimientos y avance de Etapa 1
**Canal:** WhatsApp
**Fecha:** 2026-07-16
**Evidencia:** captura compartida por Johann el 16-jul-2026.
## Transcripción
**Erika · 12:1012:16 pm**
- “buenas tardes johan”
- “ayer mi compañero pedro te envio la invitacion para el GIT”
- “puedes revisar si ya puedes acceder”
- “adicional me acaban de liberar los procedimientos de los clientes, ahorita te lo mando por correo”
**Johann · 12:24 pm**
- “Buenas tardes”
- “De acuerdo, si ya pude acceder al repositorio, muchas gracias”
- “Enterado”
**Erika · 12:32 pm**
- “gracias y quedo a tus ordenes”
- “me pudieras pasar el avance que se tiene de la etapa 1 porfa”
**Johann · 12:54 pm**
- “Sí, sin problema, lo preparo y te lo comparto por aquí”
**Erika · 12:551:02 pm**
- “gracias”
- “ya envie el correo con los procedimientos de cargas de factura de los clientes puedes validarlo si llego el correo por favor”
**Johann · 1:03 pm**
- “Recibido, gracias”
**Erika · 1:281:29 pm**
- “a ti, quedo al pendiente de los avances de la etapa 1”
- “y si necesitas algo mas de nuestro lado me avisas va”
**Johann · 1:31 pm**
- “va, en cuanto los tenga te los comparto”
**Johann · 8:40 pm** *(mismo día, en la noche)*
- Envía el archivo **`Plan-actividades-avance-2026-07-16.xlsx`** (11 kB).
- “Buenas noches, una disculpa por la hora”
**Erika · 8:44 pm**
- “Buenas noches johan”
- *(respondiendo al documento)* “Ntp, gracias”
## Acciones derivadas
1. ~~Validar que el acceso al repositorio privado permita lectura y escritura.~~**Comprobado el 16-jul:** push exitoso del scaffold inicial (`04d8388..1f7f098`).
2. Revisar los procedimientos de carga de facturas enviados por correo y contrastarlos con el flujo levantado en Discovery.
3. ~~Compartir con Erika un corte verificable del avance de la Etapa 1.~~**Hecho (16-jul, 8:40 pm):** Excel de avance enviado por WhatsApp; Erika acusó recibo.
## Observación
En el chat Johann confirmó que ya podía acceder al repositorio y que recibió el correo. Aún falta conservar el correo o sus adjuntos como evidencia y realizar la revisión de contenido (insumo para la sesión del 22-jul).
@@ -0,0 +1,112 @@
# WhatsApp — Erika Chávez (PM, Balam) ↔ Johann · coordinación de sesiones (validación de prototipo + API Jira), envío del flujo de facturación y reagenda 23→24 jul
**Canal:** WhatsApp
**Fechas:** 2026-07-21 (tarde) a 2026-07-27 (mañana)
**Evidencia:** copia del chat compartida por Johann el 27-jul-2026.
**Relación con la bitácora:** continúa el hilo del 21-jul ([#51](../bitacora/REGISTRO.md)); cruza con la sesión de reglas del 22-jul ([#54](../bitacora/REGISTRO.md)), la validación del prototipo del 24-jul ([#55](../bitacora/REGISTRO.md)) y la sesión de API de Jira del 27-jul ([#56](../bitacora/REGISTRO.md)).
> **Nota sobre imágenes:** las capturas no se conservan en el volcado de texto; se infieren por el contexto y se marcan como **📷 [imagen inferida]**.
---
## Transcripción
### Martes 21-jul (tarde) — horas por Excel y aclaración de cotizaciones/MVP
**Johann · 12:51 pm** — “Disculpa acerca de las horas, mientras se habilita el flujo de Jira, ¿te las comparto por Excel?”
**Erika · 12:52 pm** — “Sí por favor con el entregable y act y horas” · “De cada etapa por favor”
**Johann · 12:52 pm** — “De acuerdo”
**Erika · 12:58 pm** — “disculpa ¿no es esto lo de las cotizaciones?”
> 📷 **[imagen inferida — confianza alta]:** captura señalando el punto de cotizaciones (probablemente §1.4 de la propuesta o la fila del Excel).
**Johann · 1:00 pm** — “Sí pero desde el MVP”
**Johann · 1:01 pm** — “También identifiqué un punto que no aparece todavía en el Excel: durante el Discovery surgió la posibilidad de que los tickets de Jira generen automáticamente las cotizaciones en BIND. Para eso eventualmente necesitaríamos acceso técnico a Jira y permisos controlados de escritura en BIND. Esto es para que cuando se cree un ticket de Jira, se cree automáticamente la cotización en BIND.”
**Erika · 1:01 pm** *(citando “Sí pero desde el mvp”)* — “¿Qué es MVP?”
**Johann · 1:02 pm** — “Esta aplicación que estamos trabajando”
**Erika · 1:03 pm** — “Okey” · “ya vi que dice fuera de alcance”
> 📷 **[imagen inferida — confianza media]:** posible captura de la §1.3 (Jira “Fuera de alcance”).
**Johann · 1:04 pm** — “Okay, cualquier cosa me avisas”
### Miércoles 22-jul — disculpa por la sesión de reglas, propuesta a ajustar, agenda de API Jira y envío del flujo por correo
**Erika · 11:35 am** — “buenos días Johan, primero que nada una disculpa por no estar en la sesión de hoy, tuve un compromiso personal, sin embargo les avisé a los ingenieros mi ausencia para que pudieran tomar esa reunión importante contigo. Veo que se mencionó lo del ajuste de la integración del sistema Jira ¿vrdd?”
**Erika · 11:35 am** — “¿ajustarás la propuesta?”
**Erika · 11:35 am** — “y quedó pendiente de nuestro lado la revisión de la API con Jira y el flujo de facturación de Jira ¿vrdd?”
**Johann · 11:5511:56 am** — “Hola buen día” · *(citando su disculpa)* “No hay problema” · *(citando lo del pendiente)* “Sí, así es”
**Erika · 11:58 am** — “Okey de acuerdo, deja valido la información correspondiente para mandarte lo solicitado”
**Erika · 11:59 am** *(citando “ajustarás la propuesta?”)* — “¿Se ajustará?”
**Johann · 12:05 pm** — “Sí, de igual manera entre hoy y mañana te comparto el conteo de horas y la propuesta ajustada”
**Erika · 1:21 pm** — “Johan, ¿pudieras tener una sesión el viernes a las 7 am para ver lo de la API de Jira junto con el Ing. Noe y mi compañero Pedro?” · “¿Cómo ves?”
**Johann · 1:22 pm** — “Sí, me parece bien”
**Erika · 1:22 pm** — “Va, deja la agendo, gracias”
**Erika · 2:26 pm** — “Johan, te confirmo: el correo del flujo de facturación de Jira ya lo mandé” · “Quedo al pendiente de cualquier duda o comentario :)”
**Johann · 2:40 pm** — “De acuerdo, muchas gracias :)”
**Erika · 2:47 pm** — “A ti, igual la sesión ya se agendó, la del viernes”
### Jueves 23-jul — reagenda por tema personal de Araceli; validación se mueve a viernes; API Jira se mueve a lunes
**Erika · 6:53 am** — “Buenos días Johan” · “¿Ya listo?”
**Johann · 6:53 am** — “Hola Erika, buenos días” · “¡Listo!”
**Erika · 6:54 am** — “¡Súper!” · “Igual comenzaremos con que expliques el prototipo y si hay dudas que se comenten” · “Ten a la mano el archivo que nos compartiste para que proyectes por favor”
**Johann · 6:55 am** — “¿Cuál archivo disculpa?”
**Erika · 6:55 am** — “El que nos enviaste”
**Johann · 6:55 am** — “Oh, el PDF con las capturas”
**Erika · 6:55 am** — “Sí”
**Erika · 7:007:01 am** — “Johan” · “Una disculpa, me van avisando que Araceli trae un tema personal y no podrá conectarse, y es de gran importancia que esté ella ya que es la del proceso completo” · “¿Podemos cambiar esta sesión a mañana a las 7 am?” · “Y la que tenías mañana conmigo de la API de Jira moverla a la tarde, no sé cuál sea tu disponibilidad”
**Johann · 7:017:02 am** — “Entiendo” · “¿En qué horario en la tarde podrían para lo de la API de Jira?”
**Erika · 7:02 am** — “A la hora que indiques” · “¿Puedes a las 4-5-6?”
**Johann · 7:03 am** — “¿Podría ser después de las 6:30 de casualidad?”
**Erika · 7:03 am** — “Sí claro, 6:30 a 7:30 va”
**Johann · 7:05 am** — “¿Un poco más cercano a las 7 habrá oportunidad? ¿O ya sería muy tarde?”
**Erika · 7:09 am** — “¿A las 7 entonces?”
**Johann · 7:10 am** — “Sí, a esa hora me quedaría súper”
**Erika · 7:11 am** — “Listo, nos vemos a las 7 am mañana para prototipo y en la tarde 7 pm para lo de la API” · “Gracias Johan y una disculpa”
**Johann · 7:27 am** — “Enterado, muchas gracias Erika”
**Erika · 9:459:46 am** — “Johan” · “¿Puedes el lunes a las 7 am?” · “Es que me comenta Pedro que lo puede mañana a esa hora”
**Johann · 9:56 am** — “Sí sin problema”
**Erika · 10:06 am** — “Súper” · “gracias”
**Erika · 10:08 am** — “Listo ya la moví”
**Johann · 10:09 am** — “Listo, ya la acepté”
**Erika · 10:23 am** — “gracias”
**Erika · 11:29 am** — “Johan ¿esta actividad se acabó ayer?”
> 📷 **[imagen inferida — confianza alta]:** captura de una actividad del Excel/plan (la de escritura/sync en BIND).
**Johann · 11:37 am** — “Sí, aún no he hecho pruebas de escritura en BIND, pero ya está”
**Erika · 11:37 am** — “Okey de acuerdo”
### Viernes 24-jul — arranque de la sesión de validación del prototipo
**Erika · 6:57 am** — “Buenos días Johan” · “¿Cómo estás?” · “¿Todo listo?”
**Johann · 6:57 am** — “Hola Erika, buenos días” · “Sii” · “Listo” · *(citando “como estas?”)* “Bien ¿y tú?”
**Erika · 6:576:59 am** — “Bien gracias” · “Pues ahorita le damos entonces va” · “Vamos a conectarnos”
**Johann · 6:58 am** — “Va”
**Erika · 7:00 am** — “Ya estamos”
*(→ inicia la sesión de validación del prototipo, [#55](../bitacora/REGISTRO.md))*
### Lunes 27-jul — solicitud de avances de Etapa 1
**Erika · 7:11 am** — “Buenos días Johan, disculpa ¿me puedes pasar los avances de la etapa 1 pls?”
**Johann · 7:13 am** — “Buenos días Erika, sin problema”
**Johann · 7:14 am** — “Disculpa, ¿de casualidad ya tenemos el Jira para este proyecto?”
*(→ este mismo día por la mañana ocurre la sesión de API de Jira con Pedro, [#56](../bitacora/REGISTRO.md), donde se compromete el token PAF)*
---
## Acciones derivadas
1. **Johann — enviar conteo de horas (Excel con entregable + actividad + horas por etapa) + propuesta ajustada** por la integración Jira→BIND. Comprometido “entre hoy y mañana” el 22-jul (es decir, para el 23-jul). ⚠️ **Verificar si ya se envió.**
2. **Johann — preparar y entregar los avances de la Etapa 1** solicitados por Erika el 27-jul (7:11 am).
3. **Conservar el correo del flujo de facturación de Jira** que Erika envió el 22-jul (2:26 pm) — insumo para la integración.
4. **Pregunta abierta de Johann (27-jul):** ¿ya existe el Jira del proyecto? → se atiende en la sesión de API del 27-jul ([#56](../bitacora/REGISTRO.md)): Pedro genera el token **PAF** (1 año).
## Observaciones
- **Saga de reagenda:** la **validación del prototipo** pasó de jueves 23-jul 7 am → **viernes 24-jul 7 am** (Araceli, dueña del proceso, tuvo un tema personal). La **sesión de API de Jira** pasó de viernes 24-jul 7 am → viernes 24-jul 7 pm → **lunes 27-jul 7 am** (por disponibilidad de Pedro).
- Erika reiteró dos veces la pregunta de si **se ajustará la propuesta** por el cambio de la integración Jira — es un pendiente comercial, no solo técnico.
@@ -0,0 +1,473 @@
Flujo para dar de alta clientes nuevos, registros en BIND las diferencias por comisión/fee-Proyecto integraciones Balam
Wed, Jul 22, 2026
0:01 - Johann
¡Gracias por ver el vídeo! Buenos días, ¿cómo estás?
0:33 - Johann
¿Qué tal? Bien, ¿y tú?
0:37 - Unidentified Speaker
¿Qué tal todo?
0:39 - Conference Room (Noe Rocha) - Speaker 1
Bien, gracias a Dios. A ver, ya nada más faltaría... Este...
0:46 - Unidentified Speaker
¿Arturo?
0:47 - Unidentified Speaker
Y ahorita arrancamos. Va, sin problema.
0:50 - Unidentified Speaker
Bien.
0:51 - Johann
Sí, me comentan que estuvieron fuera del país.
0:56 - Conference Room (Noe Rocha) - Speaker 1
Sí, estuvimos con...
0:58 - Conference Room (Noe Rocha) - Speaker 1
algunos temas con clientes y sí nos enfrentamos bastantes días aquí de la oficina. Pero ya de vuelta para retomar actividades y avanzar con este tema que nos interesa mucho. ¿Y qué tal fue?
1:12 - Unidentified Speaker
¿A qué país fueron?
1:14 - Conference Room (Noe Rocha) - Speaker 1
Estuvimos en España con unos clientes de España y aprovechamos y dimos una vuelta allá a Polonia en Cracovia para conocer. En Europa Central Es muy bonito viajar por allá y conocer otras culturas, otras ciudades, otras lenguas. Los polacos no entienden nada. Lo bueno es que hablan muy bien inglés. Hablan muy bien inglés. Entonces te puedes entender bien.
1:46 - Unidentified Speaker
Sí, sí, sí.
1:48 - Conference Room (Noe Rocha) - Speaker 1
Sí, sí, sí. Así fue. Estuvo muy padre. Bastante recomendable. Bien lejos, está muy lejos.
1:56 - Johann
Sí, me imagino hasta el otro lado del océano.
1:59 - Conference Room (Noe Rocha) - Speaker 1
Sí, y luego todavía llegando al otro lado es, tríncate otras cuatro horas para llegar a esos lugares en vuelo, entonces, tres horas y media, cuatro horas, depende de dónde vayas. Pero sí, es impresionante, o sea, mucho bosque, mucho verde, muy bonito.
2:16 - Johann
Muy bonito.
2:17 - Unidentified Speaker
¿Qué tal, Arturo?
2:18 - Johann
Buenos días.
2:19 - Unidentified Speaker
Hola Arturo, buenos días.
2:22 - Unidentified Speaker
¿Dónde te escuchas Arturo?
2:25 - Unidentified Speaker
¿Ahí me escuchan?
2:27 - Arturo Rosas Hernandez
Ahí te escuchamos. Excelente. Buenos días, ¿cómo están? Todo muy bien.
2:34 - Conference Room (Noe Rocha) - Speaker 1
Bien, ¿y tú? Que bueno, que bueno, todo bien.
2:40 - Arturo Rosas Hernandez
Gusto saludarte Johann, ¿cómo estás?
2:44 - Arturo Rosas Hernandez
También, también, buenos días.
2:48 - Arturo Rosas Hernandez
Buenos días, buenos días.
2:49 - Unidentified Speaker
Bueno, pues listo.
2:51 - Arturo Rosas Hernandez
Pues empecemos, Johann.
2:52 - Conference Room (Noe Rocha) - Speaker 1
Yo sé que por ahí habías pedido un foro con Erika y era para ver flujos, ¿no? El flujo de clientes nuevos, los registros de Vine, las diferencias por comisión, los fideiproyectos. Esto supongo que para ajustar o documentar lo que necesitas dentro del propio desarrollo y entendimiento de cómo suceden las cosas, ¿verdad?
3:17 - Johann
Sí, justamente.
3:18 - Conference Room (Noe Rocha) - Speaker 1
Pues mira, aquí tenemos a Arturo, y un poquito escuchando también la conversación, aunque no va a estar en la presentación porque está en otros temas, está Araceli. Entonces, pues, si quieres, ve preguntando y aquí vamos aclarando con Arturo el ASIS, ¿no?, cómo está funcionando ahorita.
3:37 - Johann
Ok, de acuerdo, me parece bien. Ahora mismo, estaría bien si pudiéramos comenzar con cómo se da de alta un cliente en Bind. Los ejercicios que habíamos visto previamente eran cuando el cliente de Vine ya existía. Y esa parte ya me quedó claro y Arturo nos lo explicó muy bien. No sé si pudiéramos ver un ejemplo de cómo se crea.
4:02 - Conference Room (Noe Rocha) - Speaker 1
En la plataforma, directamente en Vine.
4:04 - Arturo Rosas Hernandez
Sí, creo que se cortó un poquito. Te cortas un poquito, Johann. Te preguntaba, Johann, ¿sería sobre la plataforma?
4:12 - Conference Room (Noe Rocha) - Speaker 1
O sea, ¿entrar a la plataforma y que desde principio a fin cómo se da un Dalton cliente, ¿verdad?
4:21 - Unidentified Speaker
En Bain.
4:22 - Unidentified Speaker
Sí.
4:23 - Conference Room (Noe Rocha) - Speaker 1
A ver, adelanta tú.
4:25 - Arturo Rosas Hernandez
Ok, déjenme para eso entonces les muestro mi pantalla y me confirman por favor cuando ya la aprenda.
4:34 - Unidentified Speaker
Ya, está bien.
4:36 - Arturo Rosas Hernandez
Ok, déjenme ver si me acuerdo, porque esto no sucede muy a menudo así que en el apartado de compras en el módulo de proveedores ahí existen todos los proveedores que tenemos dados de alta actualmente ahí los podemos consultar y me gustaría empezar con la opción de modificar entonces modificar existen dos opciones en esta pantalla que es la de editar, editar el producto como tal o simplemente eliminar. Y agregarlo.
5:15 - Conference Room (Noe Rocha) - Speaker 1
Sí, obviamente y agregarlo.
5:17 - Arturo Rosas Hernandez
Entonces, bueno, no sé qué tan importante sea la parte de modificar y eliminar, pero bueno, está aquí en esta pantalla. Y lo siguiente, la siguiente opción que nos da es obviamente exportar, importar o generar notas de crédito. Una lista de EFOS y el apartado de agregar. Entonces en el botón de agregar simplemente le damos clic y nos abre una siguiente pantalla que es la pantalla de agregar proveedor y nos pide dos pestañas de información. Una es la de detalle que incluye o pide todo el tema fiscal, por decirlo de alguna manera, y la dirección. Entonces hace poco justo dimos de alta la razón social de Frisa, entonces la información para esta pantalla de detalle se toma básicamente de la constancia de situación fiscal del cliente. Y el estado de cuenta. Exacto. Hasta aquí, hasta la parte de aquí, razón social, RFC, nombre comercial y categoría, sería la parte fiscal. Y lo siguiente es su estado de cuenta, como bien lo dijo Noe, su estado de cuenta bancaria, que sería el banco, y nada más. El banco es la cuenta clave porque los días de crédito y el monto de crédito vienen de la parte comercial, desde la parte de negociación comercial, de los acuerdos exactos, ahí la parte comercial decide o negocia con el cliente la cantidad de crédito o de días de créditos que se tendrá, el correo electrónico que se usará o se para la comunicación y la sucursal, digo aquí nosotros no tenemos sucursales todavía en BIND pero si en algún momento hubiera más de una sucursal aquí estaría la matriz como actualmente la tenemos que es la que utilizamos para todos y pudiera haber más sucursales de BALAM pues sí sobre todo de BALAM obviamente el teléfono, el teléfono de contacto o de comunicación y algunos comentarios también podemos definir la parte del lenguaje de los documentos si tenemos clientes que por ejemplo BICTEX si no mal recuerdo que la comunicación debe ser en inglés entonces para ese caso o para casos como ese elegiremos el formato o lenguaje inglés y le damos siguiente no sé si quieran que hagamos una una alta de prueba para que veamos el flujo, o solo así platicado es suficiente Johann?
8:32 - Conference Room (Noe Rocha) - Speaker 1
No sé si algo pase adicional, porque si no tenemos datos, supongo que algunos datos reales para esto. Tú dime Johann, si al menos esta primera vista te es suficiente para entender un poco ¿Cómo dar datos a un cliente? Se pide la información fiscal, su CFDI, luego su estado de cuenta. Con esa información, ahora sí volvemos aquí y aquí lo alimentamos y le damos de alta. Vamos a suponer que le dimos de alta a alguien. Vámonos a la opción de editar un usuario para ver qué datos aparecen. Digo, falta la parte de las direcciones.
9:13 - Arturo Rosas Hernandez
Ah, ok. Adelante de dirección. Obviamente, en la pestañita de direcciones pide el país. ¿A qué país corresponde? Si tenemos clientes, por ejemplo, en España, podríamos tener algún cliente en España o en Estados Unidos. Entonces, ahí hay que definirlo. El estado, el municipio, la localidad, la calle. Esta parte también viene de la constancia de situación fiscal. La colonia, el código postal, si tiene número exterior, si tiene número interior. El código de la colonia código es de opcional. La localidad. Y ahora sí, una vez que terminamos de llenar esta documentación, de esta información, le damos guardar. Y ahora sí, la pestaña anterior.
9:57 - Conference Room (Noe Rocha) - Speaker 1
Yo sumaría, Arturo, a lo que dices, es que agregar a clientes es lo mismo que agregar a proveedores, ¿verdad, Arturo?
10:06 - Arturo Rosas Hernandez
Sí, sí, correcto.
10:07 - Conference Room (Noe Rocha) - Speaker 1
Es el mismo procedimiento clientes como proveedores. Correcto. Te lo digo porque estaba viendo que había algunos proveedores también dado de alta y después de agregarlo supongo que lo que pasa es que te genera un ID de proveedor.
10:25 - Arturo Rosas Hernandez
Sí, entonces justo lo que dice Noe, la parte de agregar proveedores y agregar clientes, esta es la pestaña de agregar clientes, digo la pantalla, esa está en el módulo de ventas y clientes entonces la anterior es compras y proveedores y esta es venta y clientes ok la información como lo dijimos básicamente inicia en el botón de agregar también tiene las mismas dos pestañas detalle y direcciones básicamente se llena la misma información que mencionábamos hace un rato razón social nombre comercial y rfc Los días de crédito, el monto de crédito. Las ventas esperadas y los créditos negociados. Lista de precios, si existe lista de precios. El correo electrónico de comunicación. El número de cuenta. El descuento pactado, si existe un descuento pactado al inicio. Los teléfonos de contacto. Cómo se enteró de nosotros. Hasta ahorita este apartado no lo usamos. El uso SFDI. En algunos casos, Si tienen un CFDI específico, la mayoría de las veces todos aceptan gastos en general, pero depende de su constancia de situación fiscal. El régimen fiscal, este también viene dado por su constancia de situación fiscal y algunos comentarios finales. En el apartado de direcciones, este sí es idéntico al de proveedores, le damos guardar. Y hasta aquí, no sé si haya duda, Johann.
12:02 - Unidentified Speaker
OK.
12:03 - Johann
Hasta ahora me quedan claros los detalles que se tienen que dar de alta cuando se agrega un cliente y un proveedor. Igual, como comentan hoy, si es verdad que crear uno nuevo implicaría datos reales, ¿no? Entonces, con este proceso que la platicadito, me queda claro que datos son los que se piden.
12:28 - Arturo Rosas Hernandez
Sí, y apenas tiene unos cuantos días esta frisa, entonces hubiera sido buena oportunidad para guardarlo. Justo ayer platicábamos Sara y yo que voy a ir grabando algunos procesos que surjan como nuevos, entonces los voy a grabar y después estos tipos muy sencillos manualitos que compartí ahí con Eric para el tema de cómo generar las facturas de algunos clientes, algo parecido a hacer, ¿no? Pero grabarlo y luego generar un Word y tal vez un PowerPoint con algunas imágenes y así, hacer un tipo proceso, procedimiento muy sencillo, ir haciéndolo cada vez que se presente la oportunidad de procesos o de clientes nuevos, proveedores, facturación. O sea, Frisa ahorita justo ya vamos proceso de facturación ya tengo un caso entonces justo lo voy a grabar y lo voy a documentar para que en necesidades como esta pues ya se tenga la información y se hagan ejemplos reales bueno ok entonces una vez que se guarda la información ya podemos regresar al apartado de clientes que es básicamente como el de proveedores y aparece en listados todos los clientes que tenemos lo que decía que Freeza por aquí ya debe estar, si no mal recuerdo. Lo que está acá también es el último que registramos y justo lo que decía Noe, se le asigna un ID que es el 1016. Este ID es interno, es exclusivo de Vine y de Valamp. Si tuviéramos en algún momento Vine para diferentes empresas, pues no, serían IDs diferentes. Existen dos opciones, que es la opción de editar, como lo comentaba al inicio, en esta, si entramos, ahí vamos a ver toda la información que nosotros registramos, la parte de detalle, la parte de direcciones, la parte de los contactos, si hay adicionales, información adicional que se tenga la necesidad de agregar, y algunos archivos. Aquí podemos agregar la contancia de situación fiscal, la cuenta bancaria con la que se dio de alta, tal vez algún tema de NDA o algún contrato marco. Bueno, pues aquí lo podemos subir y quedaría ahí en un solo lugar. Desde aquí tenemos el módulo de acciones que en las diferentes pestañas, nos muestra opciones adicionales esta pantalla solamente es de visualización es editable hasta que le damos clic en el botón de editar ahí sí una vez que se cambie cualquier información pues nos dará la opción de guardarla al final antes de salir principalmente en la pestaña de detalles ahorita le voy a dar cancelar para no borrar no modificar nada que no quiera modificar y pues básicamente no sé si haya alguna duda alguna información adicional y yo nada más cuando se va a dar de alta un cliente o un proveedor pero en este caso el cliente nace primero de la propuesta comercial de la del acuerdo comercial que sigue con ese cliente y entonces si se les da se empieza a dar de alta pero primero viene del área comercial hoy vamos a tener un nuevo cliente o de evolución a esta propuesta a algo ya en firme entonces hay que empezar a darlo de alta ese es para los nacionales para los internacionales ese me imagino que no te ha tocado Arturo este pero creo que es algunos algunos datos son diferentes como el caso de Acuntia que es de europeo si no no me ha tocado pero bueno podemos ver el ejemplo de Acuntia también debería haber algún documento legal o fiscal del país o de la región en donde esté dado de alta el proveedor entonces igual pediríamos una un documento de este tipo similar al al RFC o la constancia de situación fiscal de la de la empresa pero es aterrizada a la el CFDI que dice sin efectos fiscales al ser una expresa extranjera.
17:08 - Unidentified Speaker
Correcto.
17:09 - Conference Room (Noe Rocha) - Speaker 1
Tiene una pequeña variación.
17:11 - Arturo Rosas Hernandez
Y el RFC te da un genérico, te da simplemente un consecutivo genérico y te lo propone la herramienta, entonces ahí no hay mucho que hacer. Aquí sí, lo importante, como decía Noe, es que el uso de CFDI sea sin efectos fiscales, porque esto no declara impuestos. O deduzca impuestos de ningún tipo, ni ESR ni van a nada. Adelante.
17:37 - Conference Room (Noe Rocha) - Speaker 1
Oye Arturo, no me queda duda, obviamente la factura se hace solamente PDF, no se genera XML ni se timbra nada ante el SAT, ¿verdad?
17:46 - Arturo Rosas Hernandez
Correcto, sí, qué buen comentario. Entonces, para los nacionales, una vez que generas una factura, pues te genera dos archivos, el PDF y el XML. En temas de fiscalía mexicana, el XML es el que realmente lee sobre todo los bueno cualquier sistema o los sistemas que se habían creado pero sobre todo el del SAT este es el que realmente lee la información que trae la información trae el código y es el que lee los sistemas del SAT y el pdf es simplemente una representación gráfica una imagen de lo que contiene el xml pero el xml es importante y el otro es solamente pues visual un documento visual que normalmente se usa para transacciones de personas de morales o físicas etcétera pero para los sistemas la lectura de los sistemas se hace a través del xml y porque lo menciono porque para para los proveedores nacionales por eso es sin efectos fiscales porque estos no le no se leen de ninguna forma entre sistemas o sea no genera código por decirlo de alguna manera sólo genera un archivo pdf y ese no hay forma de que lo lean los sistemas no simplemente se registra como gasto extranjero y no genera obligaciones fiscales. La información que se llena básicamente es esta, muy parecida a lo que se llena de lado mexicano, las direcciones pues también la dirección que viene contenida en el documento fiscal o legal que los puedan compartir, los contactos normalmente los que nos que tenemos. Este cliente no lo di de alta yo, entonces ahí a lo mejor faltaron algunas información. Pero hay que agregarlas. Pero sí es importante llenarlas. De hecho, que bueno, ahorita me la voy a anotar porque voy a revisar los contactos que una tenemos vez y voy de a ir llenando la información que se tenga y que no esté registrada aquí en la herramienta, básicamente.
19:49 - Conference Room (Noe Rocha) - Speaker 1
Muy bien.
19:50 - Conference Room (Noe Rocha) - Speaker 1
¿Qué más de esta parte de clientes, Johann, podrías ver? No, por esta parte ya entiendo mejor el proceso.
19:59 - Johann
Por esta parte de clientes sería todo. Mi siguiente pregunta, si es que ya no hay nada que contar en ¿Cómo es que se registra en Bind? ¿O qué se hace con esa comisión?
20:36 - Conference Room (Noe Rocha) - Speaker 1
Sí.
20:37 - Arturo Rosas Hernandez
Tengo un poco de duda, si quieres comentarlo, pero el proceso que creamos ya no nos permite ver a nosotros, o a mí, o a nosotros, o al puesto actual.
20:54 - Conference Room (Noe Rocha) - Speaker 1
A ver, si quieres, vuelvo a preguntar, Johann, solo para que ahora te escuche. A ver, dime.
21:04 - Johann
Bueno, ¿ahí me escuchó bien?
21:06 - Conference Room (Noe Rocha) - Speaker 2
Buenos días.
21:07 - Conference Room (Noe Rocha) - Speaker 2
¿Qué tal?
21:08 - Conference Room (Noe Rocha) - Speaker 1
Buenos días.
21:08 - Johann
¿Me escuchó bien? Sí. De acuerdo. Buenos días, Araceli. Buenos días. Aquí. Mi pregunta era, me comentaban que había momentos en donde los montos de factura no coincidían por una fee que ustedes pagaban, ¿cierto? Sí. Entonces, mi pregunta era, ¿qué sucedía con esa fee? Si se registraba en Pero eso ya no nos corresponde a nosotros.
21:33 - Conference Room (Noe Rocha) - Speaker 2
Quien lo registra es el despacho. Hace cuenta que nuestro proceso nada más es en hacer la conciliación y ahí siempre viene un FII y el FII depende del banco que lo mande. Por ejemplo, cuando es de Accent, si es cierto banco, nos cobra un FII. Pero, por ejemplo, si es un banco texano, nos cobra otro FII, aunque sea el depósito al mismo Banorte. Entonces, cuando se hace la conciliación, lo que nosotros pedimos es el estado de cuenta, por eso es importante, del lado del cliente, para saber cuáles facturas nos pagaron, porque nos llega un monto más o menos parecido sin el FII. Pero ese FII, quien lo hace a nivel contable y quien lo deduce y quien hace todo lo necesario, es el despacho. De nuestro lado no hay nada que hacer, No hay nada que conciliar. La conciliación nada más de nuestro lado viene del estado de cuenta de las facturas que pagaron con lo que nos depositó.
22:39 - Johann
Pero de esa parte nosotros no hacemos el asiento contable. Ok, entiendo. Entonces es el despacho quien registra este fee en BIM, ¿cierto?
22:50 - Conference Room (Noe Rocha) - Speaker 2
Exactamente. Ellos hacen un manejo contable para empatar y mapear y que no se nos vaya quedando un residual como como deuda del lado del cliente porque pues eso debería de ser, no? O sea, oye, no me pagaste los ciento cincuenta, me llegaron ciento cuarenta y dos, me debes ocho pesos. No, ellos hacen esa deducción para a nivel fiscal y contable. Siempre que digas o sabes que me pagaste el cien por ciento, aunque no haya sido así con un FI, verdad?
23:19 - Conference Room (Noe Rocha) - Speaker 2
Pero eso ya es por parte del despacho que son FIS bancarios.
23:23 - Conference Room (Noe Rocha) - Speaker 2
Exactamente.
23:24 - Conference Room (Noe Rocha) - Speaker 1
Sí, la transacción. Es lo que cobra el banco por mover el dinero de donde está a las cuentas mexicanas.
23:33 - Conference Room (Noe Rocha) - Speaker 2
Pero esa parte ya no nos corresponde a nosotros, Johann. Nada más si habría que, por ejemplo, cuando el agente de IA haga la conciliación, que identifique que ese es un fin bancario.
23:47 - Johann
¿Verdad?
23:48 - Unidentified Speaker
El proceso.
23:48 - Johann
El proceso. Ok, entiendo.
23:51 - Conference Room (Noe Rocha) - Speaker 1
sería el despacho que autoriza o por saldada una factura con con dicha diferencia exactamente a nivel contable a nivel contable digamos a nivel cuenta nosotros no vamos a poder vamos a tener a lo mejor al momento de la conciliación antes de llevar un tema contable vamos a ver la diferencia pero esa diferencia corresponde al fin no sabemos no tenemos los reyes exactos de cuánto va a ser el fin si es por un monto si es por una cantidad, si es porque ese día es el Día de la Virgen y se lo quiero cobrar más.
24:26 - Conference Room (Noe Rocha) - Speaker 2
Pero siempre viene marcado en el estado de cuenta. Por ejemplo, no es sorpresa en el sentido de que, por ejemplo, dice IVA sobre comisión, comisión de IVA. Yo lo digo porque la gente lo lee y sabe que es una comisión bancaria. Y nada más en los pagos que se reciben de moneda extranjera, es en donde tenemos un FII. Los pagos nacionales no hay ningún FII. Ahí sí nos tiene que cuadrar centavos, verdad? Y nada más en los extranjeros. Por eso en los extranjeros es súper importante que nos pasen en el estado de cuenta. El cliente, el cliente y por ejemplo, no siempre es así, porque por ejemplo, Axios nos paga a nuestra cuenta de Banorte de dólares. Pero por ejemplo, tenemos también la de Y hay otro cliente que se llama Big Tech, que nos paga directamente de un banco americano a otro banco americano. Ahí no nos quitan el fee, la comisión.
25:27 - Conference Room (Noe Rocha) - Speaker 1
O sea, la única forma que tenemos de saber el dato del fee en un pago internacional es pedirle el estado de cuenta al cliente.
25:38 - Conference Room (Noe Rocha) - Speaker 2
O por ejemplo, en Big Tech te hace match la factura con el deporte.
25:44 - Conference Room (Noe Rocha) - Speaker 1
¿Por qué? Porque ese es cuenta americana.
25:47 - Conference Room (Noe Rocha) - Speaker 2
Banco, banco americano.
25:48 - Conference Room (Noe Rocha) - Speaker 1
Pero en el caso específico del ingreso que es Europa a México. Ahí sí. Y ese fin no lo podemos identificar a menos de que nos manden del estado de cuenta.
25:59 - Conference Room (Noe Rocha) - Speaker 2
Se identifica porque en el estado de cuenta viene la comisión. Pero de todas maneras, acuérdate de que diga Johann aquí ya entramos en otro tema. En este caso de ACCIONS hay muchas facturas. Por el mismo monto. Entonces, por eso tenemos que pedir el estado adecuado.
26:19 - Johann
Para estar seguro de que la factura corresponde a qué monto. Exactamente. Entiendo. Esa parte ya me queda clara. Muchas gracias. Gracias. Entonces, este monto de fee se registra en Bain por parte del despacho.
26:39 - Conference Room (Noe Rocha) - Speaker 1
¿En los internacionales específicamente? Y para que no se obtenga un margen, una deuda por parte del cliente. Prácticamente esto lo vamos a ver más con este proveedor, con Acuntia, hoy por hoy. Puede pasar con otro cliente, sí, si tenemos otro proyecto que esté en la misma situación, que sea un banco europeo, que nos tenga que mover el dinero hasta México. Y ahí, evidentemente, pues va a venir la comisión.
27:08 - Johann
Ok. Listo. Muchas gracias por esa explicación. Ya me quedo más claro y voy a trabajar en el productivo también.
27:17 - Conference Room (Noe Rocha) - Speaker 1
Sí, y en el caso de los nacionales pues está identificado directamente en el estado de cuenta.
27:24 - Unidentified Speaker
No hay sorpresa.
27:26 - Johann
Ok, de acuerdo. Ahora, sí, por esta parte ya me quedo muy claro. Muchas gracias. Y otra cosa que me gustaría ver también es respecto a lo de Jira. Comentaba con Erika que durante las sesiones previas me mostraron el proceso y cómo es que de las solicitudes de Jira es donde nacían los tickets para una facturación. De esta manera, aunque no está la propuesta inicial, me gustaría ver la la posibilidad o proponer la solución de que desde Jira se carguen a Bind como cotizaciones, que es el primero de los pasos para llegar a hacer una factura ¿no? Porque sería cotización, prefactura y factura. Sí, yo entiendo eso perfectamente Johann.
28:23 - Conference Room (Noe Rocha) - Speaker 1
Cuando lo hablamos en su momento no estaba, no se tenía en uso Jira para el tema de las propuestas. Entonces sí, yo recuerdo perfectamente que habíamos dicho que inicialmente ni BUC ni GIRA iban a estar dentro del proceso. Lo que pasó en el tiempo es que evolucionó el proceso interno a que todo se fuera por GIRA, hoy por hoy. Entonces de lo que dijimos a lo que está pasando ahorita, hay una variante, que GIRA sí entra en la fórmula hoy por hoy. Para este tema de GIRA y explorar el tema de GIRA, cómo se va a conectar si hay un Si hay un API para extraer la información. No lo explotó yo, habría que verlo con Pedro. Y si quieres, en esta etapa que ahorita estamos de exploración, contemplarlo y ya me dices, oye, bueno, pues a lo mejor aquí va a tener que ser un pequeño ajuste y lo vemos, lo ponemos sobre la mesa, ¿sí?
29:16 - Johann
OK. Sí, me parece bien. Porque en ese caso, les quería preguntar acerca de, dentro de los tickets de gira, ¿cuál es el estatus que un ticket listo para llegar a ser facturación? Sí, mira.
29:32 - Conference Room (Noe Rocha) - Speaker 1
En teoría debe estar en completo. Hay un estatus muy específico de Jira que dice resuelto. Porque mira, aquí lo vemos. Por ejemplo, estos son todos los inicia, dale flujos un actuales. Poquito de zoom Arturo, ahí inicia, luego se va abierto y luego de abierto hacia abajo se va en proceso de facturación, ese proceso de facturación también se puede cancelar, o sea puede ser que ya no ya no ocurra nada y se cancela y ahí muere, pero vamos a seguir suponiendo que ya que se vuelve en factura.
30:10 - Conference Room (Noe Rocha) - Speaker 2
Dale para abajo.
30:11 - Conference Room (Noe Rocha) - Speaker 1
Luego se va a una validación, porque puede ser lo que vimos ahorita, es una validación para una factura nacional o es una factura extranjera. Y esas dos requieren dos procesos diferentes, como ya vimos ahorita. Y la otra nada más la pura factura. Después, ya que está en esa validación, qué tipo de moneda, qué tipo de facturación, en términos generales.
30:32 - Arturo Rosas Hernandez
Y ahora sí, se manda a facturar con todos esos preámbulos, con todos esos detalles, se van directamente a facturar en BIND aquí no dice que se facture en BIND simplemente que aquí todo lo que se tiene que facturar de ese periodo ya está digamos este ya lo tenemos claro que se tiene que ir a facturar para que quede facturado el sistema que después de esto aquí nosotros esto no cubre todo el flujo porque después esto sería a cuentas por cobrar pero digamos que hasta aquí llega el proceso ahorita al día de hoy de la facturación y por qué lo usamos en gira porque son tantos temas que de repente traemos que porque necesitamos tener una visualización de cuántas facturas hay que hacer y si ya están listas para facturar correcto y las evidencias es la documentación el histórico y las evidencias de que se facturó algo no y aparte las autorizaciones porque de repente pudiera suceder que una factura se genera por un peso cuando realmente tuvo que haber sido por 90 centavos y esa diferencia no se observó porque no hubo un flujo o un proceso de autorizaciones o revisiones entonces para eso JIRA nos sirve para crear un proceso estándar de a ver antes de que antes de que envíe esa validación nacional o a validación del pdf y xml mete la proceso de facturación y en este proceso de facturación es confirma el monto, confirma si el proveedor está dado de alta, si con su constancia de situación fiscal está vigente, si su cuenta bancaria, si tiene sus datos de cuenta bancaria o etcétera. Si tienes toda la información necesaria para facturar de manera correcta, incluido el monto que tienes que facturar.
32:20 - Conference Room (Noe Rocha) - Speaker 1
Y en teoría facturado es que ya lo hiciste en la plataforma y ya incluso en facturado ya subiste el xml.
32:28 - Arturo Rosas Hernandez
A ver no, No, no, no, estaba recopilando toda la información necesaria y ya estaba metiendo a Bind toda la información, pero resultó que decían que ya habían facturado, o sea, alguien tomó el ticket, dijo que ya había facturado, pero no había evidencia, no había evidencia de que había facturado, no había número de factura, ni cliente, no había un pdf, un xml, no había nada de evidencia y en los próximos procesos de revisión de que, oye, facturamos junio, oye, facturamos mayo, oye, ¿qué pasó en enero de dos mil veinticinco? No, pues, ¿quién sabe? Ah, bueno, no hay evidencia, entonces, nos dimos cuenta que teníamos que meter un proceso obligado de que se adjuntara un PDF, no podemos asegurar que se suba un PDF justo de la factura que se generó, o sea, no puedo asegurar que es la pero sí obligar a que suban un pdf y un xml ya si alguien no sube la factura correcta pues ya es una mentira muy grande pero la podemos detectar y para eso se metió esa validación y para lo internacional el pdf no obligado subir un pdf y obviamente tiene que ser de la factura generada esto se hizo yo nada más con lo que dice Arturo, porque si tuvimos desaciertos operativos en donde decían, es que ya facturé, y dices, pues dónde está la factura, no, pues no, ah no, pues es que sí facturé, pero facturé otra cosa, dices, o sea no, necesito que factures esto, entonces internamente necesitamos esta validación para decir, oye, ok, ya lo facturaste, ok, validame que efectivamente Aquí en Gira.
34:45 - Conference Room (Noe Rocha) - Speaker 1
Lo que hiciste en Bind. Puedes subirme los archivos a Gira. Porque lo vamos a validar, que efectivamente existe. Y ahora sí, ya podemos decir que está facturado correctamente. Entonces, a tu respuesta, ya para volver. ¿Qué estatus es el que tomamos para saber si algo ya está facturado? Facturado, que diga facturado. ¿Qué es el último status? El resuelto. Porque el anterior solamente es un proceso de validación, pero no nos dice, o sea, no nos confirmas si está bien todo lo que se hizo. Correcto. ¿Correcto?
35:32 - Johann
OK, correcto. Entiendo. Muchas gracias por este diagrama. Me queda ahora sí claro el flujo que se sigue y primero toman un ticket de Jira después hacen todo el proceso online y a la par están actualizando el ticket ¿verdad? El Jira ok de acuerdo ya me quedo claro disculpa Arturo ¿te podría pedir este diagrama?
36:01 - Arturo Rosas Hernandez
sí ¿Le saca un screen o...?
36:05 - Unidentified Speaker
Sí.
36:06 - Arturo Rosas Hernandez
Nada más que sale muy pequeño. La única forma es screenshot. Sale muy pequeño.
36:15 - Johann
El click derecho, ¿no habrá algo de copiar?
36:21 - Arturo Rosas Hernandez
Uy, se ve muy chiquito. Sí.
36:25 - Unidentified Speaker
Si no...
36:26 - Unidentified Speaker
Dale ahí donde dice...
36:30 - Conference Room (Noe Rocha) - Speaker 1
Porque también es interesante los comentarios. Hoy no, no se va a alcanzar a ver. Mira, si lo compartes. Dile a Pedro que si hay forma de verlo en una pantalla más grande. Si no, aquí en la oficina lo proyectamos en una pantalla más grande y de ahí se lo mandamos. Pero la respuesta sí, se te puede mandar. Sí, sí, sí te lo mandamos.
36:50 - Arturo Rosas Hernandez
Mejor te lo mandamos, porque se va a ver muy muy mal y no te va a servir de mucho, entonces mejor enviarlo en buen tamaño para que te sirva realmente para lo que necesites.
37:04 - Johann
De acuerdo, me parece excelente.
37:07 - Arturo Rosas Hernandez
Y ya nada más como perrequisito o como pre, que seguramente será algo que como platicábamos se puede incluir de Jira, tenemos spaces en Jira, ¿no? Entonces, ¿qué son los spaces? Déjame te lo enseño. Son diferentes módulos grandes que concentran actividades, ¿no? Actividades o tickets, tipos de tickets. Entonces, ¿por qué lo menciono? Porque está el request type, digo, el space facturación, y ahí es donde se concentra todo el tema de facturación, hay otro de administración general, otro de GEDEX y otro de recursos humanos, pero es importante mencionar que el de facturación tiene un un espacio específico, único, que es donde se concentra todo el tema de facturación, entonces creo que vale la pena mencionarlo para saber que no está revuelto con el resto de tickets, o sea que hay una forma de cerrar ese universo a un solo tipo de Que se llama, perdón, de SPACE, que se llama... FACTURACIÓN.
38:25 - Unidentified Speaker
FACTURACIÓN.
38:25 - Arturo Rosas Hernandez
Y con diferentes REQUEST TYPE. Pero ahorita solamente uno que es FACTIVACIÓN ADICIONAL, RECURRENTE. Podría haber RECURRENTE ADICIONAL o NUEVA. Pero de momento el tema de los REQUEST TYPE no cambia. Eso es para la facturación.
38:41 - Conference Room (Noe Rocha) - Speaker 1
Pero creo que en la sesión anterior platicaron con Araceli. Que también habían propuesto... Que salían de Gira, ¿no?
38:49 - Arturo Rosas Hernandez
¿Propuestas? ¿O no? ¿Propuestas?
38:51 - Conference Room (Noe Rocha) - Speaker 1
No, además vieron el puro flujo de facturación en la sesión anterior. Johannes, que yo no estuve, por eso pregunto.
38:59 - Johann
Sí, en la sesión anterior vimos el tema de cobranza.
39:04 - Johann
¿Cobranza en Gira?
39:05 - Conference Room (Noe Rocha) - Speaker 1
Ah, no, en Gira no vimos cobranza.
39:08 - Johann
Cuando estuvimos viendo Gira.
39:10 - Conference Room (Noe Rocha) - Speaker 1
La pura cobranza, sí. ¿Y el tema de Gira surgió hasta cuándo?
39:16 - Johann
Fue el primer paso dentro de la facturación, que fue una sesión antes.
39:21 - Conference Room (Noe Rocha) - Speaker 1
Ah, ya. ¿Y qué? ¿Hablaba de esto precisamente? ¿De este tema de facturación?
39:26 - Unidentified Speaker
Sí.
39:27 - Johann
Arturo me mostró un ejemplo de cómo es que o dónde es que se registra un ticket. Me mostró los campos que un ticket te pide para hacer una facturación y después ya se va al taller de y entiendo que se va a este apartado de facturación, y a partir de ahí es donde le dan seguimiento a una factura.
39:52 - Conference Room (Noe Rocha) - Speaker 1
Sí, correcto. Muy bien, aquí entonces lo único es que en esta etapa de descubrimiento, Johann, también te tendría que pasar el API para que exploraras la conexión, ¿verdad, Pedro?
40:03 - Johann
Sí, entonces con ese API yo vendría a buscar la información dentro del grupo de facturación. Y esas serían las facturas con las que se están trabajando.
40:16 - Conference Room (Noe Rocha) - Speaker 1
Con las que se trabajan. En teoría, si toda facturación se ejecuta aquí como proceso inicial y se maquila en Bind. Ok. Y algunas facturas son procesos manuales y otras son procesos ya automáticos de facturación. Que eso si quieres lo platicamos con Pedro. Yo creo que a lo mejor sería bueno tener una sesión adicional con Pedro de este tema, si te parece, para que entiendas cómo son la facturación. Hay un proceso que se llama facturación recurrente y eso sí debo explicártelo por separado, nada más para entender cómo nace, porque no es que alguien se meta y lo pida, sino es un proceso que ya está programado. Y por ejemplo Acuntia, la mayoría de las facturas de Acuntia Vienen automáticamente, ¿verdad Arturo? Como recurrentes.
41:04 - Arturo Rosas Hernandez
Sí, ya tenemos un flujo recurrente como de 30 facturas. Un poco menos. Más o menos. Entonces, en ese flujo de recurrencia, como sea, hay intervención humana. Porque los temas comerciales pueden variar. Es decir, de un mes a otro puede subir o bajar la facturación. No la cantidad de facturas, porque esa más o menos se mantiene constante. Pero a lo mejor el costo de una de esas facturas, el monto, puede variar de un mes a otro.
41:37 - Conference Room (Noe Rocha) - Speaker 1
Y esa recurrencia obedece que hay temas contractuales ya establecidos por un periodo con un proveedor, con un cliente. Entonces si yo ya tengo, es como la casa. Oye, estoy en una casa, tengo que pagar el agua, pues yo sé que mensualmente me va a llegar. Entonces mensualmente nosotros proceso de facturarle al cliente ese servicio que ya tenemos por contrato. Para no tener que hacerlo manual, ya lo hicimos en un proceso que se llama recurrencia. Y son esas facturas que comenta Arturo.
42:08 - Unidentified Speaker
Correcto. Ok.
42:09 - Unidentified Speaker
Entiendo.
42:09 - Johann
Pero eso no está en Vine.
42:11 - Conference Room (Noe Rocha) - Speaker 1
Eso lo hicimos aquí para ejecutarlo en Vine. Porque Vine no tiene, hasta donde sé, no tiene esa esa bondad de poder, oye, pues este es un contrato que vale, no sé, todo inventar. 100 pesos. Entonces, de estos 100 pesos, yo lo tengo que facturar mensualmente, no sé. Bueno, son 12 pesos y tengo que facturarle un peso por mes. Entonces, para mí estaría bien padre, te lo digo para mí, pero ahorita no estamos en ese punto. Es decir, ok, si yo sé que tiene que al final pagar 12 pesos de un contrato fijo para lo que es fijo, pues por mes me tendría que estar descontando un pesito, un pesito y se me va viendo bien. Pues todavía falta por cobrar esto y este es el efectivamente cobrado. ¿Para qué? Pues para saber que no nos estemos pasando o que está ocurriendo algo diferente en la facturación de lo que contractualmente se estableció en un acuerdo comercial. Si ya después eso cambia y hay adegregados o cosas nuevas o cosas que se agregaron, pues a lo mejor verlo por separado. Porque es importante, porque yo creo que eso también nos ayudaría a futuro y no es para ahorita, no es para meterle más leña a la situación. Que si ya tenemos un contrato y un acuerdo, pues también tengo una... ¿Cómo te lo diré? Yo ya sé cuánto es un monto a recibir durante cierto tiempo, para que ya en un tema de dinero o de movimientos fiscales o movimientos internos de lo que va a llegar, oye, ¿cuál va a ser la proyección? Ah, pues por lo menos esto, porque tenemos un contrato y esto nos da una visualización de tanto Entonces, no hemos llegado a ese punto, pero te lo platico porque probablemente después algo así busquemos explorar en todo lo que estamos haciendo.
43:54 - Unidentified Speaker
La proyección.
43:55 - Conference Room (Noe Rocha) - Speaker 1
Ahorita simplemente estamos tratando de resolver lo que tenemos. Es una forma más ágil. Pero ya una vez afinando la máquina, la proyección es importante. Y lo malo es que Vine, hasta donde yo sé, no tiene eso, ¿verdad Arturo?
44:10 - Arturo Rosas Hernandez
Sí te puede generar, pero depende de que alguien lo alimenta, entonces esa parte de alimentar pues si vendría de tus comentarios.
44:18 - Conference Room (Noe Rocha) - Speaker 1
Sí, pero a ver, por ejemplo un contrato que yo tengo por tres años con un cliente que va a ser fijo en teoría por tantos recursos, no me da esa proyección hoy por hoy. Sí, hoy por hoy no. No tengo forma de saber cuál es la proyección de un flujo de efectivo a lo largo de más de un año por lo menos. Es, al día, al corte y a lo que tú haces Arturo, es decir, oye, pues tenemos estas fracturas y el flujo es tanto porque es lo que me tiene que pagar. Es lo que me tiene que pagar.
44:54 - Arturo Rosas Hernandez
No es el acuerdo comercial que tenemos a largo plazo. Exacto. El forecast o el futuro te lo da, pero sobre lo facturado, es decir, oye, y el plazo de pago, es decir, tienes una factura a 30, 60, 90 días plazo de pago, pues entonces dices, esta factura que voy a cobrar 10 pesos me la van a pagar dentro de tres meses entonces para octubre para octubre me debería de caer el dinero no en mi cuenta bancaria entonces el forecast viene de ahí derivado de ahí pero en las cuentas por cobrar un forecast o un pronóstico a largo plazo como este que menciona 9 hoy en un contrato que se gestó o se negoció a un año a 12 24 36 meses No hay forma de declararlo en Vine.
45:40 - Arturo Rosas Hernandez
Y ahorita no es para eso, Johann.
45:42 - Conference Room (Noe Rocha) - Speaker 1
Nada más te lo platico porque a futuro quisiéramos ir afinando las cosas para ahora sí tener un forecast más real. No de lo inmediato, porque tenemos un forecast a corto plazo. Aunque tenemos contratos anuales o por más periodo, hoy por hoy no sabemos, más allá de lo que ya está en Vine por cobrar, qué es lo que esperamos recibir a lo largo del tiempo. ¿Sale? OK.
46:07 - Conference Room (Noe Rocha) - Speaker 1
Muy bien.
46:08 - Unidentified Speaker
¿Qué más, Johanna?
46:09 - Conference Room (Noe Rocha) - Speaker 1
OK.
46:09 - Johann
Por esa parte, ya me queda muy claro que esas eran las preguntas con las que venía el día de hoy. Entiendo que mañana hay una sesión para revisar y validar el prototipo. Sí, ya el prototipo con RSL. Excelente. Entonces, por el día de hoy, esas 3 preguntas acerca de los clientes, del fee. Esta parte de Gira ya me respondió muy bien. Muchas gracias. Y ya me quedó claro.
46:41 - Conference Room (Noe Rocha) - Speaker 1
Y con esto puedo seguir trabajando. JUAN MANUEL LUCERO. Muy bien, Johann. Aquí nomás estoy poniendo un penetre, mandar el flujo desde una visualización más amplia para que lo veas a detalle. Y sesión con Arturo, con Pedro, para explorar lo que es el API. Conexión en Jira. Y ya sobre eso, este, siguientes pasos para platicar.
47:08 - Johann
De acuerdo, ahora mismo estoy utilizando el token que me pasaron de Bind únicamente como lectura. Y desde Jira valdría la pena revisar esta parte de escritura para el ticket de Jira, pasarlo a cotización en Bind y hacer una prueba.
47:31 - Conference Room (Noe Rocha) - Speaker 1
Algo más controlado. Sí. Allí te pediría mucho cuidado Johann cuando lleguemos a esa instancia. Porque no tenemos ambiente de prueba. Es producción. Entonces, nada más ser muy cuidadosos de lo que vamos a hacer. Te lo pediría mucho. O sea, muy, muy medida la prueba de lo que vamos a hacer a escritura. Para no hacernos jaraquiri nosotros.
47:54 - Unidentified Speaker
¿Sale?
47:54 - Unidentified Speaker
Sale.
47:55 - Conference Room (Noe Rocha) - Speaker 1
Bueno, muy bien.
47:56 - Conference Room (Noe Rocha) - Speaker 1
Ya llegando el momento. Lo acordamos muy bien. No se nos puede salir de las manos de la plataforma. Porque en serio, se nos hace una fiesta. Y nos ha costado mucho tener el RP como lo tenemos. Entonces, listo. Sería todo. Gracias por tu tiempo, Johann. Muchas gracias a ustedes.
48:14 - Johann
Que tengan un buen día. Hasta luego. Gracias, bye.
48:17 - Unidentified Speaker
Bye.
@@ -0,0 +1,173 @@
API de conexión con JIRA
Mon, Jul 27, 2026
0:03 - Noe Rocha
Hola Erika, buenos días. ¿Cómo estás? Bien, gracias. Todo muy bien, también. ¿Te confirmó Pedro? Sí. Vamos a esperar. Hola Johann, buenos días. Hola, ¿qué tal? Buenos días.
0:21 - Unidentified Speaker
Hola Erika, hola Pedro.
0:23 - Unidentified Speaker
Buenos días. Hola, buenos días.
0:27 - Pedro Alberto Ayala Elizondo
¿Qué tal? Buenos días.
0:31 - Noe Rocha
Bueno, pues ya estamos todos. Espero que hayan tenido un buen fin de semana. Caluroso, pero buen fin de semana. Bueno, a ver, como propósito del tema, dentro del descubrimiento que está haciendo Johann, Pedro, se ha visto que muchas partes del proceso, que en un principio no se habían especificado, están llegando a través de JIRA. Específicamente para temas de facturación. Como están haciendo de Jira, originalmente no habíamos contemplado la conectividad, pero ahorita ya vemos que va a ser necesario. Entonces, aquí lo que queremos ver contigo y que le expliques a Johann, bueno, más allá de cómo funciona Jira, sino cómo se conecta a través de un API Jira actualmente para extraer información y darle un poquito de vista de... No sé si quieras ver también el proceso ¿O nos vamos directamente a cómo funciona? ¿Cómo estamos haciendo hoy la conectividad a través del API? Sí, con la conectividad a través del API me es suficiente.
1:38 - Johann
Vale, ya está.
1:39 - Noe Rocha
Te dejo el micrófono, Pedro.
1:41 - Noe Rocha
Adelante, por favor. Muy bien.
1:43 - Pedro Alberto Ayala Elizondo
Bueno, con el API de Jira, hoy actualmente se está utilizando... Bueno, yo lo utilizo para varios tableros de servicio de TI. Entonces, yo lo utilizo para varios tableros de TI. Entonces, algunos los tengo para limpieza de usuarios, otros los hago para aprobadores, otros simplemente para conectores. Pero sus principales funciones, más que nada, es para crear y consultar actividades, tickets, el tema de aprobaciones, aprobaciones pendientes, el tema de documentos adjuntos. Sí tiene una muy amplia variedad en temas de extracción. En el que sí tiene mucho de dónde agarrar. Entonces, pues, no sé si tienes alguna pregunta en específico de la API, cómo se gestiona o cómo funciona. O si en verdad no sé si necesitas la llave como tal para generar una con alguna fecha de expiración en específica.
2:46 - Johann
Sí, una API key y también entender por ejemplo ahora que me mencionas que si tiene la posibilidad de extraer por ejemplo los ítems de un tablero y consultar el estatus y cambiar el estatus de esa tarea es es muy útil sí sí todo todo es es accionable es tanto de lectura como de edición entonces vas a poder hacer cualquier tipo de creación que se podría hacer manual pero se puede hacer de manera entonces te paso igual quieres alguna por reporte xt te funciona?
3:25 - Noe Rocha
disculpa con reporte txt?
3:28 - Pedro Alberto Ayala Elizondo
si osea con un documento txt con el api si perfecto dejeme entonces lo genero vamos a llamarle De momento vamos a llamarle... Le estamos llamando Plataforma de Automatización Financiera. Vamos a llamarlo PAF, el token, para que no haya... Vamos a hacerlo de un año de expiración. Hasta el... 27 de julio del 2027. Y te la comparto, ya la tengo, si quieres ahorita te la por correo. Excelente.
4:51 - Johann
No sé si quieren ver algo más, algo que tengan dudas del API en general.
4:57 - Pedro Alberto Ayala Elizondo
Yo creo que van a salir las dudas ya una vez estando en acción con la herramienta, empezar a extraer los datos, empezar a jugar con las consultas. Yo tengo una duda.
5:12 - Noe Rocha
El consumo de APIs es algo parecido a Vine, que te limita en cuanto a extracción?
5:19 - Pedro Alberto Ayala Elizondo
Déjeme ver, porque creo que sí tiene el consumo al lado, pero estaba viendo que no tiene como una página como la de Bind, que es Bind de desarrolladores. Entonces creo que sí tiene una que es Atlassian.
5:40 - Noe Rocha
Si quieres, nomás investiga y luego lo vemos con Johann. En este momento. Porque si voy a tener un límite de transacción por escritura o por consulta, entonces tendremos que ver cómo funciona esto sobre la operación.
5:58 - Pedro Alberto Ayala Elizondo
Sí, creo que no existe uno por día. O sea, por día no hay, por así decirlo.
6:05 - Noe Rocha
Y las APIs las generas desde tu cuenta o... Desde mi cuenta. Las puedes diferenciar, ¿verdad? Con nombre. Con el nombre.
6:15 - Pedro Alberto Ayala Elizondo
Sí, justo así las tengo diferenciadas. De hecho, una práctica sí es ir renovando constantemente, bueno, no constantemente, pero ir renovando en cierto punto los tokens para evitar ambigüedades. Entonces, todavía están ahí todas en la base de datos y van a seguir apareciendo.
6:34 - Unidentified Speaker
Ok.
6:34 - Noe Rocha
¿Qué otra consideración importante es ahí con el uso de la API? De Argentina, particularmente.
6:43 - Pedro Alberto Ayala Elizondo
Pues, como tal, es algo muy intuitivo. Es como cualquier extracción de datos mediante un API. Simplemente haciendo los comandos correctos mediante SQL o algún lenguaje, se pueden extraer los datos de manera clara. Yo, más que nada, lo utilizo para temas de SLA. Yo tengo unos SLA configurados en cada uno de los procesos que tenemos dentro de Jira. Entonces, tengo la configuración para que este, para que este API me esté arrastrando este tipo de información. Y también el tema de la facturación. ¿Con quién está la prover? ¿En qué estatus está? También han habido temas para cambiar estatus que se han podido lograr con el API.
7:29 - Unidentified Speaker
Ok.
7:29 - Noe Rocha
Muy bien. Se fue realmente bastante rápido. Entonces, ¿el acuerdo se lo mandas en un TXT? Sí, ya lo tengo.
7:37 - Pedro Alberto Ayala Elizondo
Y no sé si así como...
7:40 - Noe Rocha
hay una página de desarrolladores de Jira. Simplemente para temas de consulta que tenga que tener Johann sobre el uso.
7:51 - Unidentified Speaker
Ok.
7:52 - Pedro Alberto Ayala Elizondo
Sí, eso todo te lo incluyo ahorita en el correo como informativo. Va, de acuerdo.
8:00 - Unidentified Speaker
Muy bien.
8:01 - Noe Rocha
Johann, ya con esta información, ¿cuál sería su idea?
8:06 - Johann
¿Cuáles serían los siguientes pasos? Los siguientes pasos, de mi parte, yo revisaría la documentación de Jira. También, si me pudieran compartir pronto el nombre exacto del tablero en donde vamos a consultar los tickets, también sería útil para saber a dónde o de dónde extraer esos tickets. Entonces, yo investigo la documentación y con la piqui que me comparte Pedro, ya puedo integrarlo al prototipo que estamos haciendo.
8:35 - Noe Rocha
Pedro. Pero no sé si está identificable a través de la API. O con un nombre. Supongo que con el nombre del tablero.
8:46 - Pedro Alberto Ayala Elizondo
Pero el tablero se refiere al de Power BI.
8:50 - Noe Rocha
No, no. Es que el tablero...
8:53 - Pedro Alberto Ayala Elizondo
Corrígeme, Johann.
8:54 - Noe Rocha
Si te refieres más bien a la... Al Space? Sí, al Space. Así es.
9:01 - Pedro Alberto Ayala Elizondo
Ah, ok, ok. ¿Dónde están almacenados todos los tickets? De facturación. Sí, en la bandeja de facturación.
9:10 - Noe Rocha
Sí, porque hay varias bandejas. Entonces, para que no tengas que buscar en todas. Ser muy específico de a cuál nos referimos.
9:20 - Pedro Alberto Ayala Elizondo
Esas son las bandejas que hay por hoy. Administración General, ITS, Medilo, Recursos Humanos, Facturación. Y por hoy, donde se encuentra lo bueno es aquí.
9:31 - Noe Rocha
Ya. Y si, por ejemplo, cuando tú has hecho la revisión o has usado el API, ¿cómo identificas cuál bandeja es? Por la llave.
9:44 - Pedro Alberto Ayala Elizondo
Por la llave. Esta tiene llave AG, llave DITCM, este es RH, este es FAC y este es HD.
9:54 - Noe Rocha
Ok, entonces la llave para el tablero de facturación debería ser FC. Sí, FAC.
10:00 - Unidentified Speaker
FAC.
10:01 - Pedro Alberto Ayala Elizondo
FAC guión y el numerito. Y esos son todos los correspondientes al... Sí, lo bueno que la API de Jira es global, entonces vas a poder extraer información de todas las banderas, pero la bandeja que nos importa es facturación, pero es que hay ciertas cosas que pasan en recursos humanos que al momento de cerrarse en recursos humanos genera cosas en facturación, también en administración general. Haz de cuenta que facturación es como el, la bandeja padre y se va, es la que se alimenta de varios, de varios que vienen siendo las demás.
10:41 - Unidentified Speaker
Por procesos diferentes.
10:43 - Pedro Alberto Ayala Elizondo
Ajá.
10:44 - Noe Rocha
Que todas vienen cayendo en facturación. Muy bien.
10:49 - Pedro Alberto Ayala Elizondo
Bien, pero, eh, reviso.
10:51 - Noe Rocha
¿Qué más, Johann? Creo que con esto es suficiente.
10:57 - Johann
Igual, cuando comience a ser ya las pruebas, les comparto mis dudas, o si me hablan Hasta entonces voy a estar haciendo un script de consulta. Y si pudieran apoyarme, me gustaría también hacer un script de creación, eliminación y edición de un registro de prueba. Para ver que todo esté correcto y ya de ahí implementarlo.
11:29 - Noe Rocha
O sea ya, digamos, probar una creación de un documento, dices tú?
11:35 - Unidentified Speaker
Sí.
11:36 - Noe Rocha
Si te parece, ya cuando sea el momento de hacer la creación. Hacemos una prueba en vivo. Y veremos cómo funciona.
11:48 - Johann
Sí, sin problema. O también si tienen a la mano un script. Donde ya tengan un CRUD.
11:57 - Noe Rocha
Fíjate que no tenemos algo así, ¿verdad Pedro? A través de API no. No hemos tenido la necesidad de hacerlo. Bueno, si es el checkpoint, entonces tú nos dices, Johann, para hacer para las dudas o para alguna prueba en específico. ¿Te parece? Sí, me parece bien. Vale, pues. Bueno, pues entonces es todo. Gracias por su desmañanada.
12:29 - Pedro Alberto Ayala Elizondo
Buen inicio de semana. Igualmente. Igualmente. Bye. Muchas gracias.
@@ -0,0 +1,57 @@
# Correo — Pedro Ayala → Johann · medición de consumo de la API de Jira y entrega del token
**Canal:** Correo
**Fecha:** 2026-07-27, 07:40 am
**De:** Pedro Alberto Ayala Elizondo `<pedro.ayala@balamtalentoestrategico.com>`
**Para:** Johann · **CC:** Noe Rocha, Erika Chávez
**Asunto:** Seguimiento: medición de consumo API de Jira y accesos
**Relación:** cumple los compromisos de Pedro en la sesión de API de Jira del mismo día ([REGISTRO #56](../bitacora/REGISTRO.md)): entregar el token e investigar los límites de consumo.
---
## Transcripción del correo
> Buenos días, Johan. Espero te encuentres bien.
>
> Gracias por la sesión y por tu tiempo. Te comparto el detalle de cómo se mide el consumo de la API de Jira, porque tiene un par de puntos que hay que tener claros.
>
> **Cómo funciona el límite:**
>
> No existe un límite de volumen del tipo "X llamadas por mes". El uso de la API tampoco genera costo adicional sobre la licencia. Lo que sí existen son los **límites de velocidad**, y actualmente son **tres independientes que operan en paralelo**:
>
> 1. **Cuota por puntos (por hora).** Cada llamada consume puntos según el trabajo que implica: 1 punto base más 1 punto por objeto de dominio (issues, proyectos) o 2 puntos por objeto de identidad (usuarios, grupos, roles). **Las escrituras solo cobran el punto base.** La bolsa por defecto es de **65,000 puntos por hora**.
> 2. **Burst por segundo.** Aplica a todo el tráfico, incluido el de API token. Los defaults son **100 request por segundo para GET y POST, y 50 para PUT y DELETE**, con un bucket independiente por endpoint y por tenant. Hay endpoints con límites propios más bajos; el más notable es el de consulta de clientes de un service desk, **restringido a 5 por segundo**.
> 3. **Límite por issue en escrituras.** **20 operaciones de escritura cada 2 segundos y 100 cada 30 segundos** sobre un mismo ticket.
>
> Cualquiera de los tres devuelve **HTTP 429**. El header **`RateLimit-Reason`** indica cuál se activó.
>
> **Sobre la página de desarrolladores para revisar consumo:** aquí la respuesta es que **no existe y es una limitante de Jira**.
>
> - No hay dashboard de consumo en la administración de Jira. No hay pantalla de administrador ni reporte nativo.
> - El Developer Console de Atlassian solo sirve si uno publica una app propia, y ahí únicamente se ve el tier asignado, no el consumo de la instancia.
> - El detalle de uso por API token requiere **Atlassian Guard Premium**, que es una licencia aparte.
> - Existen apps de terceros en Marketplace que estiman el consumo, pero trabajan por muestreo, no con telemetría real de Atlassian.
>
> La **única fuente confiable son los headers de respuesta**: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-NearLimit` (que se activa cuando queda menos del 20% de capacidad), y en respuestas 429 también `X-RateLimit-Reset`, `Retry-After` y `RateLimit-Reason`.
>
> Te comparto el API token en el siguiente link de Google Drive:
>
> `https://drive.google.com/drive/folders/1J4GZcV7gndpXJ6qlXtcpK6ZiNZbvkM_0?usp=sharing`
>
> Si se presenta algún problema con el acceso, estoy al pendiente.
>
> Saludos,
## Respuesta de Johann
> Enterado, muchas gracias Pedro! Saludos
---
## Notas e implicaciones para el desarrollo
- **Cierra el pendiente de la sesión #56:** ya no hay incógnita sobre el límite. **No hay tope mensual** ni costo por uso; el diseño del sync debe respetar **límites de velocidad**, no un cupo diario como en BIND (20K/día).
- **El sync debe autorregularse leyendo los headers** `X-RateLimit-*`: pausar/reducir ritmo cuando `X-RateLimit-NearLimit` aparezca (<20% de capacidad) y respetar `Retry-After` ante un 429. No hay dashboard, así que la telemetría vive en las respuestas.
- **Las escrituras son baratas en puntos** (solo el punto base): favorece la capa de escritura (crear cotizaciones/tickets) frente a las consultas de identidad (2 puntos c/u).
- **Cuidado con el límite por-issue en escrituras** (20/2 s, 100/30 s por ticket): relevante si la automatización hiciera varias escrituras sobre el mismo ticket en ráfaga.
- ⚠️ **El token vive en el enlace de Google Drive** de arriba — tratar como credencial: descargarlo, moverlo a user-secrets / Key Vault y **no** dejarlo en texto plano en el repo ni en el disco. (El conector de Google Drive de claude.ai requiere autorización; el token no se consultó desde aquí.)
Binary file not shown.
+62
View File
@@ -0,0 +1,62 @@
# Marca Balam — tokens de diseño
> Destilado del **Manual de Imagen Corporativa** que Pedro envió el 1-jul-2026 (evidencia: [`../fuentes/manual de imagen corporativa - Balam.pdf`](../fuentes/manual%20de%20imagen%20corporativa%20-%20Balam.pdf)). Es la fuente oficial de color, tipografía y uso del logo para el **prototipo visual navegable** (Etapa 0) y cualquier UI/entregable de la plataforma.
>
> ⚠️ Ojo: el ámbar de la **propuesta PDF** (`#C0892F`) es un acento editorial de Johann, **no** el amarillo de marca. Para la plataforma y prototipos, usar los tokens de abajo.
## Colores corporativos
| Token | Nombre | HEX | RGB | Uso |
|---|---|---|---|---|
| `--balam-amarillo` | Amarillo | `#F7BD0C` | 245, 189, 12 | Color primario de marca. Logo, acentos, botones, énfasis. |
| `--balam-cafe` | Café | `#331F0E` | 51, 31, 14 | Fondo oscuro de marca, texto sobre claro, superficies. |
| `--balam-blanco` | Blanco | `#FFFFFF` | 255, 255, 255 | Fondo claro, texto sobre café. |
Complementos que aparecen en el manual (sin HEX oficial, apoyo): un **gris neutro** (~`#5C5C5C`) y un **degradado café→amarillo** para fondos/decoración.
```css
:root {
--balam-amarillo: #F7BD0C;
--balam-cafe: #331F0E;
--balam-blanco: #FFFFFF;
--balam-gris: #5C5C5C; /* neutro de apoyo, sin HEX oficial */
}
```
**Combinaciones del manual:** logo amarillo sobre café (versión principal), café sobre amarillo, y monocromático blanco/negro. Mantener contraste alto (café ↔ amarillo/blanco).
## Tipografía
**Familia única: Poppins** (sans-serif geométrica). Pesos disponibles: Light · Regular · Medium · SemiBold · Bold · ExtraBold.
Jerarquía del manual (px a escala de presentación — reescalar a `rem` en web):
| Nivel | Peso | Tamaño manual |
|---|---|---|
| Títulos | SemiBold | 75 px |
| Subtítulos | Regular | 46 px |
| Párrafo | Light | 28 px |
| Botones | Light | 28 px |
```css
/* Poppins vía Google Fonts o self-hosted */
body { font-family: "Poppins", system-ui, sans-serif; }
h1 { font-weight: 600; } /* SemiBold */
h2 { font-weight: 400; } /* Regular */
p { font-weight: 300; } /* Light */
```
## Logo
- **Símbolo:** felino (jaguar) en avance + wordmark `BALAM` con bajada `TALENTO ESTRATÉGICO`.
- **Versiones:** (1) principal a color sobre café · (2) monocromática a color · (3) blanco y negro. Elegir según fondo para máximo contraste.
- **Área de restricción:** margen libre alrededor del logo ≈ la altura de la contramarca ("X"), sin que texto/imágenes/bordes lo invadan.
- **Tamaño óptimo / mínimos:** 484 px, 352 px y **207 px como mínimo** de ancho para legibilidad.
- **Co-branding:** Balam **siempre en primer lugar**, respetando la distancia definida frente al logo del partner.
## Aplicación al prototipo (Etapa 0)
- Tema oscuro de marca: fondo `--balam-cafe`, texto `--balam-blanco`, acción/acento `--balam-amarillo`.
- Tema claro: fondo `--balam-blanco`, texto `--balam-cafe`, acento `--balam-amarillo`.
- Botones primarios en amarillo con texto café; tipografía Poppins en toda la UI.
- Logo en la versión que corresponda al fondo (principal sobre café; b/n cuando el color no aplique).
+57
View File
@@ -0,0 +1,57 @@
# Agenda por día — semana del 20 al 24 de julio 2026
Cierre de la Etapa 1. Cruza los compromisos externos del Excel enviado a Erika el 16-jul
(`Plan-actividades-avance-2026-07-16.xlsx`), los bloques técnicos B0B9 de [Plan-Etapa1.md](Plan-Etapa1.md)
y los pendientes de gestión de [PENDIENTES.md](../bitacora/PENDIENTES.md). Quedan ~2431 h de construcción.
> ⚠️ Desfase a comunicar en la demo del viernes: el Excel compromete la "capa de escritura controlada"
> al mar 22, pero por ADR-001 está bloqueada hasta después de la sesión del mié 22. Se entrega jue 23
> en modo dry-run con flags apagados. El "modelo de facturas + migraciones" (Excel: 2324 jul) en
> realidad se construye primero (B1, lun 20) porque todo el sync depende de él.
## Lunes 20 — fundación de datos + gestión (día de corte de Erika)
**Gestión (primera hora):**
- [ ] 📧 Enviar el correo a Noé + Pedro: salvaguardas + 5 dudas técnicas del API (borrador 1 de [Borradores-seguimiento-tecnico.md](Borradores-seguimiento-tecnico.md)). Le da a Pedro 2 días para investigar antes de la sesión del miércoles.
- [ ] 💬 WhatsApp a Erika/Pedro: flujo de horas en Jira (borrador 2) — lunes es su día de corte.
- [ ] 💬 Recordatorio a Erika: acceso Azure programado esta semana (condiciona el CI/CD del viernes).
- [ ] ⏱️ Validar las horas reconstruidas en [Seguimiento-horas.csv](Seguimiento-horas.csv) (26.92 h estimadas) y confirmar/ajustar las filas del 1619 jul.
- [ ] 📄 Revisar los procedimientos de carga de facturas por cliente (correo de Erika 16-jul); volcar diferencias vs Discovery/prototipo en el punto 3 de [Sesion-Etapa1-2026-07-22.md](Sesion-Etapa1-2026-07-22.md).
**Técnico:****B0, B1, B2 y B3 quedaron ADELANTADOS el domingo 19 en la noche** (ver [REGISTRO #4850](../bitacora/REGISTRO.md)): Postgres 17 local (5438), modelo migrado y sembrado, auth completa con matriz verificada, y **sync de clientes corriendo contra BIND real** (16 clientes, idempotente, dedup correcto). Hallazgo: GUIDs null en producción → modelos corregidos; mencionarlo a Pedro. 5 commits locales — **push pendiente de decisión de Johann**. El lunes queda: gestión en la mañana + **B4** (sync de facturas/cotizaciones + estados + cartera, 4.55.5 h) — con un día completo de colchón vs. el plan.
## Martes 21 — seguridad y primer sync real (~68 h)
- B2 Auth JWT + 4 roles + policies + bitácora de auditoría (45 h).
- B3 Sync de clientes con normalización y dedup por RFC (2.53.5 h) — el Excel lo compromete terminando hoy.
- Seguimiento a Pedro/Noé: arranque de la configuración de Azure (de su lado; no bloquea lo local).
## Miércoles 22 — sesión de definiciones + sync de facturas
**B4 y B6 quedaron ADELANTADOS la noche del martes 21** (ver [REGISTRO #5253](../bitacora/REGISTRO.md)): sync de facturas/cotizaciones con histórico completo verificado (1,494 facturas, cartera MXN/USD cuadrada contra BIND), mapper de estados puro con pruebas, y RLS aplicado (falta solo el rol local `balam_app` para la verificación de aislamiento). Hallazgo para la sesión: **todo el histórico es PUE, cero PPD** — preguntar a Arturo.
- 📅 **Sesión de reglas Etapa 1 (Arturo + CEO).** Llevar [Sesion-Etapa1-2026-07-22.md](Sesion-Etapa1-2026-07-22.md) con la minuta lista y los hallazgos de los procedimientos por cliente. Salidas esperadas: alta de cliente, fee, envío, alcance Jira→BIND, frontera Emitida/Vigente, autorización de escritura.
- Post-sesión: registrar la minuta y actualizar [Hallazgos-y-decisiones-Etapa0.md](Hallazgos-y-decisiones-Etapa0.md) (ADRs afectados).
- Ajustar `InvoiceStatusMapper` con la frontera Emitida/Vigente definida en la sesión (es función pura: minutos).
- Restante técnico de la semana: B5 scheduler, B7 (post-autorización), B8/B9, CI/CD viernes.
## Jueves 23 — escritura controlada + validación del prototipo
- Cerrar B4 si quedó cola; **correr el sync inicial del histórico en la noche — jamás en vivo en demo**.
- B7 Capa de escritura controlada Draft→DryRun→Confirm con flags apagados y cero llamadas reales (34 h), ya con las definiciones del miércoles.
- Avanzar el cierre del documento de hallazgos + ADRs (el Excel lo compromete hoy).
- 📅 **7:00 pm — Validación del prototipo Etapa 0.** Llevar la lista de decisiones que requieren visto bueno y la separación MVP vs Anexo B (recordatorios a clientes = Anexo B; multiempresa = fuera; agentes Jira = Nivel 3).
## Viernes 24 — robustez, CI/CD y cierre de etapa
- B5 Scheduler 15 min con guarda de cuota + backfill (23 h) · B6 RLS real de Postgres (1.52.5 h, contractual, no recortable).
- B8 pruebas de flujos críticos + B9 seeder + runbook (recortables a lo mínimo si aprieta).
- CI/CD + gestión de secretos con Pedro (según acceso Azure).
- 📅 **Demo semanal + reporte de horas.** Meta: login + roles + sync real en Postgres + cartera. Comunicar ahí el ajuste de la capa de escritura (dry-run, pendiente de autorización para escritura real).
- Registrar cierre en bitácora y actualizar Excel de avance para Erika.
## Si aprieta el tiempo (recortes ya identificados en el plan, ≈ 5 h)
`GET /api/audit` y middleware post-demo (1) · dedup solo RFC exacto (0.5) · quotes full-scan simple (0.5) ·
equivalente MXN (0.5) · backfill con tope fijo (0.5) · B7 sin modelos provisionales si el 22 cambia el alcance (1) ·
seeder mínimo (0.5). La demo del viernes exige como mínimo: login + roles + sync + cartera.
Binary file not shown.
+50
View File
@@ -0,0 +1,50 @@
# Corte de avance — Etapa 1
**Fecha:** 16-jul-2026
**Etapa:** Plataforma base y sincronización con BIND
**Rango estimado contractual:** 3239 h
## Mensaje breve para Erika
Hola Erika. Te comparto el Excel actualizado con el avance de la Etapa 1 al día de hoy.
Como puntos principales, el cliente de consulta de BIND ya quedó terminado e integrado en C#, con las salvaguardas acordadas y 13 pruebas automatizadas aprobadas. La estructura base de la plataforma tiene avance parcial y continúo con el modelo de datos, autenticación/roles, separación por tenant y sincronización de clientes y facturas.
En el corte tengo 8 h registradas de esta etapa, cuyo rango estimado es de 3239 h. En el Excel marqué 20% de avance para la Etapa 1: un entregable está terminado y la plataforma base tiene avance parcial.
Ya recibí los procedimientos que me enviaste. Los voy a contrastar con el flujo levantado en las sesiones para incorporar las reglas por cliente. También validaré que el acceso al repositorio incluya permisos de escritura; si requiero algo adicional de su lado te aviso.
**Adjunto:** `Plan-actividades-avance-2026-07-16.xlsx`
## Sustento interno
### Terminado y comprobado
- Solución backend .NET 10 y estructura frontend Angular 21.
- Cliente productivo de BIND en C#, solo lectura por defecto.
- Paginación OData, reintentos, control local de cuota y errores conocidos.
- `GET /health`.
- `GET /api/bind/status`.
- **13/13 pruebas automatizadas aprobadas el 16-jul-2026.**
### En construcción
- Modelo de datos PostgreSQL y migración inicial.
- Autenticación y matriz de roles.
- Aislamiento multi-tenant y RLS.
- Sincronización incremental de clientes, cotizaciones y facturas.
- Endpoints de clientes, facturas, cotizaciones y cartera.
- Scheduler, bitácora operativa y capa de escritura controlada.
### Dependencias externas
- Validar permiso efectivo de escritura en el repositorio privado.
- Revisar los procedimientos por cliente recibidos por correo.
- Cerrar reglas de alta de cliente, fee, envío y Jira→BIND en la sesión del 22-jul.
- Recibir acceso acotado a Azure para despliegue y CI/CD.
## Criterio de medición
- **Horas registradas:** 8.00 h de un rango de 3239 h (**20.525% del esfuerzo estimado**).
- **Entregables:** 1 de 8 terminado; plataforma base con avance parcial.
- No se reporta un porcentaje global único porque mezclar horas consumidas con entregables terminados produciría una cifra engañosa.
+69
View File
@@ -0,0 +1,69 @@
# Corte de avance — Etapa 1
**Fecha:** 27-jul-2026 (corte de los lunes, formato pedido por Erika: entregable + actividad + horas por etapa)
**Etapa:** Plataforma base y sincronización con BIND
**Rango estimado contractual:** 3239 h · **Horas registradas de Etapa 1:** 19.75 h (total del proyecto: 41.58 h)
**Adjunto:** `Plan-actividades-avance-2026-07-27.xlsx`
> Documento interno de Johann. El mensaje para Erika va abajo; el resto es sustento propio (no se comparte).
---
## Mensaje breve para Erika (WhatsApp)
> Hola Erika, buen día. Te comparto el avance de la Etapa 1 al corte de hoy (Excel adjunto, con entregable · actividad · horas por etapa como lo pediste).
>
> El **núcleo de la plataforma ya está construido y probado contra producción**: autenticación con roles y bitácora de auditoría, arquitectura multi-tenant con aislamiento por RLS, el cliente de la API de BIND, la sincronización de clientes, facturas y cotizaciones, el modelo central de facturas con sus estados y la cartera separada por moneda. La sincronización del histórico ya corrió y cuadró: **1,494 facturas** con sus totales de cartera coincidiendo con BIND.
>
> Lo que sigue pendiente es, sobre todo, la **capa de escritura (cotización→factura), que dejé en pausa a propósito hasta que definan el flujo de facturación en la sesión del martes**, ya que de ahí dependen las reglas. También quedan por cerrar el afinado de datos de prueba y la parte de Azure/CI-CD, que depende de los accesos de su lado.
>
> En horas voy en **19.75 h de Etapa 1** (rango estimado 3239 h), con **6 de los 8 entregables de la etapa ya terminados**. Con la key de Jira que nos pasó Pedro hoy y las definiciones del martes, arranco la integración con Jira y la capa de escritura. Cualquier duda quedo al pendiente. 🙌
*(Nota: el ajuste de la propuesta y el conteo de horas formal van por separado; este mensaje es solo el avance de Etapa 1.)*
---
## Sustento interno
### Terminado y verificado contra producción
- **Backend base:** autenticación con JWT propio, matriz de roles (Finanzas, Dirección, Operaciones, Administración) con policies, y **bitácora de auditoría universal** (logins, sync, transiciones, escritura). — *entregable contractual 1*
- **Multi-tenant + RLS real de Postgres** (no solo filtro EF): políticas `tenant_isolation` fail-closed en las 8 tablas de negocio + interceptor de conexión. — *entregable 2**(verificación de aislamiento local pendiente de rol de app no-superusuario; las políticas ya están correctas — ver REGISTRO #53)*
- **Cliente productivo de BIND** en C#: paginación OData, reintentos, control de cuota y errores; solo lectura por defecto. — *entregable 3*
- **Sync de clientes** (full-scan barato + hash + detalle solo de nuevos/cambiados, normalización RFC/nombre, dedup por RFC exacto). — *entregable 5*
- **Sync de facturas y cotizaciones** con estados normalizados, tipo de cambio y detección de pagos (fecha de detección, ADR-004). — *entregable 6*
- **Modelo central de facturas con estados** (Emitida, Vigente, Vencida, Pagada, Cancelada) como función pura con pruebas. — *entregable 7*
- **Cartera por moneda** (jamás suma monedas): `GET /api/cartera` verificado BD↔endpoint — MXN 17 abiertas $1,568,772.32 · USD 92 abiertas $320,379.06.
- **Sync histórico corrido y verificado** (jamás en vivo): 1,494 facturas + 43 cotizaciones, detalle 1,494/1,494, idempotencia comprobada, 0 pagos falsos. (REGISTRO #52)
- 26/26 pruebas unitarias verdes.
### En construcción / en pausa
- **Capa de escritura controlada (cotización→factura)** — *entregable 4*. **Al 40 %: diseño y modelo listos, implementación en pausa.** Ya hecho: entidad `WriteOperation` con el pipeline `Draft→DryRun→Confirmed` migrada, policy `PuedeOperarEscritura`, ADR-001, el diseño del `BindWriteClient` con flags apagados por default y la regla PPD/PUE (informada por el hallazgo de que 1,374/1,374 facturas del histórico son PUE). Falta el `BindWriteClient`, el pipeline implementado, los shapes reales de los POST y las pruebas. 🔴 **Pausa deliberada** hasta la definición del flujo de facturación (sesión martes 28-jul con Arturo/Araceli): de ahí salen las reglas de prefactura, PPD/PUE, alta de cliente y qué estatus de Jira dispara qué.
- **Scheduler + backfill** (sync programado cada 15 min) — el sync ya funciona en manual; falta automatizarlo.
- **Datos de prueba (seeder) + runbook** — *entregable 8*, **al 85 %**: modelo central de facturas con el `InvoiceStatusMapper` (13 pruebas) ✅, migraciones ✅; falta el seeder de datos ficticios y el runbook.
- **Suite de pruebas de flujos críticos** (integración) — pendiente.
### Dependencias externas (lado Balam)
- **Definición del flujo de facturación/prefacturación** — sesión martes 28-jul (Erika coordina). Desbloquea la capa de escritura.
- **Correo del flujo de facturación de Jira** (Erika lo envió 22-jul) — a incorporar.
- **Alcance Jira → cotización BIND al 90 %:** conectividad resuelta el 27-jul (token PAF con vigencia a 1 año, API confirmada de lectura **y** escritura, bandeja **Facturación (FAC)** identificada, límites de consumo aclarados por correo de Pedro: sin tope mensual, 3 límites de velocidad, autorregulación por headers `X-RateLimit-*`). Falta el 10 %: **qué estatus de Jira dispara qué** (amarrado a la definición del 28-jul) y validar si basta escuchar FAC o hay que rastrear los procesos que nacen en RH/Administración General y caen ahí.
- **Acceso a Azure + CI/CD** (Pedro/Noé) — condiciona el despliegue.
## Criterio de medición
- **Entregables contractuales:** **6 de 8 terminados** (1, 2, 3, 5, 6, 7). Los dos restantes van parciales y su avance se muestra en su propia fila del Excel, no promediado en el encabezado: el **8 al 85 %** (migraciones sí, seeder no) y el **4 al 40 %** (escritura: diseño y modelo listos, implementación en pausa por definición de Balam). → **El Excel reporta 75 % de Etapa 1**, contando solo entregables cerrados, que es lo verificable.
- **Horas de Etapa 1:** 19.75 h de un rango de 3239 h (**~5162 % del esfuerzo estimado**).
- Se reporta por **entregable terminado**, no por promedio ponderado de actividades. El corte anterior mostraba 82 % ponderado, que era optimista e indefendible: no distinguía entre trabajo hecho y trabajo bloqueado. "6 de 8" dice exactamente qué falta y de quién depende.
- La brecha entre 75 % de entregables y ~55 % de horas **no es un error**: refleja que las sesiones de desarrollo asistidas por IA produjeron el núcleo en mucho menos tiempo de reloj que la estimación manual (ver la nota en `Seguimiento-horas.md`).
## Horas: estado de la validación (resuelto el 27-jul)
- **41.58 h en total** — Etapa 0: 21.83 h · Etapa 1: 19.75 h.
- **Cero horas pendientes de validar.** 9.13 h con duración documentada (`confirmada`) y 32.45 h reconstruidas y confirmadas por Johann contra evidencia fechada (`validada`).
- Correcciones aplicadas en este corte:
- Se corrigió un error de formato del CSV que ocultaba **1.00 h** del 19-jul (entorno local).
- Se re-etiquetó el 10-jul: la mayor parte eran 6 commits de pulido del prototipo (E0-05), no el entregable de cierre (E0-06). Mismo total, etiquetas correctas.
- Se incorporaron **3.50 h** de trabajo real que no estaba cobrado: diseño del plan de Etapa 1 (2.00 h, `Plan-Etapa1.md`) y preparación de las sesiones del 22 y 24-jul (1.50 h, agenda y guion de validación).
- **Ajustes a la baja** en las horas reconstruidas de Etapa 0: análisis del Discovery de facturación 1.92 → 1.00 h, documentación del de cobranza 1.50 → 0.75 h, guion de validación 0.75 → 0.45 h. Las duraciones de sesión documentadas en transcript no se tocaron.
- Cada celda de horas del Excel se genera desde el CSV y el script **falla** si el detalle no cuadra con el total.
- **Etapa 0 cerró en 21.83 h, dentro del rango contractual de 1822 h.**
## Punto abierto (no bloquea el envío)
- **Tono del mensaje:** el borrador enmarca la capa de escritura como "en pausa por la definición del 28-jul" — pone la pelota de su lado, y es verdad. Si prefieres suavizarlo, se ajusta.
@@ -0,0 +1,34 @@
# Borradores de seguimiento técnico
Mensajes preparados; no enviados. Actualizar si los temas se resuelven en la sesión del 22-jul.
## 1. Correo a Noé y Pedro — salvaguardas y dudas de BIND
**Asunto:** Balam · Salvaguardas activas y dudas técnicas de la API de BIND
Hola Noé, Pedro:
Confirmo que el acceso de BIND se ha utilizado exclusivamente para operaciones de lectura. El cliente bloquea cualquier operación de escritura, controla el número de solicitudes y mantiene el token fuera del repositorio. La validación se realizó sin persistir datos reales y los reportes conservan únicamente estructura y resultados técnicos.
Para cualquier prueba futura de escritura mantendremos los candados definidos en la propuesta: autorización previa, dry-run, confirmación humana y feature flag desactivado por defecto. Si determinan crear un usuario específico de solo lectura, el cambio de token es transparente porque se carga mediante configuración segura.
La validación confirmó que el MVP de consulta, aging y descarga de PDF es viable. Quedaron estas dudas para revisar con ustedes:
1. ¿Existe algún endpoint de pagos individuales o complementos de pago (REP)?
2. ¿Tienen la tabla que relaciona el código interno de `CFDIUse` con la clave SAT?
3. ¿Qué formato devuelve el endpoint `/{id}/xml`?
4. ¿BIND ofrece webhooks o eventos, o debemos operar únicamente con polling?
5. ¿Qué token alimenta actualmente el Power BI? Arturo mencionó el suyo y queremos evitar afectar esa integración si se reemplaza el token.
Quedo atento. Muchas gracias.
Saludos,
Johann Velázquez
## 2. WhatsApp a Erika/Pedro — flujo de horas en Jira
> Hola Erika, Pedro. Para mantener al día el corte de horas, ya inicié un control local por actividad. ¿Me ayudan a confirmar cómo debo registrar las horas en Jira y si necesito que me agreguen a algún proyecto o tablero específico? En cuanto tenga acceso concilio lo que ya llevo y continúo reportando ahí.
## 3. Confirmación al recibir el repositorio
> Listo, ya recibí la invitación y confirmé que tengo acceso de escritura al repositorio. Muchas gracias. Voy a publicar la estructura inicial del backend y les aviso cuando quede disponible.
@@ -0,0 +1,56 @@
# Correo — Respuesta a Noé/Arturo: ticket de ejemplo "como debería ser" + fecha de la prueba acompañada
Enviado · 10-ago-2026
Responder a todos sobre el hilo `RV: Seguimiento: medición de consumo API de Jira y accesos`
**Para:** Noé Rocha · **CC:** Arturo Rosas; Araceli Sánchez; Pedro Ayala; Erika Chávez
**Asunto:** (el del hilo, con `RE:`)
> ⚠️ **Agregar a Arturo y a Erika al CC:** Noé mandó su correo del 7-ago solo con Araceli y Pedro en copia, pero Arturo es quien captura y define. Erika coordina agendas.
**Contexto:** Noé reenvió el 7-ago las respuestas de Arturo del 4-ago, más la definición de que las pruebas serán acompañadas. Las cuatro preguntas del 30-jul quedan cerradas.
**Estrategia — versión mínima.** Solo cinco cosas: agradecer, pedir el ticket de ejemplo, proponer fecha, decir dónde termina el ejercicio y recordar Azure. Todo lo demás se resuelve en la sesión o con el molde. El ticket capturado "como debería ser" hace el trabajo que antes hacían tres párrafos de preguntas: si los conceptos no caben en ningún campo, se ve en el ejemplo.
**Lo que se sacó del correo y ahora hay que llevar A LA SESIÓN** (ninguno se pierde, pero ya no tienen registro escrito previo):
1. 🔴 **ACUNTIA** — que el molde no cubre si Arturo captura un caso normal. `FAC-100` trae un solo monto de 7,594.00 USD para el ticket que históricamente son 4048 facturas. **Es el riesgo más grande de alcance y ya no está pidiéndose por escrito** → preguntarlo en la sesión, o mandar un correo aparte si quieres constancia.
2. ⚠️ **El supuesto de los tickets de `Automation for Jira`** (10 de 69, sin campos, `FAC-91` activo). Ya no queda asentado por escrito que siguen manuales, así que la carga de objetar no está de su lado. Plantearlo en la sesión.
3. **Conceptos/partidas** — se resuelve solo con el molde, pero conviene mirar el ejemplo con esto en mente antes de la sesión.
4. **PUE vs PPD** y **cuenta de servicio** — ya estaban diferidos a la sesión desde la versión anterior.
**Alcance del ejercicio — cotización, NO prefactura.** Razones: (1) es literalmente lo que Arturo contestó el 4-ago; (2) la aprobación de Araceli está entre `En proceso de facturación` y `Facturado`, así que la prefactura pertenece *después* — Noé lo cerró como tres candados: **cotización → prefactura → aprobación humana → timbrado** ([REGISTRO #55](../bitacora/REGISTRO.md)); (3) Arturo pidió gradualismo explícito (*"para ir monitoreando la eficiencia de la IA"*); (4) una cotización se cancela sin efecto fiscal, mientras que en BIND la prefactura **no es un recurso aparte** sino un registro en `Invoices` con `UUID = null`, y los *shapes* de los POST nunca se han probado.
**El disparo es manual en esta prueba.** No es un modo inventado para la ocasión: son las etapas del pipeline ya modelado `Draft → DryRun → Confirmed` (ADR-001) con los feature flags apagados. La versión automática es el mismo código con el flag encendido, y **depende de Azure** para correr continuo.
> ⚠️ **Contradicción pendiente que el ticket de ejemplo resolverá solo:** el 6-jul Ara describió que **el comercial genera la cotización en BIND** y la plataforma la *convierte* a prefactura ([REGISTRO #27](../bitacora/REGISTRO.md)); el 4-ago Arturo dijo que la plataforma la *genera*; y el formulario sigue exigiendo **adjuntar la cotización**. Si ambas cosas ocurren, **quedan dos cotizaciones por ticket**. El adjunto que Arturo ponga en el ejemplo lo dirá.
======================================================================
## VERSIÓN FINAL (la que Johann envía)
Buenas tardes, espero se encuentren bien.
Gracias por las definiciones, quedan claras y ya retomé el desarrollo, ya validé que el campo "Monto sin IVA" está creado y funcionando.
Para aterrizar los detalles que faltan sería de ayuda que Arturo cree hoy o mañana un ticket de ejemplo capturado "como debería ser", con todos los campos llenos tal como quieren que se capture de aquí en adelante. Contra ese molde llego a la sesión con el flujo ya funcionando.
Para la sesión, ¿les funciona el miércoles 12 o el jueves 13, a las 7:00 am?
El ejercicio termina en la cotización en BIND.
Sigo pendiente del acceso a Azure para publicar el ambiente.
Quedo atento.
Saludos.
======================================================================
**Lo que la versión final deja fuera y por tanto pasa a la sesión (verbal, sin constancia escrita previa):**
- **El destino de la cotización de prueba.** El correo ya no dice que el ejercicio genera una cotización real en BIND producción ni que se cancela al terminar. Anunciarlo al abrir la sesión, antes de ejecutar.
- **El compromiso de compartir el script antes.** Era la condición de Noé del 24-jul. Mandarlo igual por separado cuando esté listo.
- **La prefactura como paso siguiente** y los tres candados. Explicarlo en la sesión para que no esperen ver el flujo completo.
- **ACUNTIA** y **el supuesto de los tickets de `Automation for Jira`** (ver arriba).
-**El ticket de ejemplo ya tiene dueño nombrado** (Arturo). Solo falta **agregarlo al CC**: no venía en el correo de Noé del 7-ago.
@@ -0,0 +1,119 @@
# Guion — Validación del prototipo Etapa 0 (jue 23-jul, 7:00 pm)
**Material:** `../prototipo/Prototipo-Balam-Etapa0.pdf` (11 páginas) + demo en paputec.mx/balam.
**Meta de la sesión:** que digan "sí, así opera Balam" pantalla por pantalla → cierra la Etapa 0.
**Regla de oro:** en cada pantalla, terminar con UNA pregunta de validación. No presentar; validar.
---
## Apertura (2 min)
> "Gracias por el tiempo. Lo que van a ver es el proceso que ustedes me enseñaron en las sesiones con Araceli y Arturo, convertido en pantallas. Todo es dato ficticio. El objetivo de hoy es que me digan qué SÍ refleja su operación y qué corregimos — cada 'así no es' de hoy me ahorra semanas de desarrollo."
Aviso útil: "Ayer con Arturo y Araceli aprendí cosas nuevas (fee, flujo Jira); les voy a ir señalando dónde ya sé que hay ajustes."
---
## Pág. 2 · El flujo de principio a fin (3 min)
Recorre los 5 pasos: **Solicitud Jira → Cotización BIND → Prefactura → Aprobación humana → CFDI + Envío**.
> "Este es el mapa de todo. La automatización está donde ustedes la pidieron: después de Jira, y con validación humana antes de timbrar. Aprobar y timbrar son acciones separadas — nada se timbra solo."
**⚠️ AQUÍ VA LA PREGUNTA GRANDE (caja de reglas, primera línea "PPD por defecto"):**
> "Esta regla salió del Discovery: PPD por defecto porque cobran a crédito 3090 días. Pero al sincronizar el histórico real encontré que las 1,374 facturas con método de pago son TODAS PUE, cero PPD. ¿Es política del despacho o práctica que quieren corregir? Cambia el default de la plataforma y toca el requerimiento del SAT que ya vivieron."
Anotar la respuesta — define B7 (capa de escritura).
- Validar también: "¿Recordatorios de morosidad a todos los clientes, sin excepciones — sigue firme?" (lo decidió Ara el 6-jul).
## Pág. 3 · Acceso (30 seg — no gastar tiempo)
> "Ingreso con cuenta interna, control de sesión y roles — cada quien ve lo suyo. Esto ya está construido en el backend real."
## Pág. 4 · Panel de control (4 min)
Señalar en orden: facturado del mes **separado MXN/USD (nunca se suman monedas)** · emitidas vs pendientes · cartera vencida · bandeja "Qué necesita atención".
> "La bandeja es el corazón: bloqueos por falta de cotización, facturas vencidas escaladas, prefacturas esperando aprobación, clientes nuevos sin cédula, facturas emitidas sin enviar. Cada línea tiene responsable y antigüedad."
Dato para credibilidad: "Esto ya no es dibujo — el backend real ya sincroniza la cartera de producción: 1,494 facturas, y los totales cuadran contra BIND al centavo."
**Pregunta:** "¿Son estos los 4 números que quieren ver al abrir? ¿Falta o sobra una tarjeta?" (Recordar: Pedro ya tiene Power BI de aging — esto es operación, no reporteo; no duplico lo suyo.)
## Pág. 5 · Solicitudes (Jira) (3 min)
> "La entrada del flujo: sin ticket, no se factura — tal como operan hoy. Filtros por estatus: por validar, listos, bloqueados, facturados."
Conectar con ayer:
> "Con lo que me mostró Arturo ayer, esto mapea directo a su space 'Facturación' y su flujo de estatus — donde 'resuelto' es el que confirma facturación válida. La sesión con Pedro para el API de Jira nos dirá si estos tickets entran solos o se capturan."
**Pregunta:** "¿Las columnas (tipo, cliente, moneda, monto, crédito, recurrente, estatus) son las que Arturo necesita para decidir qué facturar?"
## Pág. 6 · Detalle de la solicitud (3 min)
Señalar: datos del ticket, adjuntos (cotización, OC, horas con VoBo), doble check de administración, **cotización BIND vinculada como requisito**.
**Nota ⚠️ (fila "Cliente nuevo"):**
> "Ayer Arturo me mostró el alta completa en BIND. La decisión que les pido hoy: cuando el ticket trae un cliente que NO existe en BIND, ¿la plataforma solo lo detecta y avisa a administración, o también lo da de alta? Mi recomendación para el MVP: detectar y bloquear; el alta la hace administración en BIND como hoy."
Anotar decisión — cruza con la estimación de ~10 h de Jira→BIND.
## Pág. 7 · Preparación, aprobación y emisión (4 min)
> "Asistente de 5 pasos: cotización BIND (sin cotización no se puede continuar) → datos de factura → conceptos e IVA 16%/0% con alerta si no cuadra → prefactura en simulación, sin timbrar → aprobación humana. Aprobar NO timbra: son dos clics distintos, de dos momentos distintos."
Reforzar seguridad (le importa a Noé):
> "Y cuando llegue la escritura real: dry-run, confirmación humana por factura y feature flag apagado por defecto — como acordamos ayer, con todo el cuidado de que es producción."
**Pregunta:** "¿Quién aprueba en la vida real — siempre Arturo, o hay segundo aprobador?"
## Pág. 8 · Envío al cliente (3 min)
> "El proceso NO termina al timbrar: termina cuando el correo sale con los adjuntos correctos. Checklist bloqueante por cliente — ejemplo CEMEX: PDF+XML automático, Excel de horas con VoBo, asunto con su nomenclatura exacta. Si falta algo, el envío se bloquea — hoy un error de estos rebota la factura y con 90 días de crédito cada rebote empuja el cobro."
**Pregunta / pendiente:** "Para cargar las reglas reales necesito el Excel de particularidades por cliente que quedó con Ara y Arturo — ¿cómo va? Ya revisé los procedimientos que me mandaron el 16-jul; el Excel me completa destinatarios y nomenclaturas."
## Pág. 9 · Cuentas por cobrar (3 min)
> "El aging que hoy llevan en Excel, leído de BIND: por vencer, 130, 3160, 6190, +90 — MXN y USD siempre separados, el tipo de cambio DOF es solo informativo. Saldo y días de mora por factura."
Credibilidad: "Los números reales ya viven en el backend: la cartera sincronizada cuadra exacta contra BIND."
**Pregunta:** "¿Estos rangos de aging son los que usan? ¿Les sirve el corte por factura o necesitan también por cliente?"
## Pág. 10 · Pagos y recordatorios (4 min) — LA PANTALLA CON MÁS AJUSTES DE AYER
1. **Fee (caja "Tolerancia por comisión"):**
> "Ayer Araceli me aclaró el proceso real: el fee bancario lo registra y deduce EL DESPACHO — Balam no hace ese asiento. Entonces esta pantalla se ajusta: la plataforma DETECTA la diferencia en pagos internacionales, la ETIQUETA como probable fee y avisa; quien salda es el despacho. ¿De acuerdo con ese ajuste?"
2. **Fecha de detección:** "La fecha que muestro es la del registro en BIND (lo captura el despacho), no la fecha valor del banco — BIND no expone pagos individuales. ¿Les funciona así para el MVP?"
3. **Recordatorios (columna derecha) — poner el límite con suavidad:**
> "Ojo con esta parte: las alertas D+1 y el escalamiento D+15 son INTERNAS y van en el MVP. Los correos automáticos AL CLIENTE (D+5, D+30) están cotizados en el Anexo B — aquí los dejo visibles y preparados para activarse, pero no son parte de esta fase. Lo señalo para que no haya sorpresa al cierre."
## Pág. 11 · Bitácora (2 min)
> "Todo queda registrado: quién aprobó, quién emitió, qué override de IVA se hizo y por qué, con ticket Jira y folio BIND. Esto responde exactamente al problema que me contó Arturo ayer: 'dijeron que ya facturaron y no había evidencia'. Aquí la evidencia es automática. Y la bitácora ya existe en el backend real, no solo en el prototipo."
---
## Cierre (5 min)
1. **Pedir el veredicto explícito:**
> "¿Validan que este flujo representa su operación? Con su OK doy por cerrada la Etapa 0, aplico los ajustes que anotamos y el demo público lo doy de baja como quedamos."
2. **Recap de decisiones tomadas hoy** (leerlas en voz alta): PUE/PPD · alta de cliente (detectar vs crear) · fee = despacho confirmado · recordatorios internos vs Anexo B · rangos de aging.
3. **Siguientes pasos** (recordar compromisos de ayer): diagrama del flujo Jira en tamaño legible · sesión con Pedro (API Jira + facturación recurrente) · Excel de particularidades de envío · Azure esta semana.
4. **Si el ambiente lo permite, la comercial:**
> "Ing. Noé, ya de regreso del viaje — ¿pudieron revisar la propuesta v1.2 para lo de la facturación inicial de las 30 horas?"
## Chuleta de respuestas rápidas
- **"¿Y si queremos que también mande correos al cliente?"** → Está cotizado en Anexo B; la pantalla ya lo deja preparado. Lo activamos como ampliación cuando cierre el MVP.
- **"¿Esto ya jala con BIND de verdad?"** → La lectura sí: clientes, facturas, cotizaciones y cartera ya sincronizan de producción, en solo-lectura. La escritura va con los candados acordados.
- **"¿Cuándo estará?"** → Etapa 1 va adelantada (backend, auth, sync y seguridad por tenant ya construidos). Las fechas finas dependen de Azure y de las decisiones de hoy.
- **"¿Multiempresa / Regiotour?"** → Fuera del MVP (un token BIND por empresa); el diseño ya lo soporta a futuro.
- **"¿Forecast por contrato?"** → Lo dijo Noé ayer: no es para ahorita; queda anotado para una fase posterior.
+126
View File
@@ -0,0 +1,126 @@
# Etapa 0 — Hallazgos y decisiones de arquitectura
**Proyecto:** Plataforma de Automatización Financiera · Balam
**Estado:** borrador para cerrar con la validación del prototipo
**Última actualización:** 2026-07-15
## 1. Resultado del Discovery
El flujo operativo confirmado es:
**Jira ITSM → cotización en BIND → prefactura → validación humana → CFDI → envío según reglas del cliente → cobranza**
Reglas de negocio principales:
- Toda factura debe partir de una cotización en BIND.
- La prefactura es obligatoria antes de timbrar.
- PPD es el método predeterminado; PUE requiere una decisión consciente.
- IVA esperado: 16 % en operación nacional y 0 % para operación extranjera sin efectos fiscales, sujeto a las excepciones fiscales que confirme Balam.
- El alta de un cliente nuevo es un flujo separado y requiere definición final de Arturo.
- Los recordatorios se desean para todos los clientes; los correos automáticos externos permanecen fuera del MVP original (Anexo B) hasta confirmar alcance.
- La cobranza se controla por factura y folio. Debe tolerar diferencias por comisiones/fees conforme a la regla que confirme Arturo.
## 2. Resultado de la validación de BIND
La prueba del 6-jul realizó 117 solicitudes exclusivamente GET contra la cuenta real, sin persistir datos de Balam.
Confirmado:
- Saldo por factura viable con `Total - Payments - CreditNotes`.
- Cotizaciones, prefacturas, facturas, clientes, impuestos, PPD/PUE, vencimientos y PDF son consultables.
- Aging y alertas internas son viables sin consultar pagos individuales.
- El volumen proyectado de sincronización consume aproximadamente 5 % del límite de 20,000 solicitudes diarias.
Restricciones:
- No se encontró endpoint de pagos individuales ni complementos de pago (REP).
- BIND no expone el vínculo cotización→factura; la plataforma deberá conservarlo.
- Algunos campos clave solo aparecen en el detalle de cada factura.
- No hay webhooks confirmados; el diseño base usará sincronización incremental por polling.
- El token está acotado a una sola empresa.
- La cuenta actual es de producción y puede tener privilegios elevados; no se autoriza escritura todavía.
Detalle técnico: [`../bind-api-sandbox/VALIDACION-API.md`](../bind-api-sandbox/VALIDACION-API.md).
## 3. Decisiones de arquitectura
### ADR-001 · Lectura primero y escritura controlada
**Decisión:** operar inicialmente en modo solo lectura. Toda escritura futura requiere autorización expresa, dry-run, confirmación humana y feature flag desactivado por defecto.
**Motivo:** Balam no cuenta con sandbox y una operación incorrecta puede tener efecto fiscal.
### ADR-002 · Sincronización incremental
**Decisión:** persistir en PostgreSQL el último punto de sincronización y consultar únicamente registros nuevos o modificados. Paginar siempre con lotes de hasta 100.
**Motivo:** BIND no ofrece conteos ni `nextLink`; PPD/PUE y días de crédito requieren consultas de detalle.
### ADR-003 · Trazabilidad propia
**Decisión:** almacenar las relaciones `ticket Jira → cotización BIND → factura BIND` en la base de datos de la plataforma.
**Motivo:** la API de BIND no expone de forma confiable el vínculo cotización→factura.
### ADR-004 · Detección de pagos
**Decisión:** para el MVP, detectar pagos mediante cambios de estatus y saldo residual. Registrar la fecha de detección, no presentarla como fecha valor.
**Motivo:** no se encontró un recurso de pagos/REP. La fecha contable real requerirá información adicional o una ampliación.
### ADR-005 · Separación por empresa
**Decisión:** el MVP opera únicamente con la empresa Balam asociada al token. Multiempresa queda fuera del alcance.
**Motivo:** cada empresa requiere su propia cuenta/token de BIND.
### ADR-006 · Integración Jira→BIND pendiente de alcance
**Decisión:** diseñar el modelo para conservar el identificador del ticket, pero no comprometer todavía la automatización que crea cotizaciones desde Jira.
**Motivo:** el Discovery confirmó a Jira como entrada del proceso, pero la integración automática no estaba incluida explícitamente en el MVP. Antes de desarrollarla se requiere:
- Confirmación de alcance.
- Cuenta técnica y acceso API/OAuth a Jira.
- Webhook o regla de automatización.
- Mapeo de campos y estatus disparador.
- Acceso controlado de escritura a BIND.
## 4. Preguntas que deben cerrarse
### Con Arturo / CEO — sesión del 22-jul
1. Flujo definitivo de alta de cliente nuevo.
2. Tratamiento en BIND de diferencias por comisión/fee.
3. Particularidades de envío por cliente.
4. Estatus de Jira que autoriza crear una cotización.
5. Campos obligatorios y manejo de tickets incompletos.
### Con Pedro / Noé
1. Endpoint de pagos individuales o REP.
2. Mapeo interno de `CFDIUse` a clave SAT.
3. Formato de respuesta de `/{id}/xml`.
4. Disponibilidad de webhooks en BIND.
5. Token utilizado por Power BI y decisión sobre usuario de solo lectura.
6. Permisos e identidad técnica para Jira, si se aprueba la integración.
## 5. Dependencias de infraestructura
| Dependencia | Estado al 15-jul | Impacto |
|---|---|---|
| Token BIND | Entregado; uso solo lectura | Desbloquea consultas y cliente BIND |
| Repositorio privado GitHub | Autorizado por Noé; invitación pendiente | Necesario para publicar backend/frontend |
| Azure | Programado para semana del 21-jul | No bloquea desarrollo local |
| CI/CD y secretos | Actividad separada para 24-jul | Depende de repo y Azure |
| Jira técnico | No solicitado todavía | Solo bloquea integración automática Jira→BIND |
## 6. Criterio de cierre de Etapa 0
La Etapa 0 se cierra cuando:
- Balam valida el prototipo o registra ajustes.
- Se incorporan las decisiones de la sesión del 22-jul.
- Se valida el prototipo en la sesión del 23-jul.
- Este documento se actualiza con las respuestas finales.
- Se emite un plan refinado con alcance explícito para Jira, recordatorios externos y escritura en BIND.
+411
View File
@@ -0,0 +1,411 @@
# 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 4048 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` (45 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 4048 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`.**
+128
View File
@@ -0,0 +1,128 @@
# Plan de ejecución — Etapa 1 · Plataforma base y sincronización con BIND
**Proyecto:** Plataforma de Automatización Financiera · Balam
**Ventana:** 1324 jul 2026 (semanas 23) · **Rango contractual:** 3239 h · $19,200$23,400 + IVA
**Corte de referencia:** 16-jul-2026 · 8.00 h registradas → restan ~2431 h
**Repo de código:** `github.com/pedro-balam-itsm/BALAM` (clonado en `balam-plataforma/`)
> Documento interno de Johann. NO compartir con Balam ni commitear en el repo del cliente.
> Fuentes: propuesta v1.2 (§Etapa 1, L142157), ADR-001…006 (`Hallazgos-y-decisiones-Etapa0.md`),
> `bind-api-sandbox/VALIDACION-API.md`, `Seguimiento-horas.md`, REGISTRO #40#45.
## 1. Estado al 16-jul — entregables contractuales
Objetivo contractual: *"Plataforma funcional que ingiere clientes y facturas de BIND vía API, los normaliza, mantiene su trazabilidad y habilita la capa de escritura controlada."*
| # | Entregable (propuesta L148155) | Estado |
|---|---|---|
| 1 | Backend con autenticación, roles (Finanzas, Dirección, Operaciones, Administración) y bitácora de auditoría universal | ❌ Solo existe la entidad `AuditLogEntry` |
| 2 | Arquitectura multi-tenant (`tenant_id` + RLS), sin alta autoservicio | ❌ |
| 3 | Cliente de la API de BIND (reintentos, OData, límites, errores) | ✅ **Terminado** — C#, 13 pruebas xUnit, salvaguardas del sandbox |
| 4 | Capa de escritura controlada (cotización→factura con dry-run + confirmación + feature flag + bitácora) | ❌ Bloqueada hasta el 22-jul (solo backend; la UI es Etapa 2) |
| 5 | Sincronización programada de clientes (normalización y deduplicación) | ❌ |
| 6 | Sincronización programada de facturas y cotizaciones (estado normalizado, tipo de cambio, paginación) | ❌ |
| 7 | Modelo central de facturas con estados (Emitida, Vigente, Vencida, Pagada, Cancelada) | ❌ |
| 8 | Migraciones versionadas y datos de prueba | ❌ |
Avance parcial no contractual ya hecho: solución .NET 10 compilando (Api/Domain/Infrastructure/Integrations.Bind), `BalamDbContext` con `SyncCheckpoint`/`AuditLogEntry`, endpoints `/health` y `/api/bind/status`, frontend Angular 21 + Material con tema de marca, CLAUDE.md del repo con reglas duras y salvaguardas.
## 2. Calendario e hitos externos
| Fecha | Hito |
|---|---|
| jue 17-jul | Fin de la ventana planeada de backend base + multi-tenant |
| **vie 18-jul** | **Demo semanal (30 min, Pedro + gerencia):** meta = login + roles + sync real de BIND en Postgres + endpoint de cartera |
| sem 21-jul | Acceso Azure (Pedro + Noé) — no bloquea trabajo local |
| **mié 22-jul** | **Sesión de definiciones Etapa 1** (Arturo + CEO): alta de cliente, fee, particularidades de envío, alcance Jira→BIND. Agenda en [Sesion-Etapa1-2026-07-22.md](Sesion-Etapa1-2026-07-22.md) |
| jue 23-jul 7 pm | Validación del prototipo de Etapa 0 |
| vie 24-jul | CI/CD + gestión de secretos · demo y cierre de etapa |
## 3. Plan de construcción — fases y bloques
Dependencias: B1 → (B2, B3); B3 → B4; B4 → B5; B1 → B6; B2+B1 → B7; todo → B8/B9. B6 y B7 son paralelizables.
**Mínimo para la demo del 18-jul:** B0 + B1 + B2-núcleo + B3 + B4 (≈ 1415 h desde el 16-jul).
### F1 (16-jul) — Fundación de datos
- **B0 · Preparación local (0.51 h):** `docker-compose.yml` con Postgres 17 (puerto 5433 para no chocar); cadena de conexión en `appsettings.Development.json`; `DesignTimeDbContextFactory`; referencia Infrastructure → Integrations.Bind. Docker 29.x ya instalado; `dotnet-ef` 10.0.4 global (invocarlo desde PowerShell — el PATH de git-bash no lo ve).
- **B1 · Modelo de datos + Identity + migración inicial + seed (3.54.5 h):**
- Entidades nuevas en `Balam.Domain/Entities/`: `Tenant`, `Client` (Id = GUID de BIND; `NormalizedRfc`, `NormalizedName`, `DuplicateOfClientId`, `SourceHash`, `DetailSyncedAtUtc`), `Invoice` (modelo central: `Uuid` null ⇒ prefactura, `OpenBalance` recalculado en sync, `CfdiPaymentTermRaw` PPD/PUE del detalle, `PaidDetectedAtUtc`, `LastKnownPlatformStatus`), `Quote`, `QuoteInvoiceLink` (ADR-003; incluye `JiraTicketKey` — ADR-006), `InvoiceStatusChange` (ADR-004), `WriteOperation` (nace aquí para no re-migrar).
- Extender `SyncCheckpoint` y `AuditLogEntry` con `TenantId`; índice único `(TenantId, Resource)`.
- `BalamDbContext``IdentityDbContext<BalamUser, IdentityRole<Guid>, Guid>` (`BalamUser` vive en Infrastructure; Domain queda puro).
- Convenciones ANTES de la primera migración: fechas de BIND (sin zona) → `timestamp without time zone`; timestamps propios `*Utc``timestamptz`; montos `decimal(18,2)`, `ExchangeRate (18,6)`.
- Migración `Inicial` + `DbSeeder` idempotente: tenant Balam (GUID fijo), 4 roles, 5 usuarios ficticios `*@balam.dev` (password vía `Seed:DefaultPassword`; jamás datos reales).
### F2 (17-jul) — Seguridad, bitácora y primer sync real
- **B2 · Auth + roles + bitácora (45 h):** ASP.NET Core Identity + JWT propio (`AddIdentityCore` + `AddJwtBearer`; NO `MapIdentityApi` — emite tokens opacos, el contrato dice JWT). `POST /api/auth/login`, `GET /api/auth/me`. Roles sin acentos como identificador (`Finanzas`, `Direccion`, `Operaciones`, `Administracion`). Policies nombradas (`PuedeVerCartera`, `PuedeDispararSync`, `PuedeVerBitacora`, `PuedeOperarEscritura`). `Jwt:SigningKey` en user-secrets/Key Vault con fail-fast (mismo patrón que `Bind:ApiKey`). **Sin refresh tokens en E1** (se difieren a Etapa 2 con la UI). Bitácora universal en dos piezas — NO interceptor de `SaveChanges` (inundaría con los upserts del sync): `AuditMiddleware` (peticiones mutantes + 401/403) e `IAuditLogger` explícito (logins, resumen de cada ciclo de sync, transiciones de estado, TODA operación de escritura). `GET /api/audit` (Direccion/Administracion).
- **B3 · Sync de clientes (2.53.5 h):** la lista `Clients` NO tiene campo de fecha filtrable ⇒ full-scan barato de lista cada ciclo (~13 páginas con `PaginateAsync`) + comparación por `SourceHash` + **detalle solo para nuevos/cambiados** (ahí viven `CreditDays` y contactos). Normalización RFC/nombre (mayúsculas, sin acentos, sin sufijos societarios). Dedup MVP: marcar `DuplicateOfClientId` por `NormalizedRfc` exacto **excluyendo RFCs genéricos** (`XAXX010101000`/`XEXX010101000`); sin fuzzy matching. `POST /api/sync/run` (manual, para la demo) + `GET /api/sync/status`.
### F3 (18-jul am) — Cierre de demo
- **B4 · Sync de facturas/cotizaciones + estados + cartera (4.55.5 h):**
- Facturas: delta `$filter=Date ge datetime'{cursor}'` + **re-barrido de la ventana de facturas abiertas** (los pagos caen en facturas viejas que el delta por fecha no atrapa) + detalle (1 GET c/u) SOLO nuevas/cambiadas con tope `Sync:MaxDetailPerCycle` (50). Nunca re-barrer todo el detalle (histórico > 1,000 filas).
- Estados de plataforma como **función pura con pruebas** (`InvoiceStatusMapper`): Cancelada (`BindStatus=2`) → Pagada (`BindStatus=1` o saldo ≤ 0.01 con abonos) → Vencida (timbrada, saldo > 0, `ExpirationDate` < hoy MX) → Vigente (timbrada, en plazo) → Emitida (prefactura: `Uuid` null). ⚠️ Frontera Emitida/Vigente a confirmar el 22-jul — por eso es función pura, cambiarla cuesta minutos. Vencida/Vigente se computan en la consulta (dependen de "hoy"); lo persistido es `LastKnownPlatformStatus` solo para detectar transiciones.
- Detección de pagos (ADR-004): transición → fila en `InvoiceStatusChanges` con **fecha de DETECCIÓN** (nunca presentarla como fecha valor) + `PaidDetectedAtUtc`.
- Cotizaciones: delta por `CreationDate` con fallback a full-scan (filtro no validado contra producción); partidas `Items[]` NO se persisten en E1.
- Moneda: catálogo `Currencies` (4 filas, 1 GET/ciclo) → `CurrencyCode` sin pedir detalle.
- Endpoints: `GET /api/cartera` (agregados **por moneda — nunca sumar monedas entre sí**), `GET /api/invoices?status=&clientId=`, `GET /api/clients?search=` (marca duplicados), `GET /api/quotes`.
- **El sync inicial del histórico se corre el jueves 17 en la noche — jamás en vivo en la demo** (en demo solo el incremental, <10 req).
### F4 (21-jul) — Robustez
- **B5 · Scheduler + backfill (23 h):** `BackgroundService` + `PeriodicTimer` cada 15 min (NO Quartz/Hangfire: un solo job, estado en checkpoints, sin dashboard). `SemaphoreSlim(1,1)` anti-solape; guarda de cuota vía `BindQuotaTracker` (si `Remaining < Sync:QuotaReserve` = 500, el ciclo se salta y se audita). Backfill gradual del detalle histórico por ciclo. Presupuesto validado: <10 req/ciclo ≈ 1,000 req/día = 5 % de la cuota. Nota Azure: requiere Always On + instancia única.
- **B6 · RLS + tenancy (1.52.5 h):** RLS **real** de Postgres (compromiso contractual, no basta el filtro EF): migración con `ALTER TABLE ... ENABLE/FORCE ROW LEVEL SECURITY` + política `tenant_isolation` con `current_setting('app.tenant_id', true)::uuid` y `WITH CHECK`, por tabla de negocio; `TenantConnectionInterceptor` (`set_config` al abrir conexión); filtro global EF (`ITenantOwned` + `ICurrentTenantProvider` con tenant fijo del seed) como segunda capa. Fuera: CRUD de tenants, resolución por request, RLS sobre tablas Identity.
### F5 (22-jul, después de la sesión) — Escritura controlada
- **B7 · Capa de escritura controlada (34 h):** pipeline `Draft → DryRun → Confirm` persistido en `WriteOperations`, todo auditado. `BindWriteClient : BindClient` (hereda `RequestAsync` protected y sus salvaguardas). Flags `BindWrite:Enabled=false` y `BindWrite:AllowConvertToInvoice=false` por default. PPD default; PUE solo con `"confirmoPue": true` explícito (un PUE erróneo ya les costó un requerimiento del SAT). **CERO llamadas reales a BIND** — shapes de los POST provisionales (TODO hasta leer la doc del portal con Pedro); la conversión mock registra `QuoteInvoiceLink`. `Bind:Mode=Write` queda documentado como bloqueado hasta autorización expresa (ADR-001).
### F6 (2324 jul) — Cierre
- **B8 · Suite de pruebas de flujos críticos (2.53.5 h):** nuevo proyecto `tests/Balam.Api.Tests` (xUnit + `WebApplicationFactory` + **SQLite in-memory**; NO EF InMemory — no valida FKs/únicos; NO Testcontainers — exige red). Cobertura contractual: matriz de roles 401/403/200, sync (delta/checkpoint/detección de pago), multimoneda (cartera no mezcla), salvaguardas de escritura (flag/modo/bitácora). Costo aceptado: RLS y `timestamptz` son Postgres-specific → verificación manual en runbook.
- **B9 · Datos de prueba + runbook (12 h):** `DevDataSeeder` ficticio multimoneda/multi-estado (entregable 8 y respaldo de demo si BIND fallara); runbook: compose up → run (migra+siembra) → login → sync en vivo → cartera → bitácora → `/api/bind/status`.
## 4. Presupuesto de horas
| Bloque | Horas | ¿Recortable si aprieta? |
|---|---|---|
| B0 Preparación local | 0.51 | No |
| B1 Modelo + Identity + migración + seed | 3.54.5 | No (fundacional) |
| B2 Auth + roles + bitácora | 45 | `GET /api/audit` y middleware → post-demo (1) |
| B3 Sync clientes + dedup | 2.53.5 | Dedup solo RFC exacto (0.5) |
| B4 Sync facturas/cotizaciones + cartera | 4.55.5 | Equivalente MXN (0.5); quotes full-scan simple (0.5) |
| B5 Scheduler + backfill | 23 | Backfill con tope fijo (0.5) |
| B6 RLS + tenancy | 1.52.5 | **No recortable a cero** (contractual) |
| B7 Escritura controlada (dry-run) | 34 | Sin modelos BIND provisionales si el 22-jul cambia el alcance (1) |
| B8 Suite de pruebas | 2.53.5 | Solo casos redundantes |
| B9 Datos de prueba + runbook + colchón | 12 | Seeder mínimo (0.5) |
| **Total** | **2531** (nominal ~27.5) | Recortes identificados ≈ 5 h |
Primer recorte si el viernes se complica: bitácora consultable y sync de cotizaciones se posponen al lunes 21 — la demo exige login + roles + sync + cartera.
## 5. Decisiones de arquitectura (registro)
1. **Scheduler:** `BackgroundService` + `PeriodicTimer`, no Quartz/Hangfire — un solo job, estado ya persistido en `SyncCheckpoints` (ADR-002), cero esquema extra.
2. **RLS en dos capas:** políticas reales de Postgres (compromiso "tenant_id + RLS") + filtro global EF como defensa; sin resolución de tenant por request (ADR-005: tenant único).
3. **Identity + JWT sin refresh tokens** en E1; se agregan en Etapa 2 con la UI Angular.
4. **Bitácora:** middleware HTTP + `IAuditLogger` explícito; NO interceptor EF (el primer sync insertaría > 1,000 entradas de ruido).
5. **Pruebas con SQLite in-memory**; RLS/`timestamptz` quedan a verificación manual documentada (candidato a job de integración cuando exista CI el 24-jul).
6. **Trampas resueltas por convención:** fechas Npgsql (BIND sin zona), "hoy" con `America/Mexico_City`, `partial class Program` para `WebApplicationFactory`, BD obligatoria con fail-fast.
## 6. Bloqueado y fuera de alcance
**Bloqueado hasta la sesión del 22-jul (no adelantar):** escritura real a BIND (ADR-001); reglas de alta de cliente, fee y particularidades de envío; alcance Jira→BIND (ADR-006 — solo se persiste el folio); semántica exacta Emitida/Vigente; mapeo `CFDIUse`→clave SAT.
**Fuera de la Etapa 1:** UI (Etapa 2); refresh tokens (E2); recordatorios a clientes (Anexo B); multiempresa (ADR-005); fecha valor de pagos/REP (ADR-004 — solo fecha de detección); aging 30/60/90 y tablero (Etapa 3); conciliación bancaria; CI/CD y Azure (actividades propias, 2124 jul); envío de PDF (aunque `InvoicePdfAsync` ya existe).
## 7. Riesgos y pendientes de gestión
**Riesgos técnicos:** primera corrida del sync en vivo (mitigado: jueves noche); filtro `CreationDate` de Quotes sin validar (fallback full-scan desde el día uno); repo visible al cliente (solo datos ficticios, passwords de seed configurables, sin co-autoría en commits).
**Gestión que toca la etapa:**
- Correo formal a Noé con las salvaguardas (borrador listo en [Borradores-seguimiento-tecnico.md](Borradores-seguimiento-tecnico.md)).
- 5 preguntas técnicas a Pedro: pagos/REP, tabla `CFDIUse`→SAT, shape de `/{id}/xml`, webhooks vs polling, token del Power BI.
- Revisar los **procedimientos de carga de facturas por cliente** que Erika envió por correo el 16-jul (insumo para particularidades de envío).
- Borrar `bind_token_api.txt` del disco (el token ya vive en user-secrets).
- Registrar horas diario en [Seguimiento-horas.csv](Seguimiento-horas.csv) y conciliar con Jira cuando Pedro lo habilite.
- Preparar la sesión del 22-jul con [Sesion-Etapa1-2026-07-22.md](Sesion-Etapa1-2026-07-22.md).
Binary file not shown.
Binary file not shown.
Binary file not shown.
+22 -16
View File
@@ -1,37 +1,43 @@
# Plan de actividades — Etapas 0 a 3 # Plan de actividades — Etapas 0 a 3
**Proyecto:** Plataforma de Automatización Financiera · Balam **Proyecto:** Plataforma de Automatización Financiera · Balam
> Fechas tentativas — el arranque depende de la entrega de accesos por Balam; se confirman en el kickoff. Las etapas 2 y 3 son estimadas y se afinan al cerrar el Discovery (Etapa 0). Total ~67 semanas (6-jul → 21-ago). > Fechas tentativas. Este documento incorpora los ajustes y el corte de avance al 16-jul y se mantiene sincronizado con el [Excel oficial consolidado](Plan-actividades-avance-2026-07-16.xlsx). Las etapas 2 y 3 se afinan al validar el prototipo y cerrar las definiciones de la Etapa 1. Total estimado: ~67 semanas.
>
> Las horas reales se registran en [`Seguimiento-horas.csv`](Seguimiento-horas.csv); el porcentaje de avance no sustituye ese registro.
## Etapa 0 ## Etapa 0
| Actividad | Inicio | Fin | Responsable | Apoyo de Balam | | Actividad | Inicio | Fin | Responsable | Apoyo de Balam |
|---|---|---|---|---| |---|---|---|---|---|
| Sesión de arranque (kickoff) con el Ing. Noé | 01/07/2026 | 01/07/2026 | Johann | Sí — Noé y Erika (confirmada, 7am) | | Sesión de arranque (kickoff) con el Ing. Noé | 01/07/2026 | 01/07/2026 | Johann | ✅ Realizada (1-jul, 7am) — Noé, Pedro, Erika |
| Sesión de Discovery: proceso actual de facturación y cobranza | 06/07/2026 | 07/07/2026 | Johann | Sí — quien lleva el proceso hoy | | Sesión de Discovery: facturación, envío y cobranza | 06/07/2026 | 07/07/2026 | Johann | ✅ Realizada — Araceli + Arturo |
| Entrega y validación de accesos (BIND, Azure, manual de marca) | 06/07/2026 | 07/07/2026 | Balam / Johann | Sí — API BIND, Azure, manual de marca | | Accesos iniciales: token BIND + manual de marca | 01/07/2026 | 06/07/2026 | Balam / Johann | ✅ Entregados y validados |
| Validación técnica de la API de BIND con la cuenta real | 07/07/2026 | 08/07/2026 | Johann | Apoyo: llave de API | | Validación técnica de la API de BIND con la cuenta real | 06/07/2026 | 06/07/2026 | Johann | ✅ Realizada: 117 GET, sin escritura |
| Configuración de infraestructura en Azure (+ staging) | 08/07/2026 | 09/07/2026 | Johann | Apoyo: accesos de Azure | | Prototipo visual navegable | 08/07/2026 | 10/07/2026 | Johann | ✅ Entregado por correo el 10-jul; validación pendiente |
| Repositorio + CI/CD + gestión de secretos | 08/07/2026 | 09/07/2026 | Johann | | | Repositorio privado GitHub | 13/07/2026 | 16/07/2026 | Balam / Johann | Invitación recibida y acceso confirmado; falta validar permiso de escritura |
| Prototipo visual navegable (56 pantallas) | 08/07/2026 | 10/07/2026 | Johann | Apoyo: manual de marca | | Configuración de infraestructura en Azure (+ staging) | 21/07/2026 | 23/07/2026 | Johann | Apoyo: acceso acotado de Azure (Pedro+Noé); no bloquea trabajo local |
| Sesión de validación del prototipo | 10/07/2026 | 10/07/2026 | Johann | Sí — Pedro y Araceli | | CI/CD + gestión de secretos | 24/07/2026 | 24/07/2026 | Johann | Depende de repo y Azure |
| Documento de hallazgos + ADRs + plan refinado | 10/07/2026 | 10/07/2026 | Johann | | | Documento de hallazgos + ADRs + plan refinado | 10/07/2026 | 23/07/2026 | Johann | Borrador creado; cerrar tras las sesiones del 2223 jul |
| Sesión de validación del prototipo | 23/07/2026 | 23/07/2026 | Johann | Confirmada a las 7:00 pm con CEO/equipo Balam |
**Entregable Etapa 0 (1822 h): prototipo navegable + infraestructura Azure + repo/CI-CD + documento de hallazgos.** **Entregable Etapa 0 (1822 h): prototipo navegable + infraestructura Azure + repo/CI-CD + documento de hallazgos.**
## Etapa 1 ## Etapa 1
> Plan detallado de ejecución: [Plan-Etapa1.md](Plan-Etapa1.md)
| Actividad | Inicio | Fin | Responsable | Apoyo de Balam | | Actividad | Inicio | Fin | Responsable | Apoyo de Balam |
|---|---|---|---|---| |---|---|---|---|---|
| Backend base: autenticación, roles y bitácora de auditoría | 13/07/2026 | 15/07/2026 | Johann | | | Backend base: autenticación, roles y bitácora de auditoría | 13/07/2026 | 17/07/2026 | Johann | Trabajo local; publicar al recibir el repositorio |
| Arquitectura multi-tenant (tenant_id + RLS) | 14/07/2026 | 15/07/2026 | Johann | — | | Arquitectura multi-tenant (tenant_id + RLS) | 14/07/2026 | 17/07/2026 | Johann | — |
| Sesión de reglas de negocio con Arturo | 13/07/2026 | 13/07/2026 | Johann | Sí — Arturo | | Sesión de reglas y dudas de Etapa 1 | 22/07/2026 | 22/07/2026 | Johann | Confirmada con Arturo + CEO |
| Definición de alcance Jira → cotización BIND | 22/07/2026 | 23/07/2026 | Johann / Balam | Requiere confirmar si la integración automática entra al MVP antes de pedir token técnico |
| Cliente de la API de BIND (reintentos, OData, errores) | 15/07/2026 | 17/07/2026 | Johann | — | | Cliente de la API de BIND (reintentos, OData, errores) | 15/07/2026 | 17/07/2026 | Johann | — |
| Capa de escritura controlada (cotización→factura) | 17/07/2026 | 22/07/2026 | Johann | — | | Capa de escritura controlada (cotización→factura) | 17/07/2026 | 22/07/2026 | Johann | — |
| Sincronización de clientes | 20/07/2026 | 21/07/2026 | Johann | — | | Sincronización de clientes | 20/07/2026 | 21/07/2026 | Johann | — |
| Sincronización de facturas y cotizaciones | 21/07/2026 | 23/07/2026 | Johann | — | | Sincronización de facturas y cotizaciones | 21/07/2026 | 23/07/2026 | Johann | — |
| Modelo de facturas + migraciones + datos de prueba | 23/07/2026 | 24/07/2026 | Johann | — | | Modelo de facturas + migraciones + datos de prueba | 23/07/2026 | 24/07/2026 | Johann | — |
| Demostración semanal (viernes) + reporte de horas | 10/07/2026 | 24/07/2026 | Johann | Sí — Erika/Pedro | | Demostración semanal (viernes) + reporte de horas | 10/07/2026 | 24/07/2026 | Johann | Sí — Erika/Pedro; control local en `Seguimiento-horas.csv` mientras Jira se habilita |
**Entregable Etapa 1 (3239 h): plataforma base que sincroniza clientes y facturas de BIND, con capa de escritura controlada.** **Entregable Etapa 1 (3239 h): plataforma base que sincroniza clientes y facturas de BIND, con capa de escritura controlada.**
@@ -41,7 +47,7 @@
|---|---|---|---|---| |---|---|---|---|---|
| Implementación productiva de las pantallas (Angular Material) + integración con el backend | 27/07/2026 | 31/07/2026 | Johann | — | | Implementación productiva de las pantallas (Angular Material) + integración con el backend | 27/07/2026 | 31/07/2026 | Johann | — |
| Listado de facturas (filtros, búsqueda, paginación) + detalle con descarga PDF/XML | 28/07/2026 | 31/07/2026 | Johann | — | | Listado de facturas (filtros, búsqueda, paginación) + detalle con descarga PDF/XML | 28/07/2026 | 31/07/2026 | Johann | — |
| Catálogo de clientes + lista blanca configurable (ACUNTIA + Top 3) | 03/08/2026 | 04/08/2026 | Johann | — | | Catálogo de clientes + reglas de cobranza | 03/08/2026 | 04/08/2026 | Johann | Lista blanca actualmente vacía: recordatorios para todos |
| Creación de cotizaciones + conversión a factura vía API de BIND | 31/07/2026 | 04/08/2026 | Johann | — | | Creación de cotizaciones + conversión a factura vía API de BIND | 31/07/2026 | 04/08/2026 | Johann | — |
| Emisión multimoneda MXN/USD + flujo con confirmación humana y dry-run | 04/08/2026 | 06/08/2026 | Johann | — | | Emisión multimoneda MXN/USD + flujo con confirmación humana y dry-run | 04/08/2026 | 06/08/2026 | Johann | — |
| Tipo de cambio del DOF (proceso programado) | 05/08/2026 | 05/08/2026 | Johann | — | | Tipo de cambio del DOF (proceso programado) | 05/08/2026 | 05/08/2026 | Johann | — |
@@ -57,7 +63,7 @@
|---|---|---|---|---| |---|---|---|---|---|
| Sesión: alcance del tablero vs el Power BI existente (con Pedro) | 10/08/2026 | 10/08/2026 | Johann | Sí — Pedro | | Sesión: alcance del tablero vs el Power BI existente (con Pedro) | 10/08/2026 | 10/08/2026 | Johann | Sí — Pedro |
| Módulo de cobranza: antigüedad de cartera (30/60/90) + por vencer y vencidas | 10/08/2026 | 12/08/2026 | Johann | — | | Módulo de cobranza: antigüedad de cartera (30/60/90) + por vencer y vencidas | 10/08/2026 | 12/08/2026 | Johann | — |
| Alertas internas configurables para Finanzas + aplicación de lista blanca | 12/08/2026 | 13/08/2026 | Johann | | | Alertas internas configurables para Finanzas | 12/08/2026 | 13/08/2026 | Johann | Correos automáticos al cliente requieren confirmar ampliación de alcance |
| Tablero directivo de cuentas por cobrar | 13/08/2026 | 15/08/2026 | Johann | — | | Tablero directivo de cuentas por cobrar | 13/08/2026 | 15/08/2026 | Johann | — |
| Reportes operativos configurables (CSV/XLSX/PDF) | 17/08/2026 | 18/08/2026 | Johann | — | | Reportes operativos configurables (CSV/XLSX/PDF) | 17/08/2026 | 18/08/2026 | Johann | — |
| Endurecimiento de seguridad + respaldos + plan de recuperación | 18/08/2026 | 19/08/2026 | Johann | — | | Endurecimiento de seguridad + respaldos + plan de recuperación | 18/08/2026 | 19/08/2026 | Johann | — |
Binary file not shown.
+36
View File
@@ -0,0 +1,36 @@
fecha,semana,etapa,actividad_id,actividad,horas,estado_hora,fuente_evidencia,facturable,notas
2026-07-01,2026-W27,0,E0-01,Sesión de arranque con Noé,1.00,confirmada,bitacora/REGISTRO.md#22,si,Sesión calendarizada de 7:00 a 8:00 am
2026-07-01,2026-W27,0,E0-01,Preparación de plan kickoff y materiales,1.00,validada,planeacion/Kickoff-2026-07-01.md,si,validada por Johann 27-jul
2026-07-06,2026-W28,0,E0-02,Discovery de facturación y envío,1.08,confirmada,bitacora/REGISTRO.md#27,si,Duración documentada: aproximadamente 1 h 5 min
2026-07-06,2026-W28,0,E0-02,Preparación y análisis de Discovery de facturación,1.00,validada,bitacora/REGISTRO.md#27,si,"Completa 2.08 h con la sesión; ajustada a la baja por Johann 27-jul"
2026-07-06,2026-W28,0,E0-03,Coordinación y validación de accesos BIND y marca,1.00,validada,bitacora/REGISTRO.md#28-31,si,Recepción documentación y salvaguardas; validada por Johann 27-jul
2026-07-06,2026-W28,0,E0-04,Validación técnica de API BIND,4.50,validada,bind-api-sandbox/VALIDACION-API.md,si,117 GET análisis y reporte técnico; validada por Johann 27-jul
2026-07-07,2026-W28,0,E0-02,Discovery de cobranza,1.00,confirmada,bitacora/REGISTRO.md#35,si,Sesión calendarizada de 7:00 a 8:00 am; sin grabación
2026-07-07,2026-W28,0,E0-02,Preparación y documentación de Discovery de cobranza,0.75,validada,fuentes/2026-07-07 - Notas - Proceso actual de cobranza (sin grabacion).md,si,"Sin grabación; notas escritas a mano; ajustada a la baja por Johann 27-jul"
2026-07-08,2026-W28,0,E0-05,Diseño y construcción del prototipo,3.00,validada,prototipo/Prototipo-Etapa0.html,si,Primera mitad del esfuerzo reconstruido; validada por Johann 27-jul
2026-07-09,2026-W28,0,E0-05,Ajustes de cobranza navegación y prototipo,3.00,validada,prototipo/Prototipo-Etapa0.html,si,Segunda mitad del esfuerzo reconstruido; validada por Johann 27-jul
2026-07-10,2026-W28,0,E0-05,"Pulido final del prototipo (bandeja, modal Edo. cuenta, login, capturas)",1.50,validada,prototipo/Prototipo-Etapa0.html,si,"6 commits 00:44-01:52 (b358570..8da11ea) + 9 capturas + logo oficial; validada por Johann 27-jul"
2026-07-10,2026-W28,0,E0-06,Entregable de cierre Etapa 0: PDF hallazgos plan refinado y correo,1.50,validada,prototipo/Correo-prototipo-Etapa0.md,si,PDF generado 10:43; hallazgos y plan refinado; validada por Johann 27-jul
2026-07-13,2026-W29,1,E1-01,Backend base autenticación roles y auditoría,2.00,validada,planeacion/Plan-actividades.md,si,validada por Johann 27-jul
2026-07-13,2026-W29,1,E1-02,Coordinación del repositorio GitHub,0.50,validada,bitacora/REGISTRO.md#43,si,Seguimiento de creación y acceso; validada por Johann 27-jul
2026-07-14,2026-W29,1,E1-01,Backend base autenticación roles y auditoría,1.50,validada,planeacion/Plan-actividades.md,si,Trabajo local; completa 3.50 h; validada por Johann 27-jul
2026-07-14,2026-W29,1,E1-03,Arquitectura multi-tenant,1.00,validada,planeacion/Plan-actividades.md,si,Diseño inicial tenant_id y RLS; validada por Johann 27-jul
2026-07-15,2026-W29,1,E1-03,Arquitectura multi-tenant,0.50,validada,planeacion/Plan-actividades.md,si,Completa 1.50 h; validada por Johann 27-jul
2026-07-15,2026-W29,1,E1-04,Cliente productivo de API BIND,2.00,validada,bind-api-sandbox/VALIDACION-API.md,si,Inicio de reintentos OData y manejo de errores; validada por Johann 27-jul
2026-07-15,2026-W29,1,E1-05,Seguimiento ajuste de calendario y corte de horas,0.50,validada,bitacora/REGISTRO.md#41-45,si,Actualización de plan y control; validada por Johann 27-jul
2026-07-16,2026-W29,1,E1-06,Scaffold backend .NET 10 + frontend Angular 21 y push al repo de Balam,2.00,validada,bitacora/REGISTRO.md#46,si,Commits 220942a..1f7f098; incluye CLAUDE.md del repo; validada por Johann 27-jul
2026-07-16,2026-W29,1,E1-05,Corte de avance Etapa 1 para Erika (Excel + mensaje),1.00,validada,planeacion/Avance-Etapa1-2026-07-16.md,si,Enviado 8:40 pm por WhatsApp con acuse; validada por Johann 27-jul
2026-07-19,2026-W29,1,E1-06,"Preparación de entorno local (clon del repo, SDK .NET 10, secrets, app corriendo)",1.00,validada,bitacora/REGISTRO.md#47,si,API y frontend verificados en local; 13/13 pruebas verdes; validada por Johann 27-jul
2026-07-19,2026-W29,1,E1-08,"Diseño del plan de ejecución de Etapa 1 (bloques B0-B10, ADRs, orden)",2.00,validada,planeacion/Plan-Etapa1.md,si,Arquitectura y decisiones previas a las sesiones de desarrollo; validada por Johann 27-jul
2026-07-19,2026-W29,1,E1-06,Scalar UI para el OpenAPI del backend,0.25,confirmada,bitacora/REGISTRO.md#48,si,Sesión asistida por IA; /scalar/v1 verificado
2026-07-19,2026-W29,1,E1-01,B0+B1: Postgres 17 local + modelo de datos + Identity + migración Inicial + seed,1.00,confirmada,bitacora/REGISTRO.md#48,si,Sesión asistida por IA (noche del domingo); 16 tablas migradas y siembra verificada; tiempo real de sesión
2026-07-19,2026-W29,1,E1-01,B2: login JWT + policies por rol + bitácora de auditoría,0.50,confirmada,bitacora/REGISTRO.md#49,si,Sesión asistida por IA; matriz 401/403/200 verificada end-to-end; tiempo real de sesión
2026-07-19,2026-W29,1,E1-01,B3: sync de clientes contra BIND real + fix de modelos (GUIDs null),0.50,confirmada,bitacora/REGISTRO.md#50,si,"Sesión asistida por IA; 16 clientes sincronizados, idempotencia verificada; tiempo real de sesión"
2026-07-21,2026-W30,1,E1-01,B4: sync de facturas/cotizaciones + estados + cartera por moneda + sync histórico,1.00,confirmada,bitacora/REGISTRO.md#52,si,Sesión asistida por IA; 1494 facturas y 43 cotizaciones sincronizadas de producción; tiempo real de sesión
2026-07-21,2026-W30,1,E1-03,B6: RLS real de Postgres por tenant (migración + interceptor + filtros EF),0.50,confirmada,bitacora/REGISTRO.md#53,si,Sesión asistida por IA; verificación manual en psql; tiempo real de sesión
2026-07-21,2026-W30,1,E1-05,Cierre de sesión: Excel de avance regenerado + bitácora + control de horas,0.25,confirmada,bitacora/REGISTRO.md#52-53,si,Sesión asistida por IA; tiempo real de sesión
2026-07-21,2026-W30,1,E1-05,Preparación de la agenda de la sesión de reglas de Etapa 1,0.75,validada,planeacion/Sesion-Etapa1-2026-07-22.md,si,Agenda y preguntas para la sesión del 22-jul; validada por Johann 27-jul
2026-07-22,2026-W30,1,E1-05,"Sesión de reglas Etapa 1 con Noé, Arturo y Araceli (alta de clientes, fee, flujo Jira)",0.80,confirmada,bitacora/REGISTRO.md#54,si,Duración real ~48 min según transcript (7:007:48 am)
2026-07-23,2026-W30,0,E0-07,Preparación del guion de validación del prototipo,0.45,validada,planeacion/Guion-validacion-prototipo-2026-07-23.md,si,"Guion del recorrido de la demo del 24-jul; ajustada a la baja por Johann 27-jul"
2026-07-24,2026-W30,0,E0-07,"Sesión de validación del prototipo Etapa 0 con Noé, Arturo y Araceli — APROBADO",1.05,confirmada,bitacora/REGISTRO.md#55,si,"Duración ~1 h 4 min según transcript; Etapa 0 validada, queda 1 definición de proceso (flujo Jira)"
2026-07-27,2026-W31,1,E1-07,"Sesión de API de Jira con Pedro (token PAF, bandeja FAC)",0.20,confirmada,bitacora/REGISTRO.md#56,si,~12 min; token PAF comprometido (1 año) por correo; integración inicia tras definición del flujo 28-jul
1 fecha semana etapa actividad_id actividad horas estado_hora fuente_evidencia facturable notas
2 2026-07-01 2026-W27 0 E0-01 Sesión de arranque con Noé 1.00 confirmada bitacora/REGISTRO.md#22 si Sesión calendarizada de 7:00 a 8:00 am
3 2026-07-01 2026-W27 0 E0-01 Preparación de plan kickoff y materiales 1.00 validada planeacion/Kickoff-2026-07-01.md si validada por Johann 27-jul
4 2026-07-06 2026-W28 0 E0-02 Discovery de facturación y envío 1.08 confirmada bitacora/REGISTRO.md#27 si Duración documentada: aproximadamente 1 h 5 min
5 2026-07-06 2026-W28 0 E0-02 Preparación y análisis de Discovery de facturación 1.00 validada bitacora/REGISTRO.md#27 si Completa 2.08 h con la sesión; ajustada a la baja por Johann 27-jul
6 2026-07-06 2026-W28 0 E0-03 Coordinación y validación de accesos BIND y marca 1.00 validada bitacora/REGISTRO.md#28-31 si Recepción documentación y salvaguardas; validada por Johann 27-jul
7 2026-07-06 2026-W28 0 E0-04 Validación técnica de API BIND 4.50 validada bind-api-sandbox/VALIDACION-API.md si 117 GET análisis y reporte técnico; validada por Johann 27-jul
8 2026-07-07 2026-W28 0 E0-02 Discovery de cobranza 1.00 confirmada bitacora/REGISTRO.md#35 si Sesión calendarizada de 7:00 a 8:00 am; sin grabación
9 2026-07-07 2026-W28 0 E0-02 Preparación y documentación de Discovery de cobranza 0.75 validada fuentes/2026-07-07 - Notas - Proceso actual de cobranza (sin grabacion).md si Sin grabación; notas escritas a mano; ajustada a la baja por Johann 27-jul
10 2026-07-08 2026-W28 0 E0-05 Diseño y construcción del prototipo 3.00 validada prototipo/Prototipo-Etapa0.html si Primera mitad del esfuerzo reconstruido; validada por Johann 27-jul
11 2026-07-09 2026-W28 0 E0-05 Ajustes de cobranza navegación y prototipo 3.00 validada prototipo/Prototipo-Etapa0.html si Segunda mitad del esfuerzo reconstruido; validada por Johann 27-jul
12 2026-07-10 2026-W28 0 E0-05 Pulido final del prototipo (bandeja, modal Edo. cuenta, login, capturas) 1.50 validada prototipo/Prototipo-Etapa0.html si 6 commits 00:44-01:52 (b358570..8da11ea) + 9 capturas + logo oficial; validada por Johann 27-jul
13 2026-07-10 2026-W28 0 E0-06 Entregable de cierre Etapa 0: PDF hallazgos plan refinado y correo 1.50 validada prototipo/Correo-prototipo-Etapa0.md si PDF generado 10:43; hallazgos y plan refinado; validada por Johann 27-jul
14 2026-07-13 2026-W29 1 E1-01 Backend base autenticación roles y auditoría 2.00 validada planeacion/Plan-actividades.md si validada por Johann 27-jul
15 2026-07-13 2026-W29 1 E1-02 Coordinación del repositorio GitHub 0.50 validada bitacora/REGISTRO.md#43 si Seguimiento de creación y acceso; validada por Johann 27-jul
16 2026-07-14 2026-W29 1 E1-01 Backend base autenticación roles y auditoría 1.50 validada planeacion/Plan-actividades.md si Trabajo local; completa 3.50 h; validada por Johann 27-jul
17 2026-07-14 2026-W29 1 E1-03 Arquitectura multi-tenant 1.00 validada planeacion/Plan-actividades.md si Diseño inicial tenant_id y RLS; validada por Johann 27-jul
18 2026-07-15 2026-W29 1 E1-03 Arquitectura multi-tenant 0.50 validada planeacion/Plan-actividades.md si Completa 1.50 h; validada por Johann 27-jul
19 2026-07-15 2026-W29 1 E1-04 Cliente productivo de API BIND 2.00 validada bind-api-sandbox/VALIDACION-API.md si Inicio de reintentos OData y manejo de errores; validada por Johann 27-jul
20 2026-07-15 2026-W29 1 E1-05 Seguimiento ajuste de calendario y corte de horas 0.50 validada bitacora/REGISTRO.md#41-45 si Actualización de plan y control; validada por Johann 27-jul
21 2026-07-16 2026-W29 1 E1-06 Scaffold backend .NET 10 + frontend Angular 21 y push al repo de Balam 2.00 validada bitacora/REGISTRO.md#46 si Commits 220942a..1f7f098; incluye CLAUDE.md del repo; validada por Johann 27-jul
22 2026-07-16 2026-W29 1 E1-05 Corte de avance Etapa 1 para Erika (Excel + mensaje) 1.00 validada planeacion/Avance-Etapa1-2026-07-16.md si Enviado 8:40 pm por WhatsApp con acuse; validada por Johann 27-jul
23 2026-07-19 2026-W29 1 E1-06 Preparación de entorno local (clon del repo, SDK .NET 10, secrets, app corriendo) 1.00 validada bitacora/REGISTRO.md#47 si API y frontend verificados en local; 13/13 pruebas verdes; validada por Johann 27-jul
24 2026-07-19 2026-W29 1 E1-08 Diseño del plan de ejecución de Etapa 1 (bloques B0-B10, ADRs, orden) 2.00 validada planeacion/Plan-Etapa1.md si Arquitectura y decisiones previas a las sesiones de desarrollo; validada por Johann 27-jul
25 2026-07-19 2026-W29 1 E1-06 Scalar UI para el OpenAPI del backend 0.25 confirmada bitacora/REGISTRO.md#48 si Sesión asistida por IA; /scalar/v1 verificado
26 2026-07-19 2026-W29 1 E1-01 B0+B1: Postgres 17 local + modelo de datos + Identity + migración Inicial + seed 1.00 confirmada bitacora/REGISTRO.md#48 si Sesión asistida por IA (noche del domingo); 16 tablas migradas y siembra verificada; tiempo real de sesión
27 2026-07-19 2026-W29 1 E1-01 B2: login JWT + policies por rol + bitácora de auditoría 0.50 confirmada bitacora/REGISTRO.md#49 si Sesión asistida por IA; matriz 401/403/200 verificada end-to-end; tiempo real de sesión
28 2026-07-19 2026-W29 1 E1-01 B3: sync de clientes contra BIND real + fix de modelos (GUIDs null) 0.50 confirmada bitacora/REGISTRO.md#50 si Sesión asistida por IA; 16 clientes sincronizados, idempotencia verificada; tiempo real de sesión
29 2026-07-21 2026-W30 1 E1-01 B4: sync de facturas/cotizaciones + estados + cartera por moneda + sync histórico 1.00 confirmada bitacora/REGISTRO.md#52 si Sesión asistida por IA; 1494 facturas y 43 cotizaciones sincronizadas de producción; tiempo real de sesión
30 2026-07-21 2026-W30 1 E1-03 B6: RLS real de Postgres por tenant (migración + interceptor + filtros EF) 0.50 confirmada bitacora/REGISTRO.md#53 si Sesión asistida por IA; verificación manual en psql; tiempo real de sesión
31 2026-07-21 2026-W30 1 E1-05 Cierre de sesión: Excel de avance regenerado + bitácora + control de horas 0.25 confirmada bitacora/REGISTRO.md#52-53 si Sesión asistida por IA; tiempo real de sesión
32 2026-07-21 2026-W30 1 E1-05 Preparación de la agenda de la sesión de reglas de Etapa 1 0.75 validada planeacion/Sesion-Etapa1-2026-07-22.md si Agenda y preguntas para la sesión del 22-jul; validada por Johann 27-jul
33 2026-07-22 2026-W30 1 E1-05 Sesión de reglas Etapa 1 con Noé, Arturo y Araceli (alta de clientes, fee, flujo Jira) 0.80 confirmada bitacora/REGISTRO.md#54 si Duración real ~48 min según transcript (7:00–7:48 am)
34 2026-07-23 2026-W30 0 E0-07 Preparación del guion de validación del prototipo 0.45 validada planeacion/Guion-validacion-prototipo-2026-07-23.md si Guion del recorrido de la demo del 24-jul; ajustada a la baja por Johann 27-jul
35 2026-07-24 2026-W30 0 E0-07 Sesión de validación del prototipo Etapa 0 con Noé, Arturo y Araceli — APROBADO 1.05 confirmada bitacora/REGISTRO.md#55 si Duración ~1 h 4 min según transcript; Etapa 0 validada, queda 1 definición de proceso (flujo Jira)
36 2026-07-27 2026-W31 1 E1-07 Sesión de API de Jira con Pedro (token PAF, bandeja FAC) 0.20 confirmada bitacora/REGISTRO.md#56 si ~12 min; token PAF comprometido (1 año) por correo; integración inicia tras definición del flujo 28-jul
+82
View File
@@ -0,0 +1,82 @@
# Seguimiento de horas
Fuente local de horas efectivamente trabajadas para el proyecto Balam. Se mantiene mientras Johann obtiene acceso al flujo de Jira; después, Jira será el registro operativo y este archivo/CSV servirá para conciliación y facturación.
**Tarifa contractual:** $600 MXN/h + IVA
**Cadencia:** corte semanal; factura los viernes; pago a 30 días
**Datos tabulares:** [`Seguimiento-horas.csv`](Seguimiento-horas.csv)
**Última actualización:** 2026-07-27
## Reglas de captura
1. Registrar el tiempo el mismo día, en incrementos de 0.25 h.
2. Separar sesiones, desarrollo, análisis, documentación y gestión técnica.
3. Vincular cada registro con una actividad del plan y una evidencia cuando exista.
4. No convertir porcentajes de avance en horas: el avance mide entregable; las horas miden esfuerzo real.
5. No completar retrospectivamente una duración sin respaldo. Si solo se conoce la actividad, dejarla en la lista de reconstrucción hasta que Johann confirme el tiempo.
6. Al habilitarse Jira, conciliar ambos registros y evitar duplicados.
## Corte al 27-jul
| Etapa | Horas al corte | Rango estimado de la etapa | Estado |
|---|---:|---:|---|
| Etapa 0 | **21.83 h** | 1822 h | Cerrada y **validada por Balam el 24-jul**; dentro del rango |
| Etapa 1 | **19.75 h** | 3239 h | En curso; 6 de 8 entregables terminados |
| **Total** | **41.58 h** | | |
**Estado de validación de las horas (27-jul):**
| Estado | Horas | Significado |
|---|---:|---|
| `confirmada` | 9.13 h | Duración documentada (transcripts, sesiones calendarizadas, tiempo de sesión) |
| `validada` | 32.45 h | Reconstruida por actividad y **confirmada por Johann el 27-jul** contra evidencia fechada |
| **Total** | **41.58 h** | Sin horas pendientes de validar |
## Distribución al 27-jul
| Etapa | Actividad | ID | Horas |
|---|---|---|---:|
| 0 | Kickoff y preparación | E0-01 | 2.00 |
| 0 | Discovery de facturación, envío y cobranza | E0-02 | 3.83 |
| 0 | Accesos y salvaguardas | E0-03 | 1.00 |
| 0 | Validación técnica de la API de BIND | E0-04 | 4.50 |
| 0 | Prototipo navegable (incl. pulido final del 10-jul) | E0-05 | 7.50 |
| 0 | Entregable de cierre: PDF, hallazgos, plan y correo | E0-06 | 1.50 |
| 0 | Validación del prototipo con Balam (guion + sesión) | E0-07 | 1.50 |
| 1 | Backend base, auth, roles, bitácora y syncs (B0B4) | E1-01 | 6.50 |
| 1 | Coordinación del repositorio | E1-02 | 0.50 |
| 1 | Arquitectura multi-tenant y RLS (B6) | E1-03 | 2.00 |
| 1 | Cliente productivo de la API de BIND | E1-04 | 2.00 |
| 1 | Gestión, cortes de avance y sesión de reglas | E1-05 | 3.30 |
| 1 | Entorno local, scaffold y Scalar | E1-06 | 3.25 |
| 1 | Sesión de API de Jira | E1-07 | 0.20 |
| 1 | Diseño del plan de ejecución de Etapa 1 | E1-08 | 2.00 |
| | **Total** | | **41.58** |
> **Ajustes a la baja aplicados por Johann el 27-jul:** el análisis del Discovery de facturación bajó de 1.92 a 1.00 h, la documentación del de cobranza de 1.50 a 0.75 h, y el guion de validación de 0.75 a 0.45 h. Las duraciones de sesión documentadas en transcript **no se tocaron**. Con esto Etapa 0 vuelve a quedar dentro del rango contractual de 1822 h.
### Nota sobre las sesiones asistidas por IA
Los bloques B0B6 de Etapa 1 (auth, RLS, cliente de BIND, sincronización de 1,494 facturas de producción) se ejecutaron en **3.50 h de tiempo de reloj** contra una estimación manual de 45.5 h *por bloque*. Se registra el tiempo efectivamente trabajado, conforme al contrato. El trabajo intelectual que hizo posible esa velocidad —diseño de arquitectura, decisión de ADRs y plan de ejecución— se registra por separado en **E1-08 (2.00 h)**.
Consecuencia a vigilar: **Etapa 1 cerrará por debajo del rango de 3239 h.** Conviene reportar avance por entregable (6 de 8) y no solo por horas, para que la eficiencia no se lea como alcance faltante.
### Nota sobre el mapeo CSV → Excel
El CSV agrupa por **actividad contractual**; el Excel desglosa por **tarea de proyecto**, y no mapean 1:1. El reparto vive en `HORAS_POR_FILA` dentro de `generar_avance_2026_07_27.py`, con la trazabilidad comentada línea por línea, y el script **aborta** si la suma del detalle no cuadra con el CSV.
Dos casos que conviene recordar:
- **E1-06 (entorno, scaffold, Scalar — 3.25 h)** no tiene fila propia: se carga a "Backend base", que se renombró y amplió su rango a 89 h.
- **E1-08 (diseño del plan — 2.00 h)** se reparte en dos: **1.00 h** de diseño general va a "Arquitectura multi-tenant y diseño de la solución" (rango 34 h) y **1.00 h** del análisis de B7 —pipeline `Draft→DryRun→Confirm`, flags, regla PPD/PUE, ADR-001— va a la fila del **entregable 4 (capa de escritura)**, para que muestre el trabajo hecho aunque la implementación siga en pausa. La entidad `WriteOperation` y la policy `PuedeOperarEscritura` **no** se contabilizan ahí: se hicieron en B1/B2 y ya están en "Backend base" (evita doble conteo).
- La fila de **seguimiento semanal se queda solo con gestión y cortes de avance (1.75 h)**. Antes acumulaba 7.00 h de trabajo técnico bajo un nombre que no lo describía, lo que se leía como sobrecosto en una actividad trivial.
- La sesión **B4 (1.00 h)** se reparte entre "Sincronización de facturas" (0.50 h) y "Modelo de facturas" (0.50 h): produjo ambas cosas —el sync y el `InvoiceStatusMapper` con sus 13 pruebas más la migración `DetalleSyncPendiente`—, y antes el modelo aparecía al 85 % con 0 h.
**Criterio general:** ninguna fila debe mostrar avance con 0 h trabajadas. Las únicas excepciones legítimas son Azure y CI/CD, que están en 0 % y 0 h porque dependen de accesos del lado de Balam.
## Corte comercial
- La propuesta v1.2 contempla una **facturación inicial de 30 h ($18,000 + IVA)** que cubre Etapa 0 e inicio de Etapa 1.
- Al 27-jul hay **41.58 h trabajadas**, es decir **11.58 h por encima** de esa facturación inicial. A tarifa de $600/h son **$6,948 + IVA** aún no facturados.
- Todas las horas están validadas (ninguna pendiente de confirmar), por lo que el desglose ya es presentable para facturación.
- Pendiente: conciliar contra Jira cuando Pedro lo habilite, y confirmar con Balam si la segunda factura va por el excedente o por corte de etapa.
- La emisión de la factura inicial sigue pendiente de confirmación de Balam al correo del 2-jul.
+104
View File
@@ -0,0 +1,104 @@
# Sesión de reglas y definiciones — Etapa 1
**Fecha:** miércoles 22-jul-2026
**Participantes esperados:** CEO, Arturo, Erika, Johann
**Objetivo:** cerrar decisiones que afectan el modelo de datos y el alcance técnico antes de implementar escritura e integración Jira→BIND.
## Resultado esperado
Al terminar deben quedar definidos:
1. Flujo de alta de un cliente nuevo.
2. Tratamiento de diferencias por comisión/fee.
3. Fuente y reglas de particularidades de envío.
4. Alcance de la automatización Jira→cotización BIND.
5. Datos y autorización necesarios para comenzar escritura controlada.
## Agenda propuesta (4560 min)
### 1. Alta de cliente nuevo — 10 min
- ¿Quién crea actualmente al cliente en BIND?
- ¿Qué documentos y validaciones son obligatorios?
- ¿Qué estatus de Jira indica que el alta está autorizada?
- ¿La plataforma solo debe detectar que falta el cliente o también crearlo?
- ¿Qué ocurre si el RFC ya existe o los datos fiscales no coinciden?
**Decisión a registrar:** alcance exacto del MVP y responsable de cada paso.
### 2. Comisión/fee en cobranza — 10 min
- Cuando el pago recibido es menor por una comisión, ¿cómo se registra en BIND?
- ¿Pago parcial con saldo residual, nota de crédito, gasto/comisión o ajuste contable?
- ¿Existe una tolerancia fija o cambia por cliente/banco?
- ¿Quién autoriza considerar una factura como saldada con diferencia?
- 🆕 **Hallazgo del sync histórico (21-jul):** las 1,374 facturas con método de pago registran **PUE — ninguna PPD** — aunque cobran a crédito 3090 días. ¿Es política deliberada del despacho o práctica a corregir? Impacta la regla "PPD default" de la futura capa de escritura y el requerimiento del SAT que ya sufrieron.
**Decisión a registrar:** fórmula de estado de cobranza y si el umbral es global o por cliente.
### 3. Particularidades de envío — 10 min
- Confirmar destinatarios, adjuntos, nomenclatura del asunto y cuerpo por cliente.
- Definir quién mantiene estos datos y con qué frecuencia cambian.
- Confirmar si el Excel en preparación será la fuente inicial para cargarlos.
**Decisión a registrar:** estructura mínima del catálogo y responsable de mantenimiento.
### 4. Jira → cotización BIND — 15 min
Explicar que Jira es parte confirmada del proceso, pero la creación automática de cotizaciones no estaba incluida explícitamente en el alcance inicial.
- ¿La expectativa del MVP es solo conservar el folio de Jira o crear automáticamente la cotización en BIND?
- ¿Qué estatus o aprobación dispara la acción?
- ¿Qué tipos de ticket aplican: adicional, baja, headhunting, staff augmentation?
- ¿Qué campos son obligatorios y qué ocurre si falta alguno?
- ¿Debe haber una previsualización/confirmación humana antes de escribir en BIND?
Si Balam confirma la automatización, solicitar posteriormente:
- Cuenta técnica de Jira con acceso mínimo al proyecto.
- API token/OAuth y permiso para webhook o automatización.
- Identificadores del sitio/proyecto y mapeo de campos.
- Autorización de escritura controlada en BIND.
**Estimación a comunicar (en dos partes, no dar una sola cifra global):**
1. *Definición del flujo + accesos:* esta misma semana, un par de horas.
2. *Desarrollo:* **~10 horas, sujeto a validar la API de escritura de BIND** — sin sandbox, endpoints de escritura no documentados y producción directa (por eso lleva dry-run + confirmación humana). Frase preparada: "La definición del flujo y los accesos los resolvemos esta semana. El desarrollo lo estimo en unas 10 horas, sujeto a lo que encontremos en la API de escritura de BIND, que aún no está documentada y es producción directa — por eso va con dry-run y confirmación humana antes de escribir nada."
⚠️ No comprometer el número de desarrollo como cerrado hasta tener las reglas del punto 1 (alta de cliente) — si el ticket puede traer un cliente que no existe en BIND, las dos piezas se tocan y el alcance cambia.
**Decisión a registrar:** incluido, diferido o sujeto a estimación/cambio de alcance.
### 5. Cierre técnico — 10 min
- Confirmar si ya está listo el repositorio GitHub y el acceso de Johann.
- Confirmar fecha y responsable del acceso Azure.
- Confirmar cuándo Pedro habilitará el reporte de horas en Jira.
- Revisar las preguntas técnicas pendientes de BIND: pagos/REP, `CFDIUse`, XML, webhooks y token de Power BI.
## Límites que conviene explicitar
- Recordatorios automáticos enviados al cliente: Anexo B; el MVP contempla alertas internas.
- Multiempresa: fuera del MVP; cada empresa requiere token/cuenta BIND.
- Escritura en producción: solo con autorización, dry-run, confirmación humana y feature flag.
- Integración Jira automática: pendiente de confirmación de alcance.
## Minuta — sesión realizada (22-jul, 7:00 am, ~48 min)
> Participaron: Noe (sala), Arturo, Araceli (desde ~min 21), Johann. Erika no estuvo. Transcripción: `../fuentes/2026-07-22 - Flujo para dar de alta clientes nuevos,_ Transcript.txt`. Detalle completo en [REGISTRO #54](../bitacora/REGISTRO.md).
| Tema | Decisión | Responsable | Fecha |
|---|---|---|---|
| Alta de cliente | ASIS mapeado: mismo flujo clientes/proveedores, 2 pestañas (Detalle + Direcciones), datos de constancia fiscal + estado de cuenta; crédito viene de negociación comercial; extranjeros con RFC genérico y CFDI "sin efectos fiscales" (solo PDF, sin XML). **Pendiente decidir si la plataforma solo detecta o también crea el cliente.** | Arturo demostró; decisión MVP abierta | 22-jul |
| Fee/comisión | El fee bancario lo registra y deduce **el despacho contable**, no Balam. Solo aplica en pagos internacionales que mueven dinero a México; nacionales cuadran a centavos. La plataforma solo debe **identificar la diferencia como fee** (visible en el estado de cuenta del cliente). | Despacho (asiento) · Plataforma (detección) | 22-jul |
| Particularidades de envío | **No se tocó.** Excel sigue pendiente de Ara/Arturo. | Ara + Arturo | — |
| Jira→BIND | Noe confirmó que **Jira ya es parte del proceso** (evolucionó desde el alcance inicial) y puso el ajuste sobre la mesa. Space "Facturación"; estatus final que confirma facturación = **"resuelto"**; validación exige PDF+XML (nacional) o PDF (internacional). Sesión con Pedro para API de Jira + recurrentes. | Erika coordina sesión con Pedro | Por agendar |
| Escritura BIND | Explorarla con máxima cautela: **no hay sandbox, es producción**. Prueba Jira→cotización será acordada, medida y controlada llegado el momento. | Johann + Noe/Pedro | Tras sesión API Jira |
| Repo/Azure/Jira horas | **No se tocó.** | — | — |
| PUE vs PPD (hallazgo 21-jul) | **No se alcanzó a preguntar.** Reintentar el 23-jul o en la sesión con Pedro. | Johann | Pendiente |
**Compromisos de Balam salidos de la sesión:**
1. Enviar a Johann el **diagrama del flujo Jira** en tamaño legible (Arturo/Pedro).
2. Agendar **sesión con Pedro** (API Jira, facturación recurrente, automáticas vs manuales).
3. Arturo grabará/documentará los procesos nuevos conforme ocurran (caso Frisa en curso).
+288
View File
@@ -0,0 +1,288 @@
"""Actualiza el plan oficial con el corte reconstruido de horas al 15-jul-2026."""
from copy import copy
from pathlib import Path
import openpyxl
from openpyxl.styles import Alignment, Font, PatternFill
from openpyxl.utils import get_column_letter
PATH = Path(__file__).with_name("Plan-actividades-avance-2026-07-10-ajustado.xlsx")
def find_row(ws, task):
for row in range(2, ws.max_row + 1):
if ws.cell(row, 1).value == task:
return row
raise ValueError(f"No se encontró la tarea: {task}")
def copy_row_style(ws, source_row, target_row, max_col=11):
for col in range(1, max_col + 1):
source = ws.cell(source_row, col)
target = ws.cell(target_row, col)
if source.has_style:
target._style = copy(source._style)
target.number_format = source.number_format
target.alignment = copy(source.alignment)
workbook = openpyxl.load_workbook(PATH)
sheet = workbook["Plan"]
# Actividades separadas después del plan original. Las inserciones son idempotentes.
if not any(
sheet.cell(row, 1).value == "Definición de alcance Jira → cotización BIND"
for row in range(2, sheet.max_row + 1)
):
source_row = find_row(sheet, "Sesión de reglas de negocio con Arturo")
sheet.insert_rows(source_row + 1)
copy_row_style(sheet, source_row, source_row + 1)
values = [
"Definición de alcance Jira → cotización BIND",
"2 días",
"mié 22/07/26",
"jue 23/07/26",
None,
"Johan y Balam",
0,
]
for column, value in enumerate(values, start=1):
sheet.cell(source_row + 1, column, value)
if not any(
sheet.cell(row, 1).value == "CI/CD + gestión de secretos"
for row in range(2, sheet.max_row + 1)
):
source_row = find_row(sheet, "Repositorio + CI/CD + gestión de secretos")
sheet.insert_rows(source_row + 1)
copy_row_style(sheet, source_row, source_row + 1)
values = [
"CI/CD + gestión de secretos",
"1 día",
"vie 24/07/26",
"vie 24/07/26",
None,
"Johan y Pedro",
0,
]
for column, value in enumerate(values, start=1):
sheet.cell(source_row + 1, column, value)
# Calendario ajustado con los acuerdos del 1315 de julio.
updates = {
"Sesión de validación del prototipo": (
"1 día",
"jue 23/07/26",
"jue 23/07/26",
"Johan y Balam",
),
"Documento de hallazgos + ADRs + plan refinado": (
"10 días",
"vie 10/07/26",
"jue 23/07/26",
"Johan",
),
"Sesión de reglas de negocio con Arturo": (
"1 día",
"mié 22/07/26",
"mié 22/07/26",
"Arturo y CEO",
),
"Backend base: autenticación, roles y bitácora de auditoría": (
"5 días",
"lun 13/07/26",
"vie 17/07/26",
"Johan",
),
"Repositorio + CI/CD + gestión de secretos": (
"4 días",
"lun 13/07/26",
"jue 16/07/26",
"Pedro y Noé",
),
"Arquitectura multi-tenant (tenant_id + RLS)": (
"4 días",
"mar 14/07/26",
"vie 17/07/26",
"Johan",
),
}
for task, (duration, start, end, resources) in updates.items():
row = find_row(sheet, task)
sheet.cell(row, 2, duration)
sheet.cell(row, 3, start)
sheet.cell(row, 4, end)
sheet.cell(row, 6, resources)
rules_row = find_row(sheet, "Sesión de reglas de negocio con Arturo")
sheet.cell(rules_row, 1, "Sesión de reglas y dudas de Etapa 1")
repo_row = find_row(sheet, "Repositorio + CI/CD + gestión de secretos")
sheet.cell(repo_row, 1, "Repositorio privado GitHub")
headers = {
8: "Horas al 15/07",
9: "Tipo de registro",
10: "Notas de horas",
11: "Rango estimado",
}
for column, value in headers.items():
cell = sheet.cell(1, column, value)
cell.fill = copy(sheet.cell(1, 1).fill)
cell.font = copy(sheet.cell(1, 1).font)
cell.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
# Corte: 22 h de Etapa 0 + 8 h del inicio de Etapa 1 = 30 h.
hours = {
"Sesión de arranque (kickoff) con el Ing. Noé": (
2.00,
"Incluye preparación y sesión de 1 h",
),
"Sesión de Discovery: proceso actual de facturación y cobranza": (
5.50,
"Incluye preparación, sesiones y documentación de facturación/cobranza",
),
"Entrega y validación de accesos (BIND + manual de marca)": (
1.00,
"Coordinación, recepción y salvaguardas",
),
"Validación técnica de la API de BIND con la cuenta real": (
4.50,
"117 consultas GET, análisis y reporte técnico",
),
"Prototipo visual navegable": (
6.00,
"Diseño, construcción y ajustes con datos ficticios",
),
"Sesión de validación del prototipo": (0.00, "Agendada para el 23-jul"),
"Documento de hallazgos + ADRs + plan refinado": (
3.00,
"PDF/correo de entrega, hallazgos, ADRs y actualización del plan",
),
"Sesión de reglas y dudas de Etapa 1": (0.00, "Agendada para el 22-jul"),
"Definición de alcance Jira → cotización BIND": (
0.00,
"Se define con Balam el 2223 jul",
),
"Backend base: autenticación, roles y bitácora de auditoría": (
3.50,
"Trabajo local del 1315 jul",
),
"Repositorio privado GitHub": (0.50, "Coordinación de creación y acceso"),
"CI/CD + gestión de secretos": (0.00, "Programado para el 24-jul"),
"Arquitectura multi-tenant (tenant_id + RLS)": (
1.50,
"Diseño técnico inicial",
),
"Cliente de la API de BIND (reintentos, OData, errores)": (
2.00,
"Inicio del cliente productivo",
),
"Demostración semanal (viernes) + reporte de horas": (
0.50,
"Seguimiento, ajuste de calendario y corte de horas",
),
}
pending = {
"Sesión de validación del prototipo",
"Sesión de reglas y dudas de Etapa 1",
"Definición de alcance Jira → cotización BIND",
"CI/CD + gestión de secretos",
}
stage_rows = {0: [], 1: []}
current_stage = None
for row in range(2, sheet.max_row + 1):
task = sheet.cell(row, 1).value
if task == "Etapa 0":
current_stage = 0
sheet.cell(row, 11, "1822 h")
continue
if task == "Etapa 1":
current_stage = 1
sheet.cell(row, 11, "3239 h")
continue
if task == "Integracion de plataformas Balam":
sheet.cell(row, 11, "112136 h")
continue
if task not in hours:
continue
value, note = hours[task]
sheet.cell(row, 8, value)
sheet.cell(row, 9, "Pendiente" if task in pending else "Reconstruida")
sheet.cell(row, 10, note)
if current_stage in stage_rows:
stage_rows[current_stage].append(row)
project_row = find_row(sheet, "Integracion de plataformas Balam")
stage0_row = find_row(sheet, "Etapa 0")
stage1_row = find_row(sheet, "Etapa 1")
sheet.cell(stage0_row, 8, f"=SUM({','.join(f'H{row}' for row in stage_rows[0])})")
sheet.cell(stage1_row, 8, f"=SUM({','.join(f'H{row}' for row in stage_rows[1])})")
sheet.cell(project_row, 8, f"=H{stage0_row}+H{stage1_row}")
summaries = {
project_row: "Corte reconstruido al 15-jul",
stage0_row: "22 h: límite superior estimado de la etapa",
stage1_row: "8 h consumidas al 15-jul; etapa aún en curso",
}
for row, note in summaries.items():
sheet.cell(row, 9, "Resumen")
sheet.cell(row, 10, note)
for row in range(2, sheet.max_row + 1):
sheet.cell(row, 8).number_format = '0.00 "h"'
for column in range(8, 12):
sheet.cell(row, column).alignment = Alignment(vertical="top", wrap_text=True)
if sheet.cell(row, 1).value in {
"Integracion de plataformas Balam",
"Etapa 0",
"Etapa 1",
}:
for column in range(8, 12):
sheet.cell(row, column).font = Font(bold=True, color="FFFFFF")
sheet.cell(row, column).fill = PatternFill("solid", fgColor="331F0E")
widths = {
1: 58,
2: 13,
3: 16,
4: 16,
5: 14,
6: 22,
7: 14,
8: 16,
9: 18,
10: 55,
11: 18,
}
for column, width in widths.items():
sheet.column_dimensions[get_column_letter(column)].width = width
sheet.freeze_panes = "A2"
sheet.auto_filter.ref = f"A1:K{sheet.max_row}"
sheet.sheet_properties.pageSetUpPr.fitToPage = True
sheet.page_setup.fitToWidth = 1
sheet.page_setup.fitToHeight = 0
sheet.oddFooter.center.text = (
"Horas reconstruidas al 15-jul-2026; validar contra Jira antes de facturar"
)
stage0_total = sum(hours[sheet.cell(row, 1).value][0] for row in stage_rows[0])
stage1_total = sum(hours[sheet.cell(row, 1).value][0] for row in stage_rows[1])
assert stage0_total == 22.0
assert stage1_total == 8.0
temporary = PATH.with_suffix(".tmp.xlsx")
workbook.save(temporary)
check = openpyxl.load_workbook(temporary, data_only=False)["Plan"]
assert check.max_column == 11
assert check.cell(find_row(check, "Etapa 0"), 8).value.startswith("=SUM(")
assert check.cell(find_row(check, "Etapa 1"), 8).value.startswith("=SUM(")
temporary.replace(PATH)
print(f"Actualizado: {PATH}")
print("Etapa 0: 22.00 h | Etapa 1: 8.00 h | Total al 15-jul: 30.00 h")
+98
View File
@@ -0,0 +1,98 @@
"""Genera el Excel de avance que se compartirá con Erika el 16-jul-2026."""
from copy import copy
from pathlib import Path
from shutil import copy2
import openpyxl
DIRECTORY = Path(__file__).parent
SOURCE = DIRECTORY / "Plan-actividades-avance-2026-07-10-ajustado.xlsx"
TARGET = DIRECTORY / "Plan-actividades-avance-2026-07-16.xlsx"
def find_row(sheet, task):
for row in range(2, sheet.max_row + 1):
if sheet.cell(row, 1).value == task:
return row
raise ValueError(f"No se encontró la actividad: {task}")
copy2(SOURCE, TARGET)
workbook = openpyxl.load_workbook(TARGET)
sheet = workbook["Plan"]
sheet.cell(1, 8, "Horas al 16/07")
updates = {
"Integracion de plataformas Balam": (
0.20,
"Corte de avance al 16-jul; Etapa 0 en validación y Etapa 1 en curso",
),
"Etapa 0": (
0.91,
"22 h registradas; prototipo entregado y validación agendada para el 23-jul",
),
"Etapa 1": (
0.20,
"8 h registradas; 1 de 8 entregables terminado y plataforma base parcial",
),
"Backend base: autenticación, roles y bitácora de auditoría": (
0.30,
"API, health check y DbContext base listos; autenticación, roles y auditoría pendientes",
),
"Repositorio privado GitHub": (
0.90,
"Invitación recibida y acceso confirmado el 16-jul; falta validar permiso de escritura",
),
"Arquitectura multi-tenant (tenant_id + RLS)": (
0.25,
"Diseño técnico inicial; entidades tenant y políticas RLS pendientes",
),
"Cliente de la API de BIND (reintentos, OData, errores)": (
1.00,
"Terminado: cliente C# solo lectura, paginación, reintentos y cuota; 13/13 pruebas aprobadas",
),
"Modelo de facturas + migraciones + datos de prueba": (
0.10,
"Base operativa con SyncCheckpoint y AuditLog; modelo de facturas y migración pendientes",
),
"Demostración semanal (viernes) + reporte de horas": (
0.50,
"Corte del 16-jul preparado; control local mientras se habilita Jira",
),
}
for task, (progress, note) in updates.items():
row = find_row(sheet, task)
sheet.cell(row, 7, progress)
sheet.cell(row, 10, note)
stage1_row = find_row(sheet, "Etapa 1")
sheet.cell(stage1_row, 8, "=SUM(H12:H24)")
for row in range(2, sheet.max_row + 1):
sheet.cell(row, 7).number_format = "0%"
sheet.oddFooter.center.text = (
"Avance al 16-jul-2026 · Horas reconstruidas pendientes de conciliación con Jira"
)
# Conserva los estilos y usa el nombre de archivo como título impreso.
sheet.oddHeader.center.text = "Plan de actividades y avance · Proyecto Balam"
for cell in sheet[1]:
cell._style = copy(cell._style)
temporary = TARGET.with_suffix(".tmp.xlsx")
workbook.save(temporary)
check = openpyxl.load_workbook(temporary, data_only=False)["Plan"]
assert check.cell(find_row(check, "Etapa 1"), 7).value == 0.20
assert check.cell(
find_row(check, "Cliente de la API de BIND (reintentos, OData, errores)"), 7
).value == 1.00
assert check.cell(find_row(check, "Etapa 1"), 8).value == "=SUM(H12:H24)"
temporary.replace(TARGET)
print(f"Generado: {TARGET}")
+159
View File
@@ -0,0 +1,159 @@
"""Genera Plan-actividades-avance-2026-07-21.xlsx desde el del 16-jul.
Columnas nuevas: Bloque · Horas estimadas (rango) · Horas trabajadas · Estatus.
Semáforo: verde=completada, amarillo=en curso, rojo=vencida, gris=próxima.
Línea roja gruesa = HOY (21-jul): lo de arriba debería estar hecho o en curso."""
import re
from datetime import date
import openpyxl
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
SRC = "/Users/johann/Desktop/Proyectos personales/BALAM/planeacion/Plan-actividades-avance-2026-07-16.xlsx"
DST = "/Users/johann/Desktop/Proyectos personales/BALAM/planeacion/Plan-actividades-avance-2026-07-21.xlsx"
HOY = date(2026, 7, 21)
AMARILLO, CAFE = "F7BD0C", "331F0E"
CREMA, GRIS_B = "FDF3D8", "D9D9D9"
V_FILL, V_FONT = "C6EFCE", "006100" # verde
A_FILL, A_FONT = "FFEB9C", "9C6500" # amarillo
R_FILL, R_FONT = "FFC7CE", "9C0006" # rojo
G_FILL, G_FONT = "F2F2F2", "595959" # gris
# prefijo -> (bloque, estimadas_rango, trabajadas, nuevo_pct o None)
MAPA = {
"Integracion de plataformas Balam": ("", "5061", 38.0, 0.65),
"Etapa 0": ("", "1822", 22.0, None),
"Sesión de arranque (kickoff)": ("", "2", 2.0, None),
"Sesión de Discovery": ("", "45", 5.5, None),
"Entrega y validación de accesos": ("", "1", 1.0, None),
"Validación técnica de la API": ("", "34", 4.5, None),
"Prototipo visual navegable": ("", "56", 6.0, None),
"Documento de hallazgos": ("", "23", 3.0, None),
"Sesión de validación del prototipo": ("", "1", 0.0, None),
"Etapa 1": ("", "3239", 16.0, 0.8),
"Demostración semanal": ("", "23", 1.5, None),
"Repositorio privado GitHub": ("", "1", 0.5, None),
"Backend base": ("B2", "67", 7.25, 1.0),
"Arquitectura multi-tenant": ("B1 + B6", "23", 2.0, 1.0),
"Cliente de la API de BIND": ("", "23", 2.0, None),
"Capa de escritura controlada": ("B7", "34", 0.0, None),
"Sincronización de clientes": ("B3", "2.53", 0.5, 1.0),
"Configuración de infraestructura en Azure": ("", "1", 0.0, None),
"Sincronización de facturas": ("B4", "4.55.5", 1.0, 1.0),
"Sesión de reglas y dudas": ("", "1", 0.0, None),
"Definición de alcance Jira": ("", "1", 0.0, None),
"Modelo de facturas": ("B1 + B4 + B9", "3.54.5", 1.0, 0.85),
"CI/CD": ("", "1.52", 0.0, None),
}
def fecha(celda):
m = re.search(r"(\d{2})/(\d{2})/(\d{2})", str(celda or ""))
return date(2000 + int(m.group(3)), int(m.group(2)), int(m.group(1))) if m else None
wb = openpyxl.load_workbook(SRC)
ws = wb.active
C_BLQ, C_EST, C_TRAB, C_STAT = 8, 9, 10, 11
for col, titulo in [(C_BLQ, "Bloque (plan interno)"), (C_EST, "Horas estimadas"),
(C_TRAB, "Horas trabajadas"), (C_STAT, f"Estatus (hoy {HOY.day}-jul)")]:
ws.cell(row=1, column=col, value=titulo)
thin = Side(style="thin", color=GRIS_B)
borde = Border(left=thin, right=thin, top=thin, bottom=thin)
def pinta(celda, fill, font_color, bold=False):
celda.fill = PatternFill("solid", fgColor=fill)
celda.font = Font(color=font_color, bold=bold, size=10)
celda.alignment = Alignment(horizontal="center", vertical="center")
fila_hoy = None # primera actividad de Etapa 1 que arranca DESPUÉS de hoy
en_etapa1 = False
for row in range(2, ws.max_row + 1):
nombre = str(ws.cell(row=row, column=1).value or "").strip()
if not nombre:
continue
if nombre.startswith("Etapa 1"):
en_etapa1 = True
for prefijo, (blq, est, trab, pct) in MAPA.items():
if nombre.startswith(prefijo):
ws.cell(row=row, column=C_BLQ, value=blq)
ws.cell(row=row, column=C_EST, value=est)
ws.cell(row=row, column=C_TRAB, value=trab)
if pct is not None:
ws.cell(row=row, column=7, value=pct)
break
es_etapa = nombre.startswith("Etapa") or nombre.startswith("Integracion")
pct = ws.cell(row=row, column=7).value or 0
ini, fin = fecha(ws.cell(row=row, column=3).value), fecha(ws.cell(row=row, column=4).value)
stat = ws.cell(row=row, column=C_STAT)
if es_etapa:
ws.cell(row=row, column=C_STAT, value="")
elif pct >= 1:
stat.value = "✅ Completada"; pinta(stat, V_FILL, V_FONT)
elif fin and fin < HOY:
stat.value = "🔴 Vencida"; pinta(stat, R_FILL, R_FONT, bold=True)
elif ini and ini <= HOY:
stat.value = "🟡 En curso"; pinta(stat, A_FILL, A_FONT)
elif pct > 0:
stat.value = "🟢 Adelantada"; pinta(stat, V_FILL, V_FONT)
else:
stat.value = "⚪ Próxima"; pinta(stat, G_FILL, G_FONT)
# semáforo también en la celda de %
pcel = ws.cell(row=row, column=7)
if not es_etapa:
if pct >= 1: pinta(pcel, V_FILL, V_FONT, bold=True)
elif pct > 0: pinta(pcel, A_FILL, A_FONT, bold=True)
elif fin and fin < HOY: pinta(pcel, R_FILL, R_FONT, bold=True)
if en_etapa1 and fila_hoy is None and not es_etapa and ini and ini > HOY:
fila_hoy = row
# estilo general: encabezado marca, filas de etapa, bordes, formatos
head_fill = PatternFill("solid", fgColor=AMARILLO)
etapa_fill = PatternFill("solid", fgColor=CREMA)
for row in range(1, ws.max_row + 1):
nombre = str(ws.cell(row=row, column=1).value or "")
es_etapa = nombre.startswith("Etapa") or nombre.startswith("Integracion")
for col in range(1, C_STAT + 1):
c = ws.cell(row=row, column=col)
c.border = borde
if row == 1:
c.fill = head_fill
c.font = Font(bold=True, color=CAFE, size=11)
c.alignment = Alignment(horizontal="center", vertical="center", wrap_text=True)
elif es_etapa and nombre:
c.fill = etapa_fill
c.font = Font(bold=True, color=CAFE)
if row > 1:
ws.cell(row=row, column=7).number_format = "0%"
ws.cell(row=row, column=C_TRAB).number_format = "0.0"
for col in (C_BLQ, C_EST, C_TRAB):
ws.cell(row=row, column=col).alignment = Alignment(horizontal="center")
# línea de HOY: borde rojo grueso arriba de la primera actividad futura de Etapa 1
if fila_hoy:
rojo = Side(style="thick", color="C00000")
for col in range(1, C_STAT + 1):
c = ws.cell(row=fila_hoy, column=col)
c.border = Border(left=c.border.left, right=c.border.right,
top=rojo, bottom=c.border.bottom)
# leyenda
ley = ws.max_row + 2
ws.cell(row=ley, column=1,
value="✅ Completada · 🟡 En curso · 🔴 Vencida (fecha plan pasada, <100%) · ⚪ Próxima").font = Font(italic=True, size=9, color=G_FONT)
ws.cell(row=ley + 1, column=1,
value=f"▬ La línea roja gruesa marca HOY ({HOY.day}-jul): lo de arriba debería estar terminado o en curso.").font = Font(italic=True, size=9, color="C00000")
for letra, ancho in {"A": 48, "B": 9, "C": 12, "D": 12, "E": 12, "F": 22, "G": 12,
"H": 15, "I": 14, "J": 14, "K": 20}.items():
ws.column_dimensions[letra].width = ancho
ws.freeze_panes = "A2"
ws.oddFooter.center.text = "Avance al 21-jul-2026 · Horas conforme al control local (pendiente conciliar con Jira)"
wb.save(DST)
print("OK ->", DST, "| línea de hoy en fila:", fila_hoy)
+300
View File
@@ -0,0 +1,300 @@
"""Genera Plan-actividades-avance-2026-07-27.xlsx a partir del del 21-jul.
Diferencia clave vs. versiones anteriores: las HORAS TRABAJADAS ya no se escriben a
mano — se leen de `Seguimiento-horas.csv` (fuente de la verdad) y se agregan por
actividad del plan mediante el mapa ACT_POR_TAREA. Así cada celda de horas del
Excel es trazable a una o varias líneas del CSV, y el total del encabezado de cada
etapa es la suma real de su detalle.
Corte al 27-jul: validación del prototipo (24-jul, APROBADO) y sesión de reglas
(22-jul) completadas; API de Jira (27-jul) recibida; capa de escritura EN PAUSA a
la espera de la definición del flujo de facturación (sesión 28-jul).
"""
import csv
import os
import re
from collections import defaultdict
from datetime import date
import openpyxl
from openpyxl.styles import Alignment, Font, PatternFill
BASE = os.path.dirname(os.path.abspath(__file__))
SRC = os.path.join(BASE, "Plan-actividades-avance-2026-07-21.xlsx")
DST = os.path.join(BASE, "Plan-actividades-avance-2026-07-27.xlsx")
CSV_HORAS = os.path.join(BASE, "Seguimiento-horas.csv")
HOY = date(2026, 7, 27)
CAFE, CREMA, GRIS_B, AMARILLO = "331F0E", "FDF3D8", "D9D9D9", "F7BD0C"
V_FILL, V_FONT = "C6EFCE", "006100" # verde
A_FILL, A_FONT = "FFEB9C", "9C6500" # amarillo
R_FILL, R_FONT = "FFC7CE", "9C0006" # rojo
G_FILL, G_FONT = "F2F2F2", "595959" # gris
C_PCT, C_BLQ, C_EST, C_TRAB, C_STAT = 7, 8, 9, 10, 11
# --- Horas por fila del Excel --------------------------------------------------
# Las actividades del CSV no mapean 1:1 con las filas del plan (el CSV agrupa por
# actividad contractual; el Excel desglosa por tarea de proyecto). Se reparten por
# fila usando la evidencia de la bitácora, de modo que cada fila muestre el trabajo
# que realmente le corresponde y la suma siga cuadrando con el CSV.
#
# Trazabilidad de Etapa 1 (19.75 h del CSV):
# E1-01 6.50 = backend base 3.50 (13-14 jul) + B0/B1 1.00 + B2 0.50 + B3 0.50 + B4 1.00
# E1-02 0.50 = repositorio GitHub
# E1-03 2.00 = multi-tenant 1.50 (14-15 jul) + B6 RLS 0.50
# E1-04 2.00 = cliente de BIND
# E1-05 3.30 = gestión 0.50 + corte 16-jul 1.00 + cierre 21-jul 0.25 + prep 0.75 + sesión 0.80
# E1-06 3.25 = scaffold 2.00 + entorno local 1.00 + Scalar 0.25
# E1-07 0.20 = sesión API de Jira
# E1-08 2.00 = diseño del plan de Etapa 1
HORAS_POR_FILA = {
# --- Etapa 0 (21.83 h) — una actividad del CSV por fila
# E0-02 3.83 = sesión facturación 1.08 + análisis 1.00 + sesión cobranza 1.00 + notas 0.75
# E0-07 1.50 = guion 0.45 + sesión de validación 1.05 (transcript: 1 h 4 min)
"Sesión de arranque (kickoff)": 2.00, # E0-01
"Sesión de Discovery": 3.83, # E0-02
"Entrega y validación de accesos": 1.00, # E0-03
"Validación técnica de la API de BIND": 4.50, # E0-04
"Prototipo visual navegable": 7.50, # E0-05
"Documento de hallazgos": 1.50, # E0-06
"Sesión de validación del prototipo": 1.50, # E0-07 (guion 0.45 + sesión 1.05)
# --- Etapa 1 (19.75 h)
# El trabajo de andamiaje (entorno local, scaffold, Scalar) y el diseño del plan
# no tienen fila propia en el plan original: se cargan a la fila técnica que les
# corresponde por naturaleza, no a la de seguimiento semanal.
"Repositorio privado GitHub": 0.50, # E1-02
"Backend base": 8.25, # E1-01 5.00 + E1-06 3.25 (entorno, scaffold, Scalar)
"Arquitectura multi-tenant": 3.00, # E1-03 2.00 (incl. B6 RLS) + E1-08 1.00 (diseño general)
"Cliente de la API de BIND": 2.00, # E1-04
"Sincronización de clientes": 0.50, # E1-01 parte: B3
# B4 produjo dos cosas: el sync de facturas/cotizaciones y el modelo central
# (InvoiceStatusMapper con 13 pruebas + migración DetalleSyncPendiente). Se
# reparte para que ninguna fila quede en 0 h marcada como avanzada.
"Sincronización de facturas": 0.50, # E1-01 parte: B4 (sync)
"Modelo de facturas": 0.50, # E1-01 parte: B4 (mapper + migraciones)
"Sesión de reglas y dudas": 1.55, # E1-05 parte: prep 0.75 + sesión 0.80
"Definición de alcance Jira": 0.20, # E1-07
"Demostración semanal": 1.75, # E1-05 resto: gestión 0.50 + corte 1.00 + cierre 0.25
# Análisis y diseño de B7 (pipeline Draft→DryRun→Confirm, flags, regla PPD/PUE,
# ADR-001): 1.00 h de E1-08, separada del diseño general para que la fila del
# entregable 4 muestre el trabajo que sí se hizo. La implementación sigue en pausa.
"Capa de escritura controlada": 1.00,
# --- Sin horas aún (trabajo no iniciado o dependiente de Balam)
"Configuración de infraestructura en Azure": 0.00,
"CI/CD": 0.00,
}
def horas_por_actividad(path):
"""Suma horas del CSV por actividad_id y por etapa."""
por_act = defaultdict(float)
por_etapa = defaultdict(float)
with open(path, encoding="utf-8", newline="") as fh:
rdr = csv.DictReader(fh)
for i, r in enumerate(rdr, start=2):
if not (r.get("fecha") or "").strip():
continue
if None in r or any(v is None for v in r.values()):
raise ValueError(
f"{os.path.basename(path)} línea {i}: número de campos inesperado "
f"(¿falta escapar una coma con comillas?)")
h = float(r["horas"])
por_act[r["actividad_id"]] += h
por_etapa[r["etapa"]] += h
return por_act, por_etapa
HORAS_ACT, HORAS_ETAPA = horas_por_actividad(CSV_HORAS)
TOTAL_CSV = sum(HORAS_ETAPA.values())
# % por entregables terminados (dato duro y defendible, no promedio ponderado).
# Etapa 1: 6 de 8 entregables contractuales TERMINADOS (1,2,3,5,6,7) = 75%. Los dos
# restantes van parciales y su avance se refleja en su propia fila (entregable 4 al
# 40%, entregable 8 al 85%), no promediado en el encabezado: la etapa se mide por
# entregable cerrado, que es lo verificable.
PCT_ETAPA = {"0": 1.0, "1": 0.75}
OVERRIDES = {
"Integracion de plataformas Balam": dict(pct=0.80, trab=TOTAL_CSV),
"Etapa 0": dict(pct=PCT_ETAPA["0"], trab=HORAS_ETAPA["0"]),
"Etapa 1": dict(pct=PCT_ETAPA["1"], trab=HORAS_ETAPA["1"]),
"Documento de hallazgos": dict(pct=1.0),
"Sesión de validación del prototipo": dict(pct=1.0, comienzo="vie 24/07/26",
fin="vie 24/07/26"),
# Estas dos filas absorben el andamiaje y el diseño del plan: se renombran y se
# amplía su rango estimado para que el nombre refleje el alcance que cubren.
"Backend base": dict(
nombre="Backend base: entorno, andamiaje, autenticación, roles y bitácora",
est="89"),
"Arquitectura multi-tenant": dict(
nombre="Arquitectura multi-tenant (tenant_id + RLS) y diseño de la solución",
est="34"),
"Demostración semanal": dict(est="23"),
# B7: diseño, ADR-001, entidad WriteOperation (migrada en B1) y policy
# PuedeOperarEscritura ya existen; falta BindWriteClient, el pipeline y los
# shapes de los POST (dependen de las reglas del 28-jul). Sin horas propias:
# las del modelo y la policy ya están cobradas en B1/B2 ("Backend base").
"Capa de escritura controlada": dict(pct=0.40),
"Sesión de reglas y dudas": dict(pct=1.0),
"Sincronización de clientes": dict(pct=1.0),
"Sincronización de facturas": dict(pct=1.0),
# Conectividad resuelta el 27-jul (token PAF a 1 año, API read+write, bandeja FAC,
# límites de consumo). Queda el 10 %: qué estatus dispara qué, amarrado al 28-jul.
"Definición de alcance Jira": dict(pct=0.90),
}
# Estatus a mano (gana sobre el semáforo automático): texto, fill, font, negrita
K_ESPECIAL = {
"Documento de hallazgos": ("✅ Completada", V_FILL, V_FONT, False),
"Sesión de validación del prototipo": ("✅ Validado (aprobado)", V_FILL, V_FONT, True),
"Demostración semanal": ("🟡 En curso (semanal)", A_FILL, A_FONT, False),
"Modelo de facturas": ("🟡 Modelo y migraciones ✓ · falta seeder", A_FILL, A_FONT, False),
"Capa de escritura controlada": ("🔴 Diseño listo · impl. en pausa (def. Balam 28-jul)",
R_FILL, R_FONT, True),
"Sesión de reglas y dudas": ("✅ Completada", V_FILL, V_FONT, False),
"Definición de alcance Jira": ("🟡 Conectividad lista · falta regla 28-jul",
A_FILL, A_FONT, False),
"Configuración de infraestructura en Azure": ("🟡 Pendiente (Balam)", A_FILL, A_FONT, False),
"CI/CD": ("🔴 Pendiente · dep. Azure", R_FILL, R_FONT, True),
}
def fecha(celda):
m = re.search(r"(\d{2})/(\d{2})/(\d{2})", str(celda or ""))
return date(2000 + int(m.group(3)), int(m.group(2)), int(m.group(1))) if m else None
def pinta(celda, fill, font_color, bold=False):
celda.fill = PatternFill("solid", fgColor=fill)
celda.font = Font(color=font_color, bold=bold, size=10)
celda.alignment = Alignment(horizontal="center", vertical="center")
wb = openpyxl.load_workbook(SRC)
ws = wb.active
# 1) Horas trabajadas desde el CSV + overrides de datos por prefijo de nombre
for row in range(2, ws.max_row + 1):
nombre = str(ws.cell(row=row, column=1).value or "").strip()
if not nombre:
continue
# 1a) horas por fila (reparto trazable al CSV; ver HORAS_POR_FILA)
for prefijo, h in HORAS_POR_FILA.items():
if nombre.startswith(prefijo):
ws.cell(row=row, column=C_TRAB, value=h)
break
# 1b) overrides de %, fechas, nombre y rango estimado
for prefijo, ov in OVERRIDES.items():
if nombre.startswith(prefijo):
if "pct" in ov: ws.cell(row=row, column=C_PCT, value=ov["pct"])
if "trab" in ov: ws.cell(row=row, column=C_TRAB, value=round(ov["trab"], 2))
if "comienzo" in ov: ws.cell(row=row, column=3, value=ov["comienzo"])
if "fin" in ov: ws.cell(row=row, column=4, value=ov["fin"])
if "est" in ov: ws.cell(row=row, column=C_EST, value=ov["est"])
break
# 2) Recalcula el semáforo con HOY=27-jul (mismas reglas que el del 21-jul)
for row in range(2, ws.max_row + 1):
nombre = str(ws.cell(row=row, column=1).value or "").strip()
if not nombre or nombre.startswith("") or nombre.startswith(""):
continue
es_etapa = nombre.startswith("Etapa") or nombre.startswith("Integracion")
pct = ws.cell(row=row, column=C_PCT).value or 0
fin = fecha(ws.cell(row=row, column=4).value)
ini = fecha(ws.cell(row=row, column=3).value)
stat = ws.cell(row=row, column=C_STAT)
if es_etapa:
stat.value = ""
elif pct >= 1:
stat.value = "✅ Completada"; pinta(stat, V_FILL, V_FONT)
elif fin and fin < HOY:
stat.value = "🔴 Vencida"; pinta(stat, R_FILL, R_FONT, bold=True)
elif ini and ini <= HOY:
stat.value = "🟡 En curso"; pinta(stat, A_FILL, A_FONT)
elif pct > 0:
stat.value = "🟢 Adelantada"; pinta(stat, V_FILL, V_FONT)
else:
stat.value = "⚪ Próxima"; pinta(stat, G_FILL, G_FONT)
# semáforo en la celda de %
pcel = ws.cell(row=row, column=C_PCT)
if not es_etapa:
if pct >= 1: pinta(pcel, V_FILL, V_FONT, bold=True)
elif pct > 0: pinta(pcel, A_FILL, A_FONT, bold=True)
elif fin and fin < HOY: pinta(pcel, R_FILL, R_FONT, bold=True)
pcel.number_format = "0%"
ws.cell(row=row, column=C_TRAB).number_format = "0.00"
# 3) Overrides finos de estatus (bloqueos y dependencias)
for row in range(2, ws.max_row + 1):
nombre = str(ws.cell(row=row, column=1).value or "").strip()
for prefijo, (txt, fill, font, bold) in K_ESPECIAL.items():
if nombre.startswith(prefijo):
stat = ws.cell(row=row, column=C_STAT)
stat.value = txt
pinta(stat, fill, font, bold)
break
# 4) Renombra las filas que absorbieron alcance (al final: los pasos 2-3 buscan por
# el nombre original)
for row in range(2, ws.max_row + 1):
nombre = str(ws.cell(row=row, column=1).value or "").strip()
for prefijo, ov in OVERRIDES.items():
if "nombre" in ov and nombre.startswith(prefijo):
ws.cell(row=row, column=1, value=ov["nombre"])
break
# 5) Encabezado de la columna de estatus
ws.cell(row=1, column=C_STAT, value=f"Estatus (hoy {HOY.day}-jul)")
# 6) Reescribe leyenda/notas (borra las viejas)
for row in range(ws.max_row, 1, -1):
v = str(ws.cell(row=row, column=1).value or "")
if v.startswith(("✅ Completada ·", "▬ La línea roja", "Núcleo de la Etapa 1",
"🔴 La capa de escritura", "API de Jira:", "Horas:")):
for col in range(1, C_STAT + 1):
ws.cell(row=row, column=col).value = None
ley = ws.max_row + 2
notas = [
("✅ Completada · 🟡 En curso · 🔴 Vencida/Pendiente · ⚪ Próxima", G_FONT, True),
(f"Horas: {HORAS_ETAPA['0']:.2f} h de Etapa 0 y {HORAS_ETAPA['1']:.2f} h de Etapa 1 "
f"({TOTAL_CSV:.2f} h en total), conforme al control local de horas trabajadas. "
f"Etapa 1 estimada en 3239 h.", CAFE, False),
("Etapa 1: 6 de 8 entregables contractuales terminados — autenticación y roles con "
"bitácora, multi-tenant con RLS, cliente de BIND, sincronización de clientes, "
"sincronización de facturas y cotizaciones, y modelo de facturas con estados y "
"cartera por moneda. Verificado contra producción: 1,494 facturas sincronizadas "
"con la cartera cuadrada.", CAFE, False),
("🔴 La capa de escritura (cotización→factura) queda EN PAUSA a la espera de la "
"definición del flujo de facturación (sesión del martes 28-jul con Arturo y Araceli).",
"9C0006", False),
("Pendientes menores: datos de prueba (seeder) y verificación del aislamiento RLS "
"con rol no-superusuario. Azure y CI/CD dependen de accesos del lado de Balam.", CAFE, False),
("API de Jira: token recibido el 27-jul; la integración inicia una vez definido el flujo.",
CAFE, False),
]
for i, (txt, color, bold) in enumerate(notas):
c = ws.cell(row=ley + i, column=1, value=txt)
c.font = Font(italic=True, size=9, color=color, bold=bold)
ws.freeze_panes = "A2"
ws.oddFooter.center.text = (f"Avance al 27-jul-2026 · {TOTAL_CSV:.2f} h trabajadas "
"conforme al control local (pendiente conciliar con Jira)")
wb.save(DST)
# --- Verificación: el detalle debe cuadrar con el encabezado de cada etapa -----
print("OK ->", DST)
print(f" Etapa 0: {HORAS_ETAPA['0']:.2f} h · Etapa 1: {HORAS_ETAPA['1']:.2f} h "
f"· TOTAL {TOTAL_CSV:.2f} h")
suma_detalle = sum(HORAS_POR_FILA.values())
ok = abs(suma_detalle - TOTAL_CSV) < 0.01
print(f" Suma del detalle mostrado: {suma_detalle:.2f} h "
f"({'cuadra con el CSV' if ok else f'NO CUADRA (CSV {TOTAL_CSV:.2f})'})")
if not ok:
raise SystemExit("El detalle por fila no cuadra con el CSV — revisar HORAS_POR_FILA.")
@@ -0,0 +1,175 @@
"""Genera Avance-Balam-2026-07-27.xlsx — versión SIMPLE para enviar a Erika.
Se construye desde el Excel interno (`Plan-actividades-avance-2026-07-27.xlsx`),
que a su vez lee las horas de `Seguimiento-horas.csv`. Así los dos archivos nunca
se contradicen: este es una vista reducida, no una segunda fuente de datos.
Formato pedido por Erika el 21-jul: entregable + actividad + horas por etapa.
Se quitan del interno: rangos estimados, bloques del plan (B1/B4/B9), predecesoras
y duración en días — ruido para quien solo da seguimiento.
"""
import os
import re
from datetime import date
import openpyxl
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
from openpyxl.utils import get_column_letter
BASE = os.path.dirname(os.path.abspath(__file__))
SRC = os.path.join(BASE, "Plan-actividades-avance-2026-07-27.xlsx")
DST = os.path.join(BASE, "Avance-Balam-2026-07-27.xlsx")
HOY = date(2026, 7, 27)
# Marca Balam
CAFE, AMARILLO, CREMA = "331F0E", "F7BD0C", "FDF3D8"
V_FILL, V_FONT = "C6EFCE", "006100" # verde
A_FILL, A_FONT = "FFEB9C", "9C6500" # amarillo
R_FILL, R_FONT = "FFC7CE", "9C0006" # rojo
GRIS = "595959"
BORDE = "D9D9D9"
# Columnas del origen
O_NOMBRE, O_INI, O_FIN, O_PCT, O_TRAB, O_STAT = 1, 3, 4, 7, 10, 11
thin = Side(style="thin", color=BORDE)
box = Border(left=thin, right=thin, top=thin, bottom=thin)
def limpia_fecha(txt):
"""'vie 24/07/26' -> '24/07/2026'."""
m = re.search(r"(\d{2})/(\d{2})/(\d{2})", str(txt or ""))
return f"{m.group(1)}/{m.group(2)}/20{m.group(3)}" if m else ""
def es_etapa(nombre):
return nombre.startswith(("Etapa", "Integracion"))
# --- Lee el interno -----------------------------------------------------------
wsrc = openpyxl.load_workbook(SRC).active
filas = []
for row in range(2, wsrc.max_row + 1):
nombre = str(wsrc.cell(row=row, column=O_NOMBRE).value or "").strip()
if not nombre or nombre.startswith(("", "", "Horas:", "Etapa 1:", "🔴", "Pendientes",
"API de Jira", "Núcleo")):
continue
filas.append({
"nombre": nombre,
"ini": limpia_fecha(wsrc.cell(row=row, column=O_INI).value),
"fin": limpia_fecha(wsrc.cell(row=row, column=O_FIN).value),
"pct": wsrc.cell(row=row, column=O_PCT).value or 0,
"trab": wsrc.cell(row=row, column=O_TRAB).value,
"stat": str(wsrc.cell(row=row, column=O_STAT).value or "").strip(),
"etapa": es_etapa(nombre),
})
# --- Construye el simple ------------------------------------------------------
wb = openpyxl.Workbook()
ws = wb.active
ws.title = "Avance"
ws["A1"] = "Proyecto Balam · Plataforma de Automatización Financiera"
ws["A1"].font = Font(bold=True, size=14, color=CAFE)
ws["A2"] = f"Avance al {HOY.day}-jul-2026"
ws["A2"].font = Font(size=10, italic=True, color=GRIS)
ENC = ["Actividad", "Inicio", "Fin", "Avance", "Horas", "Estatus"]
ANCHOS = [52, 12, 12, 10, 9, 34]
FILA_ENC = 4
for i, (txt, ancho) in enumerate(zip(ENC, ANCHOS), start=1):
c = ws.cell(row=FILA_ENC, column=i, value=txt)
c.font = Font(bold=True, size=10, color=CAFE)
c.fill = PatternFill("solid", fgColor=AMARILLO)
c.alignment = Alignment(horizontal="center", vertical="center")
c.border = box
ws.column_dimensions[get_column_letter(i)].width = ancho
r = FILA_ENC + 1
for f in filas:
fill_etapa = PatternFill("solid", fgColor=CREMA) if f["etapa"] else None
c = ws.cell(row=r, column=1, value=f["nombre"])
c.font = Font(bold=f["etapa"], size=10, color=CAFE)
c.alignment = Alignment(vertical="center", wrap_text=True,
indent=0 if f["etapa"] else 1)
for col, val in ((2, f["ini"]), (3, f["fin"])):
cc = ws.cell(row=r, column=col, value=val)
cc.font = Font(size=9, color=GRIS)
cc.alignment = Alignment(horizontal="center", vertical="center")
# Avance
cp = ws.cell(row=r, column=4, value=f["pct"])
cp.number_format = "0%"
cp.alignment = Alignment(horizontal="center", vertical="center")
if f["pct"] >= 1:
cp.font = Font(bold=True, size=10, color=V_FONT)
cp.fill = PatternFill("solid", fgColor=V_FILL)
elif f["pct"] > 0:
cp.font = Font(bold=True, size=10, color=A_FONT)
cp.fill = PatternFill("solid", fgColor=A_FILL)
else:
cp.font = Font(size=10, color=GRIS)
# Horas
ch = ws.cell(row=r, column=5, value=f["trab"])
ch.number_format = "0.00"
ch.font = Font(bold=f["etapa"], size=10, color=CAFE)
ch.alignment = Alignment(horizontal="center", vertical="center")
# Estatus
cs = ws.cell(row=r, column=6, value=f["stat"])
cs.alignment = Alignment(horizontal="left", vertical="center", wrap_text=True)
cs.font = Font(size=9, color=GRIS)
if f["stat"].startswith(""):
cs.font = Font(size=9, color=V_FONT); cs.fill = PatternFill("solid", fgColor=V_FILL)
elif f["stat"].startswith("🟡"):
cs.font = Font(size=9, color=A_FONT); cs.fill = PatternFill("solid", fgColor=A_FILL)
elif f["stat"].startswith("🔴"):
cs.font = Font(size=9, bold=True, color=R_FONT); cs.fill = PatternFill("solid", fgColor=R_FILL)
for col in range(1, 7):
ws.cell(row=r, column=col).border = box
if fill_etapa and col in (1, 2, 3):
ws.cell(row=r, column=col).fill = fill_etapa
r += 1
# --- Notas --------------------------------------------------------------------
tot = next((f["trab"] for f in filas if f["nombre"].startswith("Integracion")), 0)
e0 = next((f["trab"] for f in filas if f["nombre"].startswith("Etapa 0")), 0)
e1 = next((f["trab"] for f in filas if f["nombre"].startswith("Etapa 1")), 0)
notas = [
("", False),
(f"Horas trabajadas: {e0:.2f} h en Etapa 0 y {e1:.2f} h en Etapa 1 "
f"({tot:.2f} h en total).", True),
("Etapa 1: 6 de los 8 entregables terminados — autenticación y roles con bitácora, "
"multi-tenant, cliente de la API de BIND, sincronización de clientes, "
"sincronización de facturas y cotizaciones, y modelo de facturas con estados y "
"cartera por moneda. Verificado contra producción: 1,494 facturas sincronizadas "
"con la cartera cuadrada.", False),
("La capa de escritura (cotización→factura) está en pausa a la espera de la "
"definición del flujo de facturación (sesión del martes 28-jul).", False),
("Azure y CI/CD esperan la configuración de los recursos del lado de Balam.", False),
]
for txt, bold in notas:
if txt:
c = ws.cell(row=r, column=1, value=txt)
c.font = Font(italic=True, size=9, color=CAFE, bold=bold)
c.alignment = Alignment(wrap_text=True, vertical="top")
ws.merge_cells(start_row=r, start_column=1, end_row=r, end_column=6)
ws.row_dimensions[r].height = 28 if len(txt) > 110 else 14
r += 1
ws.freeze_panes = f"A{FILA_ENC + 1}"
ws.sheet_view.showGridLines = False
ws.print_area = f"A1:F{r}"
ws.page_setup.orientation = "landscape"
ws.page_setup.fitToWidth = 1
ws.sheet_properties.pageSetUpPr.fitToPage = True
wb.save(DST)
print("OK ->", DST)
print(f" {len(filas)} filas · Etapa 0 {e0:.2f} h · Etapa 1 {e1:.2f} h · total {tot:.2f} h")
+113
View File
@@ -0,0 +1,113 @@
"""Ordena las actividades del Excel de avance por fecha de Comienzo, dentro de
cada etapa, conservando estilos, formatos, fórmulas de resumen y encabezados.
Estructura del plan:
fila 2 = Integración (resumen maestro) -> fija
fila 3 = Etapa 0 (encabezado) -> fija
filas 4-10 = tareas de Etapa 0 -> se ordenan por Comienzo
fila 11 = Etapa 1 (encabezado) -> fija
filas 12-24 = tareas de Etapa 1 -> se ordenan por Comienzo
Las celdas de fecha son texto ("mié 01/07/26"), así que se parsea el dd/mm/yy
para ordenar cronológicamente (no alfabéticamente, que ordenaría por día de
semana). En empate de Comienzo, se desempata por Fin y luego por el orden
original (estable), para no barajar tareas que arrancan el mismo día.
"""
import re
from copy import copy
from pathlib import Path
import openpyxl
DIRECTORY = Path(__file__).parent
TARGET = DIRECTORY / "Plan-actividades-avance-2026-07-16.xlsx"
# Grupos de filas de tareas a ordenar (rango inclusivo). Los encabezados
# (2, 3, 11) quedan fuera y no se mueven.
GROUPS = [(4, 10), (12, 24)]
DATE_RE = re.compile(r"(\d{2})/(\d{2})/(\d{2})")
def sort_key_from_cell(value):
"""Devuelve (aaaa, mm, dd) desde 'mié 01/07/26'; None si no hay fecha."""
if value is None:
return (9999, 99, 99)
m = DATE_RE.search(str(value))
if not m:
return (9999, 99, 99)
dd, mm, yy = (int(g) for g in m.groups())
return (2000 + yy, mm, dd)
def snapshot_row(sheet, row, max_col):
"""Captura valor + estilo + formato de cada celda de la fila, y el alto."""
cells = []
for col in range(1, max_col + 1):
c = sheet.cell(row, col)
cells.append(
{
"value": c.value,
"style": copy(c._style),
"number_format": c.number_format,
}
)
height = sheet.row_dimensions[row].height
return {"cells": cells, "height": height}
def restore_row(sheet, row, snap, max_col):
for col in range(1, max_col + 1):
c = sheet.cell(row, col)
data = snap["cells"][col - 1]
c.value = data["value"]
c._style = copy(data["style"])
c.number_format = data["number_format"]
if snap["height"] is not None:
sheet.row_dimensions[row].height = snap["height"]
def main():
wb = openpyxl.load_workbook(TARGET)
sh = wb["Plan"]
max_col = sh.max_column
for start, end in GROUPS:
snaps = [snapshot_row(sh, r, max_col) for r in range(start, end + 1)]
# Orden estable: por (Comienzo, Fin) usando el índice original como
# tercer criterio implícito de estabilidad de sorted().
order = sorted(
range(len(snaps)),
key=lambda i: (
sort_key_from_cell(snaps[i]["cells"][2]["value"]), # col C Comienzo
sort_key_from_cell(snaps[i]["cells"][3]["value"]), # col D Fin
),
)
reordered = [snaps[i] for i in order]
for offset, snap in enumerate(reordered):
restore_row(sh, start + offset, snap, max_col)
tmp = TARGET.with_suffix(".tmp.xlsx")
wb.save(tmp)
# Verificación: cada grupo queda no-decreciente por Comienzo.
check = openpyxl.load_workbook(tmp)["Plan"]
for start, end in GROUPS:
prev = (0, 0, 0)
for r in range(start, end + 1):
k = sort_key_from_cell(check.cell(r, 3).value)
assert k >= prev, f"Fila {r} fuera de orden: {k} < {prev}"
prev = k
# Los encabezados de etapa siguen en su lugar.
assert check.cell(3, 1).value == "Etapa 0"
assert check.cell(11, 1).value == "Etapa 1"
# Las fórmulas de resumen se conservan.
assert str(check.cell(11, 8).value).startswith("=SUM")
tmp.replace(TARGET)
print("Ordenado correctamente:", TARGET.name)
if __name__ == "__main__":
main()
+72
View File
@@ -0,0 +1,72 @@
# Plan: Documento "Plan-Etapa1.md" — plan fiel y completo de la Etapa 1
## Contexto
Johann necesita el plan de trabajo de la **Etapa 1 — "Plataforma base y sincronización con BIND"** (3239 h contractuales, semanas 23, ventana 1324 jul). Hoy 16-jul solo 1 de los 8 entregables contractuales está terminado (el cliente API de BIND, portado a C# con 13 pruebas) y hay 8 h registradas de la etapa; quedan ~2431 h y la demo semanal del **viernes 18-jul** es el compromiso más cercano. El usuario pidió un plan "lo más fiel posible" a toda la documentación (propuesta comercial v1.2, ADRs de Etapa 0, VALIDACION-API.md, bitácora, seguimiento de horas) — se revisó todo con 2 agentes de exploración y 1 de diseño.
**Decisión del usuario:** generar SOLO el documento (no arrancar implementación todavía), guardado en el repo privado de gestión `../balam` (nunca en el repo del cliente `balam-plataforma` — regla del CLAUDE.md de ese repo).
## Qué se hará
1. **Crear `planeacion/Plan-Etapa1.md`** en `c:\Users\JohannVelazquez\Desktop\Personal\balam` con el contenido detallado abajo.
2. **Agregar 1 línea de referencia** en `planeacion/Plan-actividades.md` (sección Etapa 1) apuntando al nuevo documento: `> Plan detallado de ejecución: [Plan-Etapa1.md](Plan-Etapa1.md)`.
3. Nada más: sin commits al repo del cliente, sin código. (El repo bitácora tiene cambios sin commitear del usuario; NO commitear nada ahí tampoco, solo dejar los archivos.)
## Contenido del documento Plan-Etapa1.md
Estructura y contenido esencial (redactado en español MX, estilo de los docs existentes de `planeacion/`):
### §1 Resumen y estado (al 16-jul)
- Entregable contractual de la etapa (propuesta L142157): plataforma que ingiere clientes/facturas de BIND, los normaliza, mantiene trazabilidad y habilita capa de escritura controlada. 3239 h · $19,200$23,400.
- Horas: 8.00 h registradas (reconstruidas) → quedan ~2431 h. Tabla de los 8 entregables contractuales con estado real (solo cliente BIND ✅; scaffold/DbContext/entidades semilla ✅ como avance parcial; resto ❌).
- Hechos del repo de código: solución .NET 10 compilando, 13 pruebas verdes, API con /health y /api/bind/status, Angular 21 con tema de marca.
### §2 Calendario e hitos externos
| Fecha | Hito |
|---|---|
| jue 17-jul | Fin de ventana planeada de backend base + multi-tenant |
| vie 18-jul | **Demo semanal (30 min, Pedro + gerencia)** — meta: login+roles, sync real de BIND en Postgres, endpoint de cartera |
| sem 21-jul | Acceso Azure (Pedro+Noé) — no bloquea trabajo local |
| mié 22-jul | **Sesión de definiciones Etapa 1** (Arturo + CEO): alta cliente, fee, envío, alcance Jira→BIND |
| jue 23-jul 7pm | Validación del prototipo Etapa 0 |
| vie 24-jul | CI/CD + secretos · demo/cierre de etapa |
### §3 Plan de construcción por bloques (B0B9, fases F1F6)
Incluir el plan técnico completo producido en el diseño (resumido aquí; el documento lo lleva íntegro):
- **F1 (16-jul) — B0 Preparación (0.51 h) + B1 Modelo de datos (3.54.5 h):** docker-compose Postgres 17 local; entidades `Tenant`, `Client`, `Invoice` (modelo central con estados), `Quote`, `QuoteInvoiceLink` (ADR-003), `InvoiceStatusChange` (ADR-004), `WriteOperation`; extender `SyncCheckpoint`/`AuditLogEntry` con TenantId; `BalamDbContext``IdentityDbContext<BalamUser,…>`; convenciones de fechas Npgsql (BIND sin zona → `timestamp without time zone`) y decimales; migración `Inicial` + `DbSeeder` idempotente (tenant Balam, 4 roles, 5 usuarios ficticios).
- **F2 (17-jul) — B2 Auth+roles+bitácora (45 h) + B3 Sync clientes (2.53.5 h):** ASP.NET Core Identity + JWT propio (sin MapIdentityApi, sin refresh tokens en E1); roles `Finanzas/Direccion/Operaciones/Administracion` (sin acentos como identificador); policies nombradas + matriz de acceso por endpoint; `AuditMiddleware` (mutantes + 401/403) + `IAuditLogger` explícito (login, ciclos de sync, escritura) — NO interceptor EF (inundaría con upserts del sync); sync de clientes: full-scan barato de lista (sin campo fecha filtrable) + `SourceHash` + detalle solo nuevos/cambiados + normalización RFC/nombre + dedup por RFC exacto excluyendo genéricos (`DuplicateOfClientId`).
- **F3 (18-jul am) — B4 Sync facturas/cotizaciones + cartera (4.55.5 h) → DEMO:** delta `Date ge` desde checkpoint + re-barrido de ventana de facturas abiertas (los pagos caen en facturas viejas) + detalle solo nuevas/cambiadas con tope por ciclo; mapeo de estados plataforma (Emitida=prefactura, Vigente, Vencida=derivada con fecha MX, Pagada, Cancelada) como **función pura con pruebas** (frontera Emitida/Vigente a confirmar el 22-jul); detección de pagos por transición → `InvoiceStatusChange` con fecha de DETECCIÓN (ADR-004); endpoints `GET /api/cartera` (agregados POR MONEDA, nunca mezclarlas), `/api/invoices`, `/api/clients`, `/api/quotes`, `POST /api/sync/run`; **sync inicial del histórico (>1,000 facturas) se corre el jueves en la noche, nunca en vivo**.
- **F4 (21-jul) — B5 Scheduler (23 h) + B6 RLS (1.52.5 h):** `BackgroundService` + `PeriodicTimer` 15 min (NO Quartz/Hangfire — un solo job, estado en checkpoints), `SemaphoreSlim` anti-solape, guarda de cuota vía `BindQuotaTracker` (reserva configurable), backfill gradual de detalle histórico; RLS REAL de Postgres (contractual): políticas `tenant_isolation` por tabla con `current_setting('app.tenant_id')` + `FORCE` + `WITH CHECK`, `TenantConnectionInterceptor` con `set_config`, más filtro global EF (`ITenantOwned`) como segunda capa; fuera: CRUD tenants, resolución por request.
- **F5 (22-jul, post-sesión) — B7 Capa de escritura controlada (34 h):** pipeline `Draft → DryRun → Confirm` persistido en `WriteOperations`, todo auditado; `BindWriteClient : BindClient` (reusa `RequestAsync` protected y sus salvaguardas); feature flags `BindWrite:Enabled=false` default; PPD default, PUE solo con confirmación explícita (salvaguarda 4); CERO llamadas reales a BIND — shapes provisionales marcados TODO hasta doc del portal con Pedro; conversión mock registra `QuoteInvoiceLink`.
- **F6 (2324 jul) — B8 Suite de pruebas (2.53.5 h) + B9 datos de prueba + runbook (12 h):** nuevo proyecto `tests/Balam.Api.Tests` con `WebApplicationFactory` + **SQLite in-memory** (no EF InMemory — no valida FKs/únicos; no Testcontainers — exige red/Docker en tests); cobertura contractual: matriz de roles, sync (delta/checkpoint/detección de pago), multimoneda, salvaguardas de escritura; `DevDataSeeder` ficticio multimoneda/multi-estado (respaldo de demo); runbook de demo.
### §4 Presupuesto de horas
Tabla B0B9 (nominal ~27.5 h, rango 2531) + recortes identificados (≈ 5 h): audit endpoint y quotes-sync pueden moverse post-demo; dedup solo RFC; backfill mínimo. B6 (RLS) NO recortable a cero por ser contractual.
### §5 Decisiones de arquitectura (con porqués, citables)
Scheduler BackgroundService vs Quartz; RLS real en dos capas; Identity+JWT sin refresh tokens (diferidos a Etapa 2 con la UI); bitácora middleware+servicio vs interceptor EF; SQLite en pruebas con costo aceptado (RLS/timestamptz se verifican manual en runbook); trampas Npgsql (fechas), "hoy" con zona México, `partial class Program`.
### §6 Bloqueado hasta el 22-jul y fuera de alcance
- Bloqueado: escritura real a BIND (ADR-001), reglas de alta de cliente/fee/envío, alcance Jira→BIND, semántica exacta Emitida/Vigente, mapeo `CFDIUse`→SAT.
- Fuera de Etapa 1: UI (E2), refresh tokens (E2), recordatorios a clientes (Anexo B), multiempresa (ADR-005), fecha valor de pagos/REP (ADR-004), aging/tablero (E3), conciliación, CI/CD+Azure (actividades propias 2124 jul), envío de PDF.
### §7 Riesgos y gestión (no técnico, en el mismo doc)
- Riesgos: primera corrida de sync en vivo (mitigado: jueves noche); filtro `CreationDate` de Quotes no validado (fallback full-scan); repo visible al cliente (solo datos ficticios, sin co-autoría en commits).
- Pendientes de gestión que tocan la etapa: correo formal a Noé (salvaguardas — borrador listo), 5 preguntas técnicas a Pedro (REP/pagos, `CFDIUse`, `/xml`, webhooks, token Power BI), borrar `bind_token_api.txt` del disco, registrar horas diario en `Seguimiento-horas.csv`, preparar sesión 22-jul (ya existe `Sesion-Etapa1-2026-07-22.md` — referenciarla).
## Archivos a crear/modificar
| Archivo | Acción |
|---|---|
| `c:\Users\JohannVelazquez\Desktop\Personal\balam\planeacion\Plan-Etapa1.md` | Crear (documento completo) |
| `c:\Users\JohannVelazquez\Desktop\Personal\balam\planeacion\Plan-actividades.md` | Agregar 1 línea de referencia en la sección Etapa 1 |
## Verificación
1. El documento existe, abre bien en Markdown y sus tablas renderizan (revisión visual).
2. Cifras contractuales cuadran con la propuesta: 3239 h, entregables L148155, roles y stack (verificar contra `propuesta/00 - PROPUESTA-COMERCIAL.md`).
3. Cifras de horas cuadran con `Seguimiento-horas.md` (8.00 h E1, 30 h totales).
4. Fechas cuadran con `bitacora/REGISTRO.md` #42#43 (22-jul, 23-jul, Azure sem 21, CI/CD 24).
5. El enlace desde `Plan-actividades.md` navega al nuevo documento.
6. Confirmar que NADA se escribió en el repo del cliente (`balam-plataforma` limpio: `git -C ...balam-plataforma status`).
+13 -7
View File
@@ -5,8 +5,8 @@
|---|---| |---|---|
| **Preparada para** | Noe Rocha (CTO) · Araceli Sánchez Jiménez (CEO/Operaciones) · Erika Chávez (PM) · Pedro Alberto Ayala Elizondo (Contacto técnico) | | **Preparada para** | Noe Rocha (CTO) · Araceli Sánchez Jiménez (CEO/Operaciones) · Erika Chávez (PM) · Pedro Alberto Ayala Elizondo (Contacto técnico) |
| **Preparada por** | Johann Velazquez — Consultor de Software · Monterrey, N.L. | | **Preparada por** | Johann Velazquez — Consultor de Software · Monterrey, N.L. |
| **Fecha** | Mayo 2026 | | **Fecha** | Mayo 2026 (actualizada julio 2026) |
| **Versión** | 1.1 — facturación BIND-first; ajustes comerciales acordados con Balam (8-jun-2026) | | **Versión** | 1.2 — facturación inicial de 30 h explícita y condiciones comerciales consolidadas (ajuste post-kickoff, 1-jul-2026). Base: v1.1 con ajustes acordados el 8-jun-2026 |
| **Vigencia** | 30 días naturales a partir de la fecha de emisión | | **Vigencia** | 30 días naturales a partir de la fecha de emisión |
--- ---
@@ -214,12 +214,16 @@ A cambio de esta flexibilidad, el esquema ofrece controles concretos:
La dedicación es de **media jornada (aproximadamente 20 h/semana**, con flexibilidad hasta 25 h en semanas de mayor carga). Sobre esa base, la primera etapa requiere **112 a 136 horas**, equivalentes a **6 7 semanas** de calendario. La dedicación es de **media jornada (aproximadamente 20 h/semana**, con flexibilidad hasta 25 h en semanas de mayor carga). Sobre esa base, la primera etapa requiere **112 a 136 horas**, equivalentes a **6 7 semanas** de calendario.
### 3.3 Tarifa y facturación ### 3.3 Condiciones comerciales
Esta sección concentra **todos** los términos comerciales del proyecto (tarifa, facturación, pago y arranque), para su lectura en un solo lugar.
- **Tarifa:** **$600 MXN por hora trabajada** + IVA, con comprobante fiscal CFDI 4.0. Aplica de igual forma a las fases posteriores (Anexo B) y a la bolsa de horas de soporte (§5). - **Tarifa:** **$600 MXN por hora trabajada** + IVA, con comprobante fiscal CFDI 4.0. Aplica de igual forma a las fases posteriores (Anexo B) y a la bolsa de horas de soporte (§5).
- **Facturación:** por etapa, conforme se entrega cada una (con el anexo de desglose de horas por tarea). La Etapa 0 se factura al inicio del proyecto. - **Facturación inicial (arranque):** **30 horas — $18,000 MXN + IVA**, facturadas al inicio del proyecto. Este primer pago **cubre la Etapa 0 completa (Discovery, 1822 h) y el inicio de la Etapa 1**, y activa el flujo de cobro. Su pago corre a **30 días naturales**.
- **Pago:** a **30 días naturales** posteriores a la factura, mediante transferencia, conforme a la política de Balam. - **Facturación de avances:** posterior a la inicial, **semanal (viernes)** por las horas efectivamente trabajadas, con desglose por tarea, conforme al contrato de prestación de servicios.
- **Arranque sin anticipo:** conforme a la política de Balam, no se maneja anticipo. La **Etapa 0 (30 horas, $18,000 MXN + IVA)** se factura al inicio y su pago corre a 30 días, igual que los avances. El arranque queda condicionado a la **firma del contrato / orden de trabajo**, que formaliza el compromiso de ambas partes en sustitución del anticipo. Si Discovery revela bloqueadores que modifiquen el alcance de forma significativa, se replantea el plan antes de continuar. - **Pago:** a **30 días naturales** posteriores a cada factura, mediante transferencia, conforme a la política de Balam.
- **Sin anticipo:** conforme a la política de Balam no se maneja anticipo; el arranque queda condicionado a la **firma del contrato / orden de trabajo** (ya cumplida), que formaliza el compromiso de ambas partes en sustitución del anticipo.
- **Ajuste de alcance:** si el Discovery revela bloqueadores que modifiquen el alcance de forma significativa, se replantea el plan antes de continuar.
### 3.4 Comunicación ### 3.4 Comunicación
@@ -255,6 +259,8 @@ La inversión de la primera etapa se desglosa por entregable, conforme al esquem
> Cifras antes de IVA. Plazo estimado: **6 7 semanas** a media jornada (~20 h/semana, con flexibilidad hasta 25 h en semanas pico). > Cifras antes de IVA. Plazo estimado: **6 7 semanas** a media jornada (~20 h/semana, con flexibilidad hasta 25 h en semanas pico).
> **Facturación inicial (vinculante para el primer pago):** el primer pago corresponde a **30 horas — $18,000 MXN + IVA**, que cubren la **Etapa 0 completa (1822 h) y el inicio de la Etapa 1**; se factura al arranque del proyecto y su pago corre a 30 días naturales (ver §3.3). Los avances posteriores se facturan semanalmente (viernes) por horas efectivamente trabajadas.
> El esquema de control por etapa busca que la inversión se concentre en la parte baja del rango; el margen superior cubre eventualidades del Discovery con BIND. Toda variación se comunica antes de incurrir en ella. > El esquema de control por etapa busca que la inversión se concentre en la parte baja del rango; el margen superior cubre eventualidades del Discovery con BIND. Toda variación se comunica antes de incurrir en ella.
--- ---
@@ -364,7 +370,7 @@ Más allá del código funcional, la entrega incluye:
1. Sesión de revisión de esta propuesta (1 h) para resolver dudas y ajustar lo que corresponda. 1. Sesión de revisión de esta propuesta (1 h) para resolver dudas y ajustar lo que corresponda.
2. **Firma del contrato / orden de trabajo** (prestación de servicios y confidencialidad) — formaliza el compromiso para arrancar sin anticipo. 2. **Firma del contrato / orden de trabajo** (prestación de servicios y confidencialidad) — formaliza el compromiso para arrancar sin anticipo.
3. **Factura de la Etapa 0** (30 horas, **$18,000 MXN** + IVA), con pago a 30 días, para iniciar Discovery. 3. **Facturación inicial** (30 horas **$18,000 MXN** + IVA), que cubre la Etapa 0 y el inicio de la Etapa 1 (ver §3.3), con pago a 30 días naturales, para iniciar Discovery.
4. Arranque del proyecto, con entrega del MVP en **6 7 semanas**. 4. Arranque del proyecto, con entrega del MVP en **6 7 semanas**.
--- ---
File diff suppressed because it is too large Load Diff
Binary file not shown.
+4 -4
View File
@@ -9,8 +9,8 @@
"metadata": { "metadata": {
"title": "Propuesta Comercial — Plataforma de Automatización Financiera · Balam", "title": "Propuesta Comercial — Plataforma de Automatización Financiera · Balam",
"author": "Johann Velazquez", "author": "Johann Velazquez",
"subject": "MVP de facturación y cobranza sobre BIND ERP — propuesta v1.1", "subject": "MVP de facturación y cobranza sobre BIND ERP — propuesta v1.2",
"keywords": "propuesta, Balam, BIND ERP, facturación, MVP, v1.1" "keywords": "propuesta, Balam, BIND ERP, facturación, MVP, v1.2"
}, },
"footer": { "footer": {
@@ -35,13 +35,13 @@
"2": "entrega valor real en el menor tiempo posible", "2": "entrega valor real en el menor tiempo posible",
"3": "horas reales con tarifa transparente", "3": "horas reales con tarifa transparente",
"4": "se desglosa por entregable, conforme al esquema", "4": "se desglosa por entregable, conforme al esquema",
"5": "para la operación y evolución incremental", "5": "se ofrece una bolsa de horas a la misma tarifa",
"6": "servicios de infraestructura externos, independientes", "6": "servicios de infraestructura externos, independientes",
"7": "depende de las siguientes condiciones", "7": "depende de las siguientes condiciones",
"8": "Más allá del código funcional, la entrega incluye", "8": "Más allá del código funcional, la entrega incluye",
"9": "Rediseño visual integral o sistema de diseño propio", "9": "Rediseño visual integral o sistema de diseño propio",
"10": "se documenta como solicitud de cambio", "10": "se documenta como solicitud de cambio",
"11": "Sesión de revisión de esta propuesta", "11": "orden de trabajo (prestación de servicios y confidencialidad)",
"anexoA": "relaciona cada funcionalidad y requerimiento", "anexoA": "relaciona cada funcionalidad y requerimiento",
"anexoB": "rangos indicativos, no compromisos contractuales" "anexoB": "rangos indicativos, no compromisos contractuales"
} }
+33
View File
@@ -0,0 +1,33 @@
# Correo — Prototipo navegable Etapa 0 (para validación)
Enviado · 10-jul-2026
Adjunto: Prototipo-Balam-Etapa0.pdf
Para: Erika Chávez; Ing. Noé Rocha
CC: Pedro Ayala
(sin Araceli, según indicó Erika el 10-jul)
**Respuesta de Balam:** revisión interna en curso; sesión de validación confirmada para el 23-jul-2026 a las 7:00 pm.
Asunto: Balam · Prototipo navegable de la Etapa 0 (para validación)
======================================================================
Hola Erika, Ing. Noé:
Como lo comentamos, les comparto el prototipo navegable de la plataforma de facturación y cobranza, correspondiente al entregable de la Etapa 0 (Discovery).
El prototipo refleja el proceso real que levantamos en las sesiones con Araceli y Arturo: solicitud en Jira, cotización BIND, prefactura, aprobación humana, CFDI y envío al cliente; más la parte de cobranza (antigüedad de saldos por factura con tolerancia a comisiones, pagos y recordatorios). También incorpora las reglas de validación que surgieron en el Discovery: PPD por defecto, IVA 16%/0%, prefactura siempre antes de timbrar y la cotización BIND como punto de partida obligatorio.
Lo pueden revisar de dos formas:
1. PDF adjunto: recorrido pantalla por pantalla con una breve descripción de cada una.
2. Versión navegable (por si quieren recorrerla ustedes mismos): paputec.mx/balam, entran directo. Es un entorno temporal de demostración con datos 100% ficticios, sin conexión a BIND ni a datos reales; lo doy de baja al cerrar la validación.
Toda la información que ven (clientes, montos, folios) es ilustrativa, únicamente para visualizar el flujo.
Quedo muy atento a sus comentarios; si les resulta más cómodo, con gusto agendamos una sesión corta para recorrerlo juntos y afinar detalles.
Saludos cordiales,
Johann Velázquez
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 606 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB