bee2d02f50
- REGISTRO #55: validación del prototipo Etapa 0 (24-jul) APROBADA; único bloqueo = definir el flujo de facturación en Jira (sesión propuesta por Araceli para el martes 28) - REGISTRO #56: sesión de API de Jira con Pedro (27-jul) — token PAF a 1 año, bandeja FAC; + seguimiento por correo del mismo día con los límites de velocidad (65k puntos/h, burst/s, por-issue) y entrega del token por Google Drive - REGISTRO #57: hilo de WhatsApp con Erika (21-27 jul) — coordinación, envío del flujo por correo y reagenda 23→24 jul; 3 imágenes inferidas - Transcripciones y correo en fuentes/; guion de validación en planeacion/ - Avance-Etapa1-2026-07-27 (nota + mensaje para Erika) y Excel del corte del 27-jul (núcleo verificado; capa de escritura en pausa por definición de Balam) - Seguimiento-horas: sesiones del 24-jul (validación) y 27-jul (API Jira) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
147 lines
6.9 KiB
Python
147 lines
6.9 KiB
Python
"""Genera Plan-actividades-avance-2026-07-27.xlsx a partir del del 21-jul.
|
|
Aplica las horas y estatus reales al 27-jul: sesión de reglas (22-jul) y
|
|
validación del prototipo (24-jul, APROBADO) completadas; sesión de API de Jira
|
|
(27-jul) en curso; capa de escritura EN PAUSA a la espera de la definición del
|
|
flujo de facturación (sesión 28-jul con Arturo/Araceli).
|
|
Reutiliza el estilo/semáforo del archivo del 21-jul."""
|
|
import re
|
|
from datetime import date
|
|
import openpyxl
|
|
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side
|
|
|
|
SRC = "/Users/johann/Desktop/Proyectos personales/BALAM/planeacion/Plan-actividades-avance-2026-07-21.xlsx"
|
|
DST = "/Users/johann/Desktop/Proyectos personales/BALAM/planeacion/Plan-actividades-avance-2026-07-27.xlsx"
|
|
HOY = date(2026, 7, 27)
|
|
|
|
CAFE, CREMA, GRIS_B, AMARILLO = "331F0E", "FDF3D8", "D9D9D9", "F7BD0C"
|
|
V_FILL, V_FONT = "C6EFCE", "006100" # verde
|
|
A_FILL, A_FONT = "FFEB9C", "9C6500" # amarillo
|
|
R_FILL, R_FONT = "FFC7CE", "9C0006" # rojo
|
|
G_FILL, G_FONT = "F2F2F2", "595959" # gris
|
|
|
|
C_PCT, C_BLQ, C_EST, C_TRAB, C_STAT = 7, 8, 9, 10, 11
|
|
|
|
# Prefijo de la actividad -> overrides de datos (pct=%, trab=horas, comienzo/fin=fechas texto)
|
|
OVERRIDES = {
|
|
"Integracion de plataformas Balam": dict(pct=0.67, trab=40),
|
|
"Etapa 0": dict(pct=1.0, trab=23),
|
|
"Documento de hallazgos": dict(pct=1.0),
|
|
"Sesión de validación del prototipo": dict(pct=1.0, trab=1.05,
|
|
comienzo="vie 24/07/26", fin="vie 24/07/26"),
|
|
"Etapa 1": dict(pct=0.82, trab=17),
|
|
"Demostración semanal": dict(trab=1.75),
|
|
"Sesión de reglas y dudas": dict(pct=1.0, trab=0.80),
|
|
"Definición de alcance Jira": dict(pct=0.40, trab=0.20),
|
|
}
|
|
|
|
# Estatus a mano (gana sobre el semáforo automático): texto, fill, font, negrita
|
|
K_ESPECIAL = {
|
|
"Documento de hallazgos": ("✅ Completada", V_FILL, V_FONT, False),
|
|
"Sesión de validación del prototipo": ("✅ Validado (aprobado)", V_FILL, V_FONT, True),
|
|
"Demostración semanal": ("🟡 En curso (semanal)", A_FILL, A_FONT, False),
|
|
"Modelo de facturas": ("🟡 En curso · falta seeder", A_FILL, A_FONT, False),
|
|
"Capa de escritura controlada": ("🔴 En pausa · def. Balam 28-jul", R_FILL, R_FONT, True),
|
|
"Sesión de reglas y dudas": ("✅ Completada", V_FILL, V_FONT, False),
|
|
"Definición de alcance Jira": ("🟡 En curso · API Jira 27-jul", A_FILL, A_FONT, False),
|
|
"Configuración de infraestructura en Azure": ("🟡 Pendiente (Balam)", A_FILL, A_FONT, False),
|
|
"CI/CD": ("🔴 Pendiente · dep. Azure", R_FILL, R_FONT, True),
|
|
}
|
|
|
|
def fecha(celda):
|
|
m = re.search(r"(\d{2})/(\d{2})/(\d{2})", str(celda or ""))
|
|
return date(2000 + int(m.group(3)), int(m.group(2)), int(m.group(1))) if m else None
|
|
|
|
def pinta(celda, fill, font_color, bold=False):
|
|
celda.fill = PatternFill("solid", fgColor=fill)
|
|
celda.font = Font(color=font_color, bold=bold, size=10)
|
|
celda.alignment = Alignment(horizontal="center", vertical="center")
|
|
|
|
wb = openpyxl.load_workbook(SRC)
|
|
ws = wb.active
|
|
|
|
# 1) Aplica overrides de datos por prefijo de nombre
|
|
for row in range(2, ws.max_row + 1):
|
|
nombre = str(ws.cell(row=row, column=1).value or "").strip()
|
|
if not nombre:
|
|
continue
|
|
for prefijo, ov in OVERRIDES.items():
|
|
if nombre.startswith(prefijo):
|
|
if "pct" in ov: ws.cell(row=row, column=C_PCT, value=ov["pct"])
|
|
if "trab" in ov: ws.cell(row=row, column=C_TRAB, value=ov["trab"])
|
|
if "comienzo" in ov: ws.cell(row=row, column=3, value=ov["comienzo"])
|
|
if "fin" in ov: ws.cell(row=row, column=4, value=ov["fin"])
|
|
break
|
|
|
|
# 2) Recalcula el semáforo con HOY=27-jul (mismas reglas que el del 21-jul)
|
|
for row in range(2, ws.max_row + 1):
|
|
nombre = str(ws.cell(row=row, column=1).value or "").strip()
|
|
if not nombre or nombre.startswith("✅") or nombre.startswith("▬"):
|
|
continue
|
|
es_etapa = nombre.startswith("Etapa") or nombre.startswith("Integracion")
|
|
pct = ws.cell(row=row, column=C_PCT).value or 0
|
|
fin = fecha(ws.cell(row=row, column=4).value)
|
|
ini = fecha(ws.cell(row=row, column=3).value)
|
|
stat = ws.cell(row=row, column=C_STAT)
|
|
|
|
if es_etapa:
|
|
stat.value = ""
|
|
elif pct >= 1:
|
|
stat.value = "✅ Completada"; pinta(stat, V_FILL, V_FONT)
|
|
elif fin and fin < HOY:
|
|
stat.value = "🔴 Vencida"; pinta(stat, R_FILL, R_FONT, bold=True)
|
|
elif ini and ini <= HOY:
|
|
stat.value = "🟡 En curso"; pinta(stat, A_FILL, A_FONT)
|
|
elif pct > 0:
|
|
stat.value = "🟢 Adelantada"; pinta(stat, V_FILL, V_FONT)
|
|
else:
|
|
stat.value = "⚪ Próxima"; pinta(stat, G_FILL, G_FONT)
|
|
|
|
# semáforo en la celda de %
|
|
pcel = ws.cell(row=row, column=C_PCT)
|
|
if not es_etapa:
|
|
if pct >= 1: pinta(pcel, V_FILL, V_FONT, bold=True)
|
|
elif pct > 0: pinta(pcel, A_FILL, A_FONT, bold=True)
|
|
elif fin and fin < HOY: pinta(pcel, R_FILL, R_FONT, bold=True)
|
|
pcel.number_format = "0%"
|
|
ws.cell(row=row, column=C_TRAB).number_format = "0.0"
|
|
|
|
# 3) Overrides finos de estatus (bloqueos y dependencias)
|
|
for row in range(2, ws.max_row + 1):
|
|
nombre = str(ws.cell(row=row, column=1).value or "").strip()
|
|
for prefijo, (txt, fill, font, bold) in K_ESPECIAL.items():
|
|
if nombre.startswith(prefijo):
|
|
stat = ws.cell(row=row, column=C_STAT)
|
|
stat.value = txt
|
|
pinta(stat, fill, font, bold)
|
|
break
|
|
|
|
# 4) Encabezado de la columna de estatus y pie
|
|
ws.cell(row=1, column=C_STAT, value=f"Estatus (hoy {HOY.day}-jul)")
|
|
|
|
# 5) Reescribe leyenda/notas (borra las viejas de la línea de HOY del 21-jul)
|
|
for row in range(ws.max_row, 1, -1):
|
|
v = str(ws.cell(row=row, column=1).value or "")
|
|
if v.startswith("✅ Completada ·") or v.startswith("▬ La línea roja"):
|
|
for col in range(1, C_STAT + 1):
|
|
ws.cell(row=row, column=col).value = None
|
|
|
|
ley = ws.max_row + 2
|
|
notas = [
|
|
("✅ Completada · 🟡 En curso · 🔴 Vencida/Pendiente · ⚪ Próxima", G_FONT, True),
|
|
("Núcleo de la Etapa 1 construido y verificado contra producción: autenticación y roles, "
|
|
"bitácora, multi-tenant con RLS, cliente de BIND, sincronización de clientes/facturas/"
|
|
"cotizaciones, modelo de facturas con estados y cartera por moneda.", CAFE, False),
|
|
("🔴 La capa de escritura (cotización→factura) queda EN PAUSA a la espera de la definición "
|
|
"del flujo de facturación (sesión del martes 28-jul con Arturo y Araceli).", "9C0006", False),
|
|
("API de Jira: token recibido el 27-jul; la integración inicia una vez definido el flujo.", CAFE, False),
|
|
]
|
|
for i, (txt, color, bold) in enumerate(notas):
|
|
c = ws.cell(row=ley + i, column=1, value=txt)
|
|
c.font = Font(italic=True, size=9, color=color, bold=bold)
|
|
|
|
ws.freeze_panes = "A2"
|
|
ws.oddFooter.center.text = "Avance al 27-jul-2026 · Horas conforme al control local (pendiente conciliar con Jira)"
|
|
|
|
wb.save(DST)
|
|
print("OK ->", DST)
|