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>
This commit is contained in:
Johann
2026-07-27 08:18:08 -06:00
parent bebca73bfe
commit bee2d02f50
10 changed files with 1270 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
# 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:** 17.0 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 **17 h de Etapa 1** (rango estimado 3239 h). 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*. 🔴 **En 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é. El andamiaje (pipeline dry-run→confirm, flags apagados, `WriteOperations`) está diseñado; se implementa contra las reglas ya cerradas.
- **Scheduler + backfill** (sync programado cada 15 min) — el sync ya funciona en manual; falta automatizarlo.
- **Datos de prueba (seeder) + runbook** — *entregable 8*: migraciones ✅, seeder ficticio pendiente.
- **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.
- **Token de Jira (PAF)** recibido el 27-jul + docs de Atlassian; falta confirmar límites de consumo (Pedro investiga). Bandeja: **Facturación (FAC)**.
- **Acceso a Azure + CI/CD** (Pedro/Noé) — condiciona el despliegue.
## Criterio de medición
- **Horas de Etapa 1:** 17.0 h registradas de un rango de 3239 h (**~4453 % del esfuerzo estimado**).
- **Entregables contractuales:** **6 de 8 terminados** (1, 2, 3, 5, 6, 7); el 8 parcial (migraciones sí, seeder no); el 4 (escritura) en pausa por definición de Balam.
- Se reporta por hora + entregable, no un porcentaje global único, para no dar una cifra engañosa. El Excel muestra ~82 % ponderado por actividad porque el trabajo restante (escritura, seeder, scheduler) es de menor peso que el núcleo ya hecho, pero **la escritura está bloqueada por la definición pendiente de Balam**, no por avance de desarrollo.
## Puntos de juicio a confirmar por Johann antes de enviar
1. **Horas 2227 jul:** solo cargué las sesiones documentadas (reglas 22-jul 0.80 h, validación 24-jul 1.05 h como Etapa 0, API Jira 27-jul 0.20 h). Si trabajaste desarrollo adicional en esa ventana, hay que sumarlo.
2. **% de Etapa 1 (82 %):** es el valor ponderado heredado del corte del 21-jul + avance; si prefieres una lectura más conservadora (por horas, ~50 %), lo ajusto.
3. **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, lo cambio.
@@ -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.
Binary file not shown.
+2
View File
@@ -28,3 +28,5 @@ fecha,semana,etapa,actividad_id,actividad,horas,estado_hora,fuente_evidencia,fac
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-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-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
28 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
29 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
30 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)
31 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)
32 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
+146
View File
@@ -0,0 +1,146 @@
"""Genera Plan-actividades-avance-2026-07-27.xlsx a partir del del 21-jul.
Aplica las horas y estatus reales al 27-jul: sesión de reglas (22-jul) y
validación del prototipo (24-jul, APROBADO) completadas; sesión de API de Jira
(27-jul) en curso; capa de escritura EN PAUSA a la espera de la definición del
flujo de facturación (sesión 28-jul con Arturo/Araceli).
Reutiliza el estilo/semáforo del archivo del 21-jul."""
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-21.xlsx"
DST = "/Users/johann/Desktop/Proyectos personales/BALAM/planeacion/Plan-actividades-avance-2026-07-27.xlsx"
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
# Prefijo de la actividad -> overrides de datos (pct=%, trab=horas, comienzo/fin=fechas texto)
OVERRIDES = {
"Integracion de plataformas Balam": dict(pct=0.67, trab=40),
"Etapa 0": dict(pct=1.0, trab=23),
"Documento de hallazgos": dict(pct=1.0),
"Sesión de validación del prototipo": dict(pct=1.0, trab=1.05,
comienzo="vie 24/07/26", fin="vie 24/07/26"),
"Etapa 1": dict(pct=0.82, trab=17),
"Demostración semanal": dict(trab=1.75),
"Sesión de reglas y dudas": dict(pct=1.0, trab=0.80),
"Definición de alcance Jira": dict(pct=0.40, trab=0.20),
}
# 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": ("🟡 En curso · falta seeder", A_FILL, A_FONT, False),
"Capa de escritura controlada": ("🔴 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": ("🟡 En curso · API Jira 27-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) Aplica 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
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=ov["trab"])
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"])
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.0"
# 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) Encabezado de la columna de estatus y pie
ws.cell(row=1, column=C_STAT, value=f"Estatus (hoy {HOY.day}-jul)")
# 5) Reescribe leyenda/notas (borra las viejas de la línea de HOY del 21-jul)
for row in range(ws.max_row, 1, -1):
v = str(ws.cell(row=row, column=1).value or "")
if v.startswith("✅ Completada ·") or v.startswith("▬ La línea roja"):
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),
("Núcleo de la Etapa 1 construido y verificado contra producción: autenticación y roles, "
"bitácora, multi-tenant con RLS, cliente de BIND, sincronización de clientes/facturas/"
"cotizaciones, modelo de facturas con estados y cartera por moneda.", 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),
("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 = "Avance al 27-jul-2026 · Horas conforme al control local (pendiente conciliar con Jira)"
wb.save(DST)
print("OK ->", DST)