From 820b8d41c8b9b4714f358f5bf88e536a025081c5 Mon Sep 17 00:00:00 2001 From: JohannVelazquez Date: Tue, 28 Jul 2026 22:21:04 -0600 Subject: [PATCH] Valida y consolida las horas al 27-jul: 41.58 h trazables desde el CSV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- bitacora/REGISTRO.md | 36 +++ planeacion/Avance-Balam-2026-07-27.xlsx | Bin 0 -> 7440 bytes planeacion/Avance-Etapa1-2026-07-27.md | 34 ++- .../Plan-actividades-avance-2026-07-27.xlsx | Bin 8630 -> 8881 bytes planeacion/Seguimiento-horas.csv | 62 ++--- planeacion/Seguimiento-horas.md | 82 ++++--- planeacion/generar_avance_2026_07_27.py | 226 +++++++++++++++--- .../generar_resumen_erika_2026_07_27.py | 175 ++++++++++++++ 8 files changed, 507 insertions(+), 108 deletions(-) create mode 100644 planeacion/Avance-Balam-2026-07-27.xlsx create mode 100644 planeacion/generar_resumen_erika_2026_07_27.py diff --git a/bitacora/REGISTRO.md b/bitacora/REGISTRO.md index 02c58c9..98f8955 100644 --- a/bitacora/REGISTRO.md +++ b/bitacora/REGISTRO.md @@ -1067,6 +1067,42 @@ Cierre de la sesión (~0.5 h real). **B6 conforme al plan:** `ITenantOwned` en l --- +## 58 · Jul 27–28, 2026 · WhatsApp Erika ↔ Johann · avance de Etapa 1 entregado, Excel de horas para FACTURACIÓN y Jira aún sin licencia ⭐ + +> Continuación de [#57](REGISTRO.md). Registrado a partir de capturas de pantalla del hilo (4 imágenes). Cubre el envío del avance del 27-jul y los pedidos de Erika del 27 (tarde) y 28 (mañana). + +**27-jul, mañana — avance de Etapa 1 entregado por mensaje:** Erika pidió los avances de Etapa 1 (📷 captura del plan, 7:11 am). Johann preguntó si ya existe **un Jira para el seguimiento de este proyecto** —es decir, dónde llevar sus actividades y horas, no la instancia a integrar— (7:14 am) → **respuesta de Erika (7:54 am): "aún estamos viendo lo de alguna licencia... pero estamos viendo una segunda opción y no Jira precisamente".** Johann ofreció trabajar en un Excel compartido; Erika contestó que le comentó a Pedro que **pudiera ser un Drive para subir la documentación, pero están en espera de la validación** (8:57 am). + +> ⚠️ **Precisión importante:** este intercambio es sobre la **herramienta de gestión del proyecto** (dónde se registran actividades y horas de Johann), NO sobre la integración técnica. El Jira a integrar es la **instancia productiva de TI que administra Pedro** —bandeja FAC, token PAF a 1 año, API read+write confirmada ([#56](REGISTRO.md))— y ese no está en duda. Consecuencia práctica: **mientras no haya herramienta de gestión, el Excel de horas de Johann ES el sistema de seguimiento del proyecto**, lo que explica la insistencia de Erika en el desglose por etapa. + +Johann envió el **avance por actividad en texto** (8:12 am), con 👍 de Erika y "gracias" (8:58 am): +> ✅ Sincronización de clientes — hecho y verificado · ✅ Sincronización de facturas/cotizaciones — hecho, 1,494 facturas cuadran · ✅ Modelo + migraciones + datos de prueba — hecho · ⏸️ Capa de escritura — en la junta del viernes comentaron que iban a definir el flujo de facturación; en cuanto quede, la implemento (Balam) · ⏳ Config. Azure (+ staging) — espera el acceso a Azure de Pedro/Noé (Balam) · ⏳ CI/CD + secretos — depende de Azure (Balam) + +**27-jul, tarde — la fila de escritura y la sesión del proceso:** Erika preguntó (3:35 pm) si la capa de escritura *"es la que está pendiente de lo que se mencionó el viernes de que validarían el flujo"* → Johann confirmó. Erika: **"es que lo tengo al 100%"** (3:40 pm) → **Johann corrigió: "lo volví a marcar como pendiente porque se iba a validar el proceso"** y preguntó cuándo podrían tener la junta revisando el proceso validado (3:44–3:45 pm). Erika: le comentó a Arturo, y como **Ara sale de viaje**, mañana en la oficina ve cuándo **revisarlo internamente y después pasarlo con Johann**; queda en avisar (3:49 pm). ⚠️ **La sesión del 28-jul no quedó confirmada — se movió a revisión interna de Balam primero.** + +**27-jul, 4:59 pm — pedido formal de horas:** *"johan un favor, me puedes pasar en un excel tus horas que llevas de cada etapa por favor"* → **Johann envió `Avance-Balam-2026-07-27.xlsx` a las 6:45 pm** (versión simplificada). Johann ofreció además pasar un Excel para las siguientes etapas; Erika (7:57 pm): *"Y las ya completas más que nada para ver cuántas son"*. + +**28-jul, mañana — el propósito del Excel y dos pendientes:** +1. **(8:36 am) ⭐ "es para llevar el conteo de horas de cada etapa sobre todo para la FACTURACIÓN correspondiente de la misma."** → El Excel de horas es el insumo de facturación, no solo seguimiento. +2. **(9:12 am) "johann adicional, ¿pasaste la propuesta con lo adicional de JIRA que no estaba contemplado?"** → Johann (10:58 am): **"Aún no la comparto, te la paso a la brevedad."** ⚠️ Es el compromiso que viene arrastrándose desde el 22-jul ([#57](REGISTRO.md)). +3. **(9:27 am)** Sobre Azure: Johann preguntó si el acceso lo iba a entregar Noé o Pedro → Erika: **"Sip"** + *"deja pregunto"* (11:01 am). Johann pidió contexto de qué se requiere específicamente de Azure (11:19 am). + +**Lecturas clave:** +> - **El Excel de horas es documento de facturación** (dicho por Erika, 28-jul 8:36 am). Cambia su naturaleza: ya no es reporte de avance, es sustento de cobro. Refuerza que las 41.58 h estén validadas y trazables. +> - **Erika creía la capa de escritura al 100%** y Johann la corrigió a pendiente. Buena decisión: si se hubiera dejado al 100%, la definición del proceso habría reabierto una actividad cerrada. Valida el criterio de reportar 40% y no más. +> - **Sin herramienta de gestión para el proyecto** (licencia en revisión; Erika evalúa una alternativa a Jira para ese fin). **No afecta la integración técnica** —esa va contra la instancia de TI de Pedro, ya disponible—, pero sí significa que **el Excel de horas de Johann es el registro oficial de seguimiento** y el insumo de facturación. Mantenerlo trazable y al día no es opcional. +> - **La propuesta ajustada por Jira sigue sin enviarse** (comprometida el 22-jul, re-preguntada el 28-jul). Es el pendiente comercial más viejo del hilo y ahora Erika lo pide por segunda vez. +> - **La sesión del flujo de facturación no está agendada:** Balam la revisa internamente primero (Ara de viaje). El desbloqueo de B7 se corre de fecha. + +**Pendientes que deja el hilo:** +- [ ] ⚠️🔥 Johann — **enviar la propuesta/adenda ajustada por la integración Jira→BIND** (comprometida 22-jul, re-preguntada 28-jul 9:12 am). Estimación ya comunicada: ~10 h ([#51](REGISTRO.md)). +- [ ] Johann — **enviar el Excel de horas de las etapas siguientes** (2, 3) que Erika pidió el 27-jul 6:46 pm ("las ya completas más que nada para ver cuántas son"). +- [ ] Balam/Erika — **avisar fecha de la sesión del flujo de facturación** tras su revisión interna. Desbloquea B7. +- [ ] Balam/Erika — **definir la herramienta de gestión del proyecto** (licencia en revisión). Mientras no exista, el Excel de Johann es el registro oficial. +- [ ] Balam/Pedro/Noé — **entregar el acceso a Azure**; Erika iba a preguntar (28-jul 11:01 am). Johann pidió el contexto de lo que se requiere. + +--- + ## Resumen ejecutivo del hilo (para contexto rápido) ### Datos duros confirmados por Balam diff --git a/planeacion/Avance-Balam-2026-07-27.xlsx b/planeacion/Avance-Balam-2026-07-27.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1eda2781a127550e52e76c67e9eefd148a79b8ed GIT binary patch literal 7440 zcmZ`;WmFtnvmGD=4I12?;O_437TjHf27&|+2@*8O;1b*!+}$NGz~D}h!5#9*z3W@| zyLs<*uRgu{$FA%^ab8&TN zHFI@k@o{ogj#WnKX2X#BrLec0U%w}AF8(8LZ^%!HmnY6L#WL&$S`bVIA_%`Wy`Z5I zw?>!#fv>T^gU#ub$lw)h8zmL2W#RfQZ=I5T6-Qu~nRrr!l3Hh^!HDrYs$Hm?xQQ9( z9*O$NT-5+qM(dc~WHp}-iufUWyjdU$c_JS+weK9c@4`@$&aXAcCJ7ezW2pFe9VJNMn<4&cfhb@cGM?tSsY^ zrX&)MVsR=17^>ga|6F$RsNQ3Yvx9$5QQZt{uJKw*GB_~cRf&s!;osh``BpK zV1I;;r`%t#|Bg91-+_%H%?D<}7? zkBlJm%s4dE@Ru@{p{qrXESAXn zZI~R+W7JFPq(x=3UK!4e@WbpIaq)n_v}tN9mO;RW5CeypWa)RPvP#fgrm5)j zSY=(xL19OT2S;Yb?UGwjAYYm9Ohc<(P^?T|*I>CmYY#;fVkI(zrboXpZ<&u8Ot~GQ z5CLENOmV@&ML$Gk2EAtz3ZC*I;sPFV2^T^5oxoEbJhl(v^Pxo{;-HxR)$D!eA_B6j z7NC9__a1%>mdx##7gj?3tW+)efGZc?VOeUyE}u$e{3Flsm$H;)Uy5;fu%M1PvPl>* zN(J))D%Z9gDPVw;ab(^mW&EQ-jdv2%M%NS zHpO|5v27Kw8hX_I6S?6aqG`FujG_kODYG*#O5#P>q(Y-KVu+oF6($ld=s}~g7VR8Y z{GhT&4P!4(f%%4uLPnq(gDjSRXCN78J^!+b8bdI#mtEt88CcMSB;gvWXttN4*;G%If@M zJ4UT}rtW(aDzY}c|X|MwF#s?kl<}cvTk|Xa?=JzXl^_d1?VD~_6oW8fp z;R&}HQq4RgiYW|*pBX(bjhVQQRR0+{dM`C=2iGqB5G3`Bl~#o_XmV)xS-U0I(YgY<`D2Pk%WlMNt|%0D`YP+xOau-{ zeoohknS|;0p{+L4JQGZ}5hX=fZt{VgWKA?mnUKS({f6gNl>w@AnXAQy?gETxq2leiX+KE&aE_)1bgm-d%INY{-1Z!?fgb<=UkH3rkkRWQS8YJ#!nYB5%l)EJc6v{F5c(5dy=NlQjoZt(E~e6e8K>1$N=vhMFi^&k!cwZv9=XY} zSdS7(Q>|CuxMkTvI`o|lheDR{@Q@sJntDtumKK(@RK;=JCs6gKKwn6u$8GLd$eiWt z1R9Z?C)EdfGx5ugKB~9oPX-P~)^b!^QOIamcow^JZJGC(Nb*!qIX8toA|bw*E`f4{ z0Xf98^LB!!#+Pp+p*y<~lR_NY?xC}qqu)sdNf7EHJJuvrzgAbfLp+0Cq_uBQt@C+h zhRsoObO>g1P4Ri*YCK3}Hoy|RT;yV1K^aFLLg6NU7&OWGAUX4WY@)AaRC9xjMhH7h zv+GGw@{z;qC0b}BIns46wVplAVo;jEJPyjqLC<)prL|V*wUlv&JXux<+`rddJ3eZh zkigQ0Nr#wSTkp{gOSpO~yYey@yT{Q)E6T%i+Jz#XHbcIbiE5u_Cd~`0nM0iF@5}uk zIggL@CY?^ zX}vENwH+^GOh;loA-IQ3J!rh&T)i8A9=UBdjeYFs(T27eUV;rTYmrL*vzJxB&(*3$ zise&3$Occ|sDwbxs~dyFT*Y3Ze^?0Z=(|nbz30_l+QDfeqrApHDKi;yHf{yUL(%Hr z59X)`1n>}}h4ZrEsE?{8O!8==&mE!%e10U*{^%p!)EurC1xR8mmXP>%>t-gBwvYoT zBgdGCKQYNyh!KC4C!9_^5M&dg&;RoN-OWAF-&I07+(A0rOZvDexskdmShw4@Q5-}- z@^MN^eDio6N?<4<<-?*PWhur|;(r6H3FUzw=02 zCJ~SNK0{ygb-vk4nzUe2Vn(l%QM(ZAeio&8Hd?|_-jZ8~{*}925`qUIb}Cq0E^6*j zt@l$X8M#>2a>(ZFnT687WUI17Rh)JS~>p(u{f6mt1klY{)VS6kCxnuS|vP1tdx>?w+a^rm$= z^`Elu+|LY${3^q}{jMt{4Y03?oq)o=_hnE!PS#u%PR|tMxpMYeZ|a*EA*E}X%C55P z_|J^wLe!Wvt0%~ExnCU!6REb4^G&~-!cY9LOf|ly#b~*AZQ^;%t1Ff?NVp|-nl0?! zMoU}CP6*6t8w%$FfEZzN(@IX zEhb*fl^LFj;-d_CLk#Np#LH!~UE0;xC5gG;p^}y=2a}mL36!!ftm{A$_9zC&dvs|f za6`cTQCIYWkii807Y632O+3QBG9+8H4J_$w%#GYsvPmB}cQJE=y|!rzKW?IK1tacrb#Z+Y>)h$+8`0%`5`#WiMLn2UQ;R^X1DSw6_5RL=$Pt^ zE&YsWU#<%69_tDqHL58d6p-!@i{BPcsM`4ApT0E%HOdQ*u@HKLEz?LA@%Uus|ZHI~YTJv#GxYZgq1k0;2AaqlUm*<}?XZ^~EiQwl>|(qayV3Vt#jn-0Acl zB{OpM&p-R}14nfZ)%V_hY^d0O^e)?fyr%8kPRsm^VZJmPPnP~d5@CA8{D4T~;J~7Q zr-|w(#Cbd@c`Nk;6@@xD&e%8zFTsBs%x((5&$G89iAT5}9e0?Dn^yI?u%J9Z(4mx< zZ%GH+Vo{(9%48zR>e(XE)p__jRdUs)7Cm2GX1^IZl(>Y1yo5Q{OisGU~$9@8&aCN(HVi>^4=VLm*}I5fdVN#sl*mmLM5zA4SGj#*g!y>^y`V?zO>= z0i!EaGkMdbsc5Y1%X>VGL~zy~y#CYkLBstGJjaqU^eOv&+EjksGm14tsuV2)Khs+p z_nD{LOcufJ9Y&X*d0R96dKA9sE*&~0&DwxMe^I`ZZ-Na+5%wB2`vS*d!FHc3ov|`E z>bzP=W)c@luPg@s7>3b&qp>2SVvaHWMZ%orB!)!B=Q}J`Uc$1h@hSzklm6}}r_l{QXzXgKjx9iS%&jJC?7J?o*7ncZTKBH59!m$dY zQ{bTqmXi69={R4TW!4i{_=_5!X=>$?LwN3>fmPltn|_{r^>R?KzX5w8P?=)bS3yT# zx1-6qO|P1=ykjsbDP3Yq1E;v6L$2QAK%tte6h;ftd+U9UL4GT>n^wi=w>b_r6ySnP ztk_1k#E}|@Q!=?3ELkgkwq0f%&G`J_2^?PFOz>x?8KL0tu-6*=zJ16%G$M6BLW}a+d*e$K|A=qO6z=Leq?9DQXQMIna44- z>+|OepKwrZZS>q286>ftq3$r)!haUAIlF>V&bmt?y)P{J3%E z-mH9aK8KvhoW(X$ivntVln@$8&?X0g}n(nRgFUwRoAfBKWvaArd}EukkL^pnNaOY1trg_Tz`rzbayd5 zk|vQwq3z`*zs>Z9;C{+eKIVcz$OsM{(UcmNY4CE}9BtExTz}X&G~U-;P#PC)xM+x$ z*C!V={jy=^zAw=m=iLcNfWn&|J}EEA@>-z_T&ZU*)2Zldo8PyrjntSbZ>V_T%kHD? zmgR4VS{9py8C7X;N@wsEa+zG{leeWmP^Y4UzVgRyJ(N!WOmafq_PZl>u7IAgO{?rQ zCJ-#8kACHbth5c)(LG{Yb}y>3yqPh6>QOnpiGjQKIqxJz&+8c}v+AfMZ1j;?7Rl9> zf7sGIINu}r{X{sD4E;s8eL(hJr{%7@z{=BlBg9Y5CUfH&{ba}O zX>HbY^=D_SzUCS4gC4Db_xOjgupKKu(8k;T;VvQx5?KKtiq{|%lg{FOGwz+IOGf%siVDcBxgcIW2vm_yW@>el}4r)PlrCSp_?cPzu~B z>S_kLs>U#ihlK?;r=ZSs2jOrkfW4psA;FA)`v7Wy9m zup_WKf@`bC2=>D18kwX}89HE85}HpGZ?rL&xSo;^nm;IW+(nu{#T>&LDA zut(Wk$JJ05T0?g+l0gAost+~e&{1~-O^-1V50&fnsV*Syt(%~nCH^Fa5TkHpP28f? zb~n~8$Z+bl+vhbS@1~+gZzyWg27)&Evd<|8}X@;Ny z1(z!fCTq#acQYzGFJ7qTMmg9slDI6&uQHYN#lSXz)=sH>^8$pL*HR#I;-tKo;*10Q zeYYAp2etbT3n_ip)%vUzczAdP{AMMh*;*;M8Ot(BBlK4f2cTK+@@AmBXy=0HI&Y6H zB??ef{1N@%^FmFUo?G@jA2-i)^IV30OVxj`!T+9}zt&^@*EZx3F^o`??M4LGS+S^W z9lPn5CTo+k*w9$Wt0@rrltkETyRziejdZgjpImhzA6Z{SYFY>4Bn{38A^4i^UY8GHBqTmPstGP)mA2fCzxuA5ZY?-^6pR{Vm5ENV+(CSUG!`XuWr}ayRl?3RC?G@`%MalJ?(|~T*VGp zI&r+#;3YOHrsDac+NRos?XP8FqwQ@CHzW_CHus9S(EBfjm+aKeT6FPbF!NscuN;QI z-QnvqOd&cjI1KhXj}op2hy(%@<=Nz!L&Ei0GOM{Edz&8GP7jpwO0{;0?-SmEibFaymXlH?5%9Y)QqSt-ZY7chEPFmF{A z4fnn-&KY=Ef-n2iuVR`4QQOBlAk2r)wiL2p_HY#tf!ZparOuCa-7WBQA*$@&9Z zAD$ZB0TK`?#)js8y)=}-8deU*RUo6oQR zKe{Y`8u(LQ`;UQ!k0gkH8TdcNwm+@>xo`WAl^_^otiP=Mvy1x^`X}H21AT@2FZTam zz(4r&AK=w9@Y(hM&euP|e 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. diff --git a/planeacion/Plan-actividades-avance-2026-07-27.xlsx b/planeacion/Plan-actividades-avance-2026-07-27.xlsx index 8f05802b11ea111924c90eb7e2633d4e7845a2c0..c13b907029a80a73a4cb39a68cf83eb1dbb3b609 100644 GIT binary patch literal 8881 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%0DIy^L^%2U;E%IU_3$nkS F{tp1Xw(S4_ diff --git a/planeacion/Seguimiento-horas.csv b/planeacion/Seguimiento-horas.csv index 5996b95..61480a0 100644 --- a/planeacion/Seguimiento-horas.csv +++ b/planeacion/Seguimiento-horas.csv @@ -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 diff --git a/planeacion/Seguimiento-horas.md b/planeacion/Seguimiento-horas.md index 35ce092..63c4de5 100644 --- a/planeacion/Seguimiento-horas.md +++ b/planeacion/Seguimiento-horas.md @@ -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. diff --git a/planeacion/generar_avance_2026_07_27.py b/planeacion/generar_avance_2026_07_27.py index c4dfcd2..ae42373 100644 --- a/planeacion/generar_avance_2026_07_27.py +++ b/planeacion/generar_avance_2026_07_27.py @@ -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.") diff --git a/planeacion/generar_resumen_erika_2026_07_27.py b/planeacion/generar_resumen_erika_2026_07_27.py new file mode 100644 index 0000000..6de4d17 --- /dev/null +++ b/planeacion/generar_resumen_erika_2026_07_27.py @@ -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")