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.
This commit is contained in:
Binary file not shown.
@@ -2,7 +2,7 @@
|
||||
|
||||
**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:** 32–39 h · **Horas registradas de Etapa 1:** 17.0 h
|
||||
**Rango estimado contractual:** 32–39 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).
|
||||
@@ -17,7 +17,7 @@
|
||||
>
|
||||
> 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 32–39 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. 🙌
|
||||
> En horas voy en **19.75 h de Etapa 1** (rango estimado 32–39 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.)*
|
||||
|
||||
@@ -37,23 +37,33 @@
|
||||
- 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.
|
||||
- **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*: migraciones ✅, seeder ficticio pendiente.
|
||||
- **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.
|
||||
- **Token de Jira (PAF)** recibido el 27-jul + docs de Atlassian; falta confirmar límites de consumo (Pedro investiga). Bandeja: **Facturación (FAC)**.
|
||||
- **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
|
||||
- **Horas de Etapa 1:** 17.0 h registradas de un rango de 32–39 h (**~44–53 % 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.
|
||||
- **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 32–39 h (**~51–62 % 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`).
|
||||
|
||||
## Puntos de juicio a confirmar por Johann antes de enviar
|
||||
1. **Horas 22–27 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.
|
||||
## 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 18–22 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.
|
||||
|
||||
Binary file not shown.
@@ -1,32 +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,reconstruida,planeacion/Kickoff-2026-07-01.md,si,"Estimación retrospectiva; validar antes de facturar"
|
||||
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.92,reconstruida,bitacora/REGISTRO.md#27,si,"Completa 3.00 h para facturación/envío incluyendo sesión"
|
||||
2026-07-06,2026-W28,0,E0-03,Coordinación y validación de accesos BIND y marca,1.00,reconstruida,bitacora/REGISTRO.md#28-31,si,"Recepción documentación y salvaguardas"
|
||||
2026-07-06,2026-W28,0,E0-04,Validación técnica de API BIND,4.50,reconstruida,bind-api-sandbox/VALIDACION-API.md,si,"117 GET análisis y reporte técnico"
|
||||
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,1.50,reconstruida,fuentes/2026-07-07 - Notas - Proceso actual de cobranza (sin grabacion).md,si,"Estimación retrospectiva"
|
||||
2026-07-08,2026-W28,0,E0-05,Diseño y construcción del prototipo,3.00,reconstruida,prototipo/Prototipo-Etapa0.html,si,"Primera mitad del esfuerzo reconstruido"
|
||||
2026-07-09,2026-W28,0,E0-05,Ajustes de cobranza navegación y prototipo,3.00,reconstruida,prototipo/Prototipo-Etapa0.html,si,"Segunda mitad del esfuerzo reconstruido"
|
||||
2026-07-10,2026-W28,0,E0-06,Entregable hallazgos ADRs PDF correo y plan,3.00,reconstruida,prototipo/Correo-prototipo-Etapa0.md,si,"Incluye preparación del entregable y documentación"
|
||||
2026-07-13,2026-W29,1,E1-01,Backend base autenticación roles y auditoría,2.00,reconstruida,planeacion/Plan-actividades.md,si,"Trabajo local; falta conciliar contra evidencia de código"
|
||||
2026-07-13,2026-W29,1,E1-02,Coordinación del repositorio GitHub,0.50,reconstruida,bitacora/REGISTRO.md#43,si,"Seguimiento de creación y acceso"
|
||||
2026-07-14,2026-W29,1,E1-01,Backend base autenticación roles y auditoría,1.50,reconstruida,planeacion/Plan-actividades.md,si,"Trabajo local; completa 3.50 h"
|
||||
2026-07-14,2026-W29,1,E1-03,Arquitectura multi-tenant,1.00,reconstruida,planeacion/Plan-actividades.md,si,"Diseño inicial tenant_id y RLS"
|
||||
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-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-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)"
|
||||
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:00–7: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"
|
||||
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
|
||||
|
||||
|
@@ -5,7 +5,7 @@ Fuente local de horas efectivamente trabajadas para el proyecto Balam. Se mantie
|
||||
**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-15
|
||||
**Última actualización:** 2026-07-27
|
||||
|
||||
## Reglas de captura
|
||||
|
||||
@@ -16,47 +16,67 @@ Fuente local de horas efectivamente trabajadas para el proyecto Balam. Se mantie
|
||||
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 reconstruido al 15-jul
|
||||
## Corte al 27-jul
|
||||
|
||||
| Etapa | Horas al corte | Rango estimado de la etapa | Estado |
|
||||
|---|---:|---:|---|
|
||||
| Etapa 0 | **22.00 h** | 18–22 h | Límite superior consumido; prototipo pendiente de validación |
|
||||
| Etapa 1 | **8.00 h** | 32–39 h | En curso |
|
||||
| **Total** | **30.00 h** | | Coincide con la facturación inicial propuesta |
|
||||
| Etapa 0 | **21.83 h** | 18–22 h | Cerrada y **validada por Balam el 24-jul**; dentro del rango |
|
||||
| Etapa 1 | **19.75 h** | 32–39 h | En curso; 6 de 8 entregables terminados |
|
||||
| **Total** | **41.58 h** | | |
|
||||
|
||||
Las **26.92 h** que no corresponden a sesiones con duración documentada se reconstruyeron retrospectivamente por actividad. Deben validarse contra memoria, archivos de trabajo y Jira antes de presentarse como horas efectivamente trabajadas.
|
||||
**Estado de validación de las horas (27-jul):**
|
||||
|
||||
## Horas con duración comprobable
|
||||
| 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 |
|
||||
|
||||
| Semana | Etapa | Horas confirmadas | Alcance incluido |
|
||||
|---|---:|---:|---|
|
||||
| 2026-W27 | 0 | 1.00 | Kickoff |
|
||||
| 2026-W28 | 0 | 2.08 | Discovery de facturación/envío y cobranza |
|
||||
| **Total comprobable** | | **3.08** | Solo sesiones con duración documentada |
|
||||
## Distribución al 27-jul
|
||||
|
||||
> Las 3.08 h están incluidas dentro del corte reconstruido de 30 h; no deben sumarse nuevamente.
|
||||
| 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 (B0–B4) | 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** |
|
||||
|
||||
## Distribución reconstruida
|
||||
> **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 18–22 h.
|
||||
|
||||
Johann debe confirmar esta distribución antes de usarla para facturación:
|
||||
### Nota sobre las sesiones asistidas por IA
|
||||
|
||||
| Etapa | Actividad consolidada | Horas |
|
||||
|---|---|---:|
|
||||
| 0 | Kickoff y preparación | 2.00 |
|
||||
| 0 | Discovery de facturación, envío y cobranza | 5.50 |
|
||||
| 0 | Accesos y salvaguardas | 1.00 |
|
||||
| 0 | Validación técnica de BIND | 4.50 |
|
||||
| 0 | Prototipo navegable | 6.00 |
|
||||
| 0 | Entregable, hallazgos, ADRs y plan | 3.00 |
|
||||
| 1 | Backend base | 3.50 |
|
||||
| 1 | Arquitectura multi-tenant | 1.50 |
|
||||
| 1 | Cliente productivo de BIND | 2.00 |
|
||||
| 1 | Repositorio y seguimiento | 1.00 |
|
||||
| | **Total** | **30.00** |
|
||||
Los bloques B0–B6 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 4–5.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 32–39 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 8–9 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 3–4 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.
|
||||
- Esas 30 h son el concepto comercial autorizado en la propuesta, pero el contrato exige reportar horas efectivamente trabajadas.
|
||||
- Antes de emitir, Johann debe validar el desglose reconstruido y conciliarlo contra Jira.
|
||||
- La emisión sigue pendiente de confirmación de Balam al correo del 2-jul.
|
||||
- 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.
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
"""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"
|
||||
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"
|
||||
@@ -21,17 +33,115 @@ 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)
|
||||
# --- 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.67, trab=40),
|
||||
"Etapa 0": dict(pct=1.0, trab=23),
|
||||
"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, 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),
|
||||
"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="8–9"),
|
||||
"Arquitectura multi-tenant": dict(
|
||||
nombre="Arquitectura multi-tenant (tenant_id + RLS) y diseño de la solución",
|
||||
est="3–4"),
|
||||
"Demostración semanal": dict(est="2–3"),
|
||||
# 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
|
||||
@@ -39,37 +149,51 @@ 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),
|
||||
"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": ("🟡 En curso · API Jira 27-jul", A_FILL, A_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) Aplica overrides de datos por prefijo de nombre
|
||||
# 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=ov["trab"])
|
||||
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)
|
||||
@@ -103,7 +227,7 @@ for row in range(2, ws.max_row + 1):
|
||||
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"
|
||||
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):
|
||||
@@ -115,32 +239,62 @@ for row in range(2, ws.max_row + 1):
|
||||
pinta(stat, fill, font, bold)
|
||||
break
|
||||
|
||||
# 4) Encabezado de la columna de estatus y pie
|
||||
# 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)")
|
||||
|
||||
# 5) Reescribe leyenda/notas (borra las viejas de la línea de HOY del 21-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 ·") or v.startswith("▬ La línea roja"):
|
||||
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),
|
||||
("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),
|
||||
(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 32–39 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 = "Avance al 27-jul-2026 · Horas conforme al control local (pendiente conciliar con Jira)"
|
||||
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")
|
||||
Reference in New Issue
Block a user