Cierre 21-jul: B4 con sync histórico verificado y B6 aplicado; horas, bitácora y Excel de avance al día

This commit is contained in:
Johann
2026-07-22 00:06:54 -06:00
parent 388e772c40
commit c3e984944e
7 changed files with 318 additions and 1 deletions
+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.
+10
View File
@@ -17,3 +17,13 @@ fecha,semana,etapa,actividad_id,actividad,horas,estado_hora,fuente_evidencia,fac
2026-07-15,2026-W29,1,E1-03,Arquitectura multi-tenant,0.50,reconstruida,planeacion/Plan-actividades.md,si,"Completa 1.50 h"
2026-07-15,2026-W29,1,E1-04,Cliente productivo de API BIND,2.00,reconstruida,bind-api-sandbox/VALIDACION-API.md,si,"Inicio de reintentos OData y manejo de errores"
2026-07-15,2026-W29,1,E1-05,Seguimiento ajuste de calendario y corte de horas,0.50,reconstruida,bitacora/REGISTRO.md#41-45,si,"Actualización de plan y control"
2026-07-16,2026-W29,1,E1-06,Scaffold backend .NET 10 + frontend Angular 21 y push al repo de Balam,2.00,reconstruida,bitacora/REGISTRO.md#46,si,"Commits 220942a..1f7f098; incluye CLAUDE.md del repo; validar duración"
2026-07-16,2026-W29,1,E1-05,Corte de avance Etapa 1 para Erika (Excel + mensaje),1.00,reconstruida,planeacion/Avance-Etapa1-2026-07-16.md,si,"Enviado 8:40 pm por WhatsApp con acuse; validar duración"
2026-07-19,2026-W29,1,E1-06,Preparación de entorno local (clon del repo, SDK .NET 10, secrets, app corriendo),1.00,reconstruida,bitacora/REGISTRO.md,si,"API y frontend verificados en local; 13/13 pruebas verdes; validar duración"
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"
1 fecha semana etapa actividad_id actividad horas estado_hora fuente_evidencia facturable notas
17 2026-07-15 2026-W29 1 E1-03 Arquitectura multi-tenant 0.50 reconstruida planeacion/Plan-actividades.md si Completa 1.50 h
18 2026-07-15 2026-W29 1 E1-04 Cliente productivo de API BIND 2.00 reconstruida bind-api-sandbox/VALIDACION-API.md si Inicio de reintentos OData y manejo de errores
19 2026-07-15 2026-W29 1 E1-05 Seguimiento ajuste de calendario y corte de horas 0.50 reconstruida bitacora/REGISTRO.md#41-45 si Actualización de plan y control
20 2026-07-16 2026-W29 1 E1-06 Scaffold backend .NET 10 + frontend Angular 21 y push al repo de Balam 2.00 reconstruida bitacora/REGISTRO.md#46 si Commits 220942a..1f7f098; incluye CLAUDE.md del repo; validar duración
21 2026-07-16 2026-W29 1 E1-05 Corte de avance Etapa 1 para Erika (Excel + mensaje) 1.00 reconstruida planeacion/Avance-Etapa1-2026-07-16.md si Enviado 8:40 pm por WhatsApp con acuse; validar duración
22 2026-07-19 2026-W29 1 E1-06 Preparación de entorno local (clon del repo SDK .NET 10 secrets app corriendo) 1.00 reconstruida
23 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
24 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
25 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
26 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
27 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
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
+8
View File
@@ -32,6 +32,7 @@ Al terminar deben quedar definidos:
- ¿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.
@@ -60,6 +61,13 @@ Si Balam confirma la automatización, solicitar posteriormente:
- 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
+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)