Prepara la Adenda 01 (integración Jira→BIND, 9–12 h) y el Excel de horas por etapa
Los dos pendientes que Erika re-preguntó el 28-jul: la adenda formaliza la generación automática de cotizaciones desde tickets FAC ($5,400–$7,200 + IVA, consistente con las ~10 h comunicadas el 21-jul) como solicitud de cambio conforme a la §10 de la propuesta v1.2; el Excel resume horas por etapa (E0 cerrada en 21.83 h, E1 en 19.75 h, E2/E3 con rangos contractuales) con importes para facturación. PDF con el mismo diseño del paquete v1.2. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,187 @@
|
||||
"""Genera Horas-etapas-Balam-2026-07-28.xlsx — resumen de horas POR ETAPA para Erika.
|
||||
|
||||
Pedido por Erika el 27-jul (6:46 pm: "las ya completas más que nada para ver
|
||||
cuántas son") y aclarado el 28-jul (8:36 am): el Excel es el insumo del conteo
|
||||
de horas de cada etapa "sobre todo para la FACTURACIÓN correspondiente".
|
||||
|
||||
Las horas trabajadas se leen del Excel interno (`Plan-actividades-avance-2026-07-27.xlsx`),
|
||||
que a su vez sale de `Seguimiento-horas.csv` — una sola fuente de datos, igual que
|
||||
`generar_resumen_erika_2026_07_27.py`. Los rangos estimados y montos son los
|
||||
contractuales de la propuesta v1.2 (§4) y de la Adenda 01 (Jira → BIND).
|
||||
"""
|
||||
import os
|
||||
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, "Horas-etapas-Balam-2026-07-28.xlsx")
|
||||
EMISION = date(2026, 7, 28) # fecha de emisión; horas al corte del lunes 27-jul
|
||||
TARIFA = 600 # MXN/h + IVA (propuesta v1.2 §3.3)
|
||||
|
||||
# Marca Balam
|
||||
CAFE, AMARILLO, CREMA = "331F0E", "F7BD0C", "FDF3D8"
|
||||
V_FILL, V_FONT = "C6EFCE", "006100" # verde
|
||||
A_FILL, A_FONT = "FFEB9C", "9C6500" # amarillo
|
||||
GRIS = "595959"
|
||||
BORDE = "D9D9D9"
|
||||
|
||||
thin = Side(style="thin", color=BORDE)
|
||||
box = Border(left=thin, right=thin, top=thin, bottom=thin)
|
||||
|
||||
# --- Horas trabajadas desde el Excel interno (única fuente) -------------------
|
||||
wsrc = openpyxl.load_workbook(SRC).active
|
||||
trab = {}
|
||||
for row in range(2, wsrc.max_row + 1):
|
||||
nombre = str(wsrc.cell(row=row, column=1).value or "").strip()
|
||||
if nombre.startswith(("Etapa 0", "Etapa 1", "Integracion")):
|
||||
clave = "TOTAL" if nombre.startswith("Integracion") else nombre.split(" ")[0] + nombre.split(" ")[1]
|
||||
trab[clave] = float(wsrc.cell(row=row, column=10).value or 0)
|
||||
|
||||
E0, E1, TOTAL = trab["Etapa0"], trab["Etapa1"], trab["TOTAL"]
|
||||
assert abs((E0 + E1) - TOTAL) < 0.01, f"Horas no cuadran: {E0} + {E1} != {TOTAL}"
|
||||
|
||||
# --- Filas del resumen --------------------------------------------------------
|
||||
# (etapa, estatus, kind_estatus, est_min, est_max, trabajadas o None)
|
||||
ETAPAS = [
|
||||
("Etapa 0 — Discovery, infraestructura y prototipo visual",
|
||||
"✅ Completada y validada (24-jul)", "ok", 18, 22, E0),
|
||||
("Etapa 1 — Plataforma base y sincronización con BIND",
|
||||
"🟡 En curso · 6 de 8 entregables terminados", "curso", 32, 39, E1),
|
||||
("Etapa 2 — Facturación (consulta y emisión), catálogo y multimoneda",
|
||||
"⚪ Próxima", "prox", 38, 46, None),
|
||||
("Etapa 3 — Cobranza, tablero, reportes y cierre",
|
||||
"⚪ Próxima", "prox", 24, 29, None),
|
||||
]
|
||||
ADENDA = ("Adicional — Integración Jira → BIND (Adenda 01)",
|
||||
"📋 En aprobación · no estaba en la propuesta original", "prox", 9, 12, None)
|
||||
|
||||
SUB_MIN = sum(e[3] for e in ETAPAS) # 112
|
||||
SUB_MAX = sum(e[4] for e in ETAPAS) # 136
|
||||
TOT_MIN, TOT_MAX = SUB_MIN + ADENDA[3], SUB_MAX + ADENDA[4] # 121, 148
|
||||
|
||||
|
||||
def dinero(h):
|
||||
return f"${h * TARIFA:,.0f}"
|
||||
|
||||
|
||||
def rango_dinero(lo, hi):
|
||||
return f"{dinero(lo)} – {dinero(hi)}"
|
||||
|
||||
|
||||
# --- Construcción -------------------------------------------------------------
|
||||
wb = openpyxl.Workbook()
|
||||
ws = wb.active
|
||||
ws.title = "Horas por etapa"
|
||||
|
||||
ws["A1"] = "Proyecto Balam · Plataforma de Automatización Financiera"
|
||||
ws["A1"].font = Font(bold=True, size=14, color=CAFE)
|
||||
ws["A2"] = ("Horas por etapa — emitido el 28-jul-2026 · horas trabajadas al corte "
|
||||
"del lunes 27-jul-2026 · tarifa $600 MXN/h + IVA")
|
||||
ws["A2"].font = Font(size=10, italic=True, color=GRIS)
|
||||
|
||||
ENC = ["Etapa", "Estatus", "Horas estimadas", "Horas trabajadas\n(al 27-jul)",
|
||||
"Importe estimado\n(MXN, antes de IVA)"]
|
||||
ANCHOS = [52, 34, 15, 15, 20]
|
||||
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", wrap_text=True)
|
||||
c.border = box
|
||||
ws.column_dimensions[get_column_letter(i)].width = ancho
|
||||
ws.row_dimensions[FILA_ENC].height = 28
|
||||
|
||||
|
||||
def fila(r, nombre, estatus, kind, est, trabajadas, importe, bold=False, fill=None):
|
||||
c = ws.cell(row=r, column=1, value=nombre)
|
||||
c.font = Font(bold=bold, size=10, color=CAFE)
|
||||
c.alignment = Alignment(vertical="center", wrap_text=True)
|
||||
|
||||
cs = ws.cell(row=r, column=2, value=estatus)
|
||||
cs.font = Font(size=9, color=GRIS)
|
||||
cs.alignment = Alignment(vertical="center", wrap_text=True)
|
||||
if kind == "ok":
|
||||
cs.font = Font(size=9, color=V_FONT); cs.fill = PatternFill("solid", fgColor=V_FILL)
|
||||
elif kind == "curso":
|
||||
cs.font = Font(size=9, color=A_FONT); cs.fill = PatternFill("solid", fgColor=A_FILL)
|
||||
|
||||
ce = ws.cell(row=r, column=3, value=est)
|
||||
ce.font = Font(bold=bold, size=10, color=CAFE)
|
||||
ce.alignment = Alignment(horizontal="center", vertical="center")
|
||||
|
||||
ct = ws.cell(row=r, column=4, value=trabajadas if trabajadas is not None else "—")
|
||||
if trabajadas is not None:
|
||||
ct.number_format = "0.00"
|
||||
ct.font = Font(bold=bold or trabajadas is not None, size=10, color=CAFE)
|
||||
ct.alignment = Alignment(horizontal="center", vertical="center")
|
||||
|
||||
ci = ws.cell(row=r, column=5, value=importe)
|
||||
ci.font = Font(bold=bold, size=10, color=CAFE)
|
||||
ci.alignment = Alignment(horizontal="right", vertical="center")
|
||||
|
||||
for col in range(1, 6):
|
||||
ws.cell(row=r, column=col).border = box
|
||||
if fill:
|
||||
ws.cell(row=r, column=col).fill = PatternFill("solid", fgColor=fill)
|
||||
ws.row_dimensions[r].height = 26
|
||||
|
||||
|
||||
r = FILA_ENC + 1
|
||||
for nombre, estatus, kind, lo, hi, t in ETAPAS:
|
||||
fila(r, nombre, estatus, kind, f"{lo} – {hi}", t, rango_dinero(lo, hi))
|
||||
r += 1
|
||||
|
||||
fila(r, "Subtotal — propuesta v1.2", "", "sub", f"{SUB_MIN} – {SUB_MAX}", TOTAL,
|
||||
rango_dinero(SUB_MIN, SUB_MAX), bold=True, fill=CREMA)
|
||||
r += 1
|
||||
|
||||
nombre, estatus, kind, lo, hi, t = ADENDA
|
||||
fila(r, nombre, estatus, kind, f"{lo} – {hi}", t, rango_dinero(lo, hi))
|
||||
r += 1
|
||||
|
||||
fila(r, "Total con Adenda 01", "", "tot", f"{TOT_MIN} – {TOT_MAX}", TOTAL,
|
||||
rango_dinero(TOT_MIN, TOT_MAX), bold=True, fill=CREMA)
|
||||
r += 2
|
||||
|
||||
# --- Notas --------------------------------------------------------------------
|
||||
notas = [
|
||||
f"Horas trabajadas al corte del lunes 27-jul-2026, del control de horas del proyecto "
|
||||
f"(mismas cifras del Excel de avance enviado el 27-jul): Etapa 0 {E0:.2f} h · "
|
||||
f"Etapa 1 {E1:.2f} h · total {TOTAL:.2f} h.",
|
||||
f"La Etapa 0 cerró en {E0:.2f} h, dentro del rango contractual de 18–22 h "
|
||||
f"(a $600/h: {dinero(E0)} antes de IVA).",
|
||||
"Referencia de facturación (propuesta v1.2, §3.3): la facturación inicial es de 30 h — "
|
||||
"$18,000 + IVA — y cubre la Etapa 0 completa más el inicio de la Etapa 1; se emite en "
|
||||
"cuanto se confirme el visto bueno. Los avances posteriores se facturan semanalmente "
|
||||
"(viernes) por horas efectivamente trabajadas, con pago a 30 días naturales.",
|
||||
"La integración Jira → BIND no estaba contemplada en la propuesta original; se "
|
||||
"formaliza en la Adenda 01 (compartida el 28-jul) y se ejecuta tras su aprobación "
|
||||
"por escrito.",
|
||||
"Los rangos de horas operan con tope por etapa: al aproximarse al máximo, el trabajo "
|
||||
"se detiene y se revisa el alcance antes de continuar.",
|
||||
]
|
||||
for txt in notas:
|
||||
c = ws.cell(row=r, column=1, value=txt)
|
||||
c.font = Font(italic=True, size=9, color=CAFE)
|
||||
c.alignment = Alignment(wrap_text=True, vertical="top")
|
||||
ws.merge_cells(start_row=r, start_column=1, end_row=r, end_column=5)
|
||||
ws.row_dimensions[r].height = 28 if len(txt) > 120 else 16
|
||||
r += 1
|
||||
|
||||
ws.freeze_panes = f"A{FILA_ENC + 1}"
|
||||
ws.sheet_view.showGridLines = False
|
||||
ws.print_area = f"A1:E{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" E0 {E0:.2f} h · E1 {E1:.2f} h · total {TOTAL:.2f} h · "
|
||||
f"v1.2 {SUB_MIN}–{SUB_MAX} h · con adenda {TOT_MIN}–{TOT_MAX} h")
|
||||
@@ -0,0 +1,66 @@
|
||||
# Adenda 01 — Integración Jira → BIND
|
||||
## Generación automática de cotizaciones desde los tickets de facturación
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Preparada para** | Noe Rocha (CTO) · Araceli Sánchez Jiménez (CEO/Operaciones) · Erika Chávez (PM) · Pedro Alberto Ayala Elizondo (Contacto técnico) |
|
||||
| **Preparada por** | Johann Velazquez — Consultor de Software · Monterrey, N.L. |
|
||||
| **Fecha** | 28 de julio de 2026 |
|
||||
| **Documento** | Adenda 01 a la Propuesta Comercial v1.2 — solicitud de cambio conforme a la §10 (control de cambios) |
|
||||
| **Vigencia** | 30 días naturales a partir de la fecha de emisión |
|
||||
|
||||
---
|
||||
|
||||
## 1. Antecedente
|
||||
|
||||
La propuesta v1.2 dejó Jira explícitamente **fuera del alcance** del MVP (§1.3 y Anexo A.4), conforme a la información disponible al momento de cotizar. Durante el Discovery y las sesiones de julio, la dirección confirmó que el proceso interno evolucionó: **hoy todo el flujo de facturación de Balam nace y se gobierna en Jira** — *"lo que no está en Jira no se procesa"* — con una bandeja dedicada (**Facturación**, llave `FAC-`) y un flujo de estatus formal que culmina en "resuelto".
|
||||
|
||||
En la sesión del 22 de julio el CTO planteó incorporar esta conectividad como ajuste de alcance; en la validación del prototipo del 24 de julio se ratificó, y en la sesión técnica del 27 de julio con Pedro Ayala quedó confirmada la viabilidad: la API de Jira cubre **lectura y escritura** de tickets, se entregó el token de integración (**"PAF"**, vigente al 27-jul-2027) y se documentaron los límites de consumo del lado de Atlassian. La estimación preliminar (~10 h) se comunicó a la PM el 21 de julio; esta adenda la formaliza por escrito, como lo prevé el control de cambios de la propuesta.
|
||||
|
||||
## 2. Alcance del cambio
|
||||
|
||||
La integración agrega a la primera etapa las siguientes capacidades:
|
||||
|
||||
1. **Conexión con la API de Jira** mediante el token PAF y lectura de los tickets de la bandeja **Facturación (`FAC-`)**, con consumo autorregulado conforme a los límites de velocidad documentados por Atlassian.
|
||||
2. **Generación automática de la cotización en BIND** cuando un ticket alcanza el estatus disparador que Balam defina (candidato natural: la entrada del ticket al proceso de facturación, previo a "resuelto"), a través de la misma **capa de escritura controlada** del MVP.
|
||||
3. **Trazabilidad ticket ↔ cotización ↔ prefactura/factura**, visible en la plataforma y registrada en la bitácora de auditoría. Los tickets leídos alimentan además la vista *"qué necesita atención"* del tablero.
|
||||
4. **Pruebas controladas:** scripts de consulta y de creación/edición sobre un registro de prueba, y una **prueba observada** con el equipo de Balam antes de habilitar la generación automática en operación (según lo acordado en la sesión del 27 de julio).
|
||||
|
||||
> **El control fiscal no cambia.** La integración crea **cotizaciones, nunca facturas**: se mantiene la cadena acordada — cotización → prefactura → **aprobación humana** → timbrado por el PAC de BIND — con modo de simulación (*dry-run*), feature flag y registro en bitácora. No existe timbrado automático.
|
||||
|
||||
## 3. Qué no incluye
|
||||
|
||||
- **Alta automática de clientes en BIND.** Si el cliente del ticket no existe en BIND, la plataforma lo **detecta y lo notifica**; darlo de alta automáticamente es una decisión de proceso aún abierta y, de aprobarse, se estima por separado.
|
||||
- **Tickets con múltiples facturas.** El supuesto de esta adenda es *un ticket → una cotización*. El manejo del caso masivo (un ticket con un listado de decenas de facturas) se define junto con Balam; si requiere desarrollo adicional, se estima por separado.
|
||||
- **Otros usos de Jira** — reporteo de horas de consultores, tableros sobre otras bandejas o el espacio comercial para pipeline de ventas — así como los módulos diferidos del Anexo B, permanecen fuera del alcance.
|
||||
|
||||
## 4. Estimación e inversión
|
||||
|
||||
| Concepto | Horas | Inversión (MXN) |
|
||||
|---|---|---|
|
||||
| Integración Jira → BIND: lectura de la bandeja FAC, disparador por estatus, cotización automática, trazabilidad y pruebas | 9 – 12 | $5,400 – $7,200 |
|
||||
|
||||
- **Tarifa vigente:** $600 MXN/h + IVA (§3.3). El rango es consistente con la estimación de ~10 h comunicada el 21 de julio y opera bajo el mismo esquema de horas reales **con tope**: al aproximarse al máximo, el trabajo se detiene y se revisa con Balam.
|
||||
- **Facturación:** como el resto de los avances — semanal (viernes) por horas efectivamente trabajadas, con pago a 30 días naturales.
|
||||
- **Efecto en el total de la primera etapa:** de 112 – 136 h ($67,200 – $81,600) pasa a **121 – 148 h ($72,600 – $88,800)**, antes de IVA.
|
||||
|
||||
## 5. Supuestos y dependencias
|
||||
|
||||
1. **Definición del flujo de facturación** por parte de Balam (actualmente en revisión interna; sesión por agendar): de ella salen el estatus disparador y las reglas de prefactura. La implementación de esta adenda inicia una vez cerrada esa definición.
|
||||
2. **Token PAF vigente** con visibilidad de la bandeja FAC (entregado el 27 de julio) y un interlocutor técnico (Pedro) para dudas de Jira, con respuesta en menos de 48 horas.
|
||||
3. **Diagrama del flujo Jira de facturación** en tamaño legible (comprometido por Balam en la sesión del 22 de julio).
|
||||
4. **Bandeja FAC como fuente.** FAC opera como bandeja "padre" del proceso de facturación; si las pruebas muestran que algún disparador nace en otra bandeja sin reflejarse en FAC, el ajuste se revisa en conjunto.
|
||||
5. **Sin ambiente de pruebas de BIND:** toda prueba de escritura será acotada, acordada previamente y observada, como se convino con el CTO.
|
||||
|
||||
## 6. Condiciones
|
||||
|
||||
Todo lo no modificado por esta adenda — condiciones comerciales (§3.3), garantía de 45 días, propiedad del código, metodología de desarrollo y supuestos generales — permanece en los términos de la propuesta v1.2 y del contrato de servicios firmado. La mención de Jira como "fuera de alcance" (§1.3 y Anexo A) queda sustituida por el alcance acotado que esta adenda define.
|
||||
|
||||
## 7. Aceptación
|
||||
|
||||
Conforme a la §10 de la propuesta (control de cambios), esta adenda se ejecuta tras su **aprobación por escrito**; basta la confirmación por correo electrónico. No requiere un nuevo contrato.
|
||||
|
||||
---
|
||||
|
||||
**Johann Velazquez** · Consultor de Software
|
||||
Monterrey, Nuevo León
|
||||
Binary file not shown.
@@ -0,0 +1,377 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Adenda 01 — Integración Jira → BIND · Balam</title>
|
||||
<style>
|
||||
@font-face{ font-family:"Caladea"; font-style:normal; font-weight:400; src:url("fonts/Caladea-Regular.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Caladea"; font-style:normal; font-weight:700; src:url("fonts/Caladea-Bold.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Caladea"; font-style:italic; font-weight:400; src:url("fonts/Caladea-Italic.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Caladea"; font-style:italic; font-weight:700; src:url("fonts/Caladea-BoldItalic.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Carlito"; font-style:normal; font-weight:400; src:url("fonts/Carlito-Regular.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Carlito"; font-style:normal; font-weight:700; src:url("fonts/Carlito-Bold.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Carlito"; font-style:italic; font-weight:400; src:url("fonts/Carlito-Italic.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"Carlito"; font-style:italic; font-weight:700; src:url("fonts/Carlito-BoldItalic.ttf") format("truetype"); }
|
||||
@font-face{ font-family:"DejaVu Sans Mono"; font-style:normal; font-weight:400; src:url("fonts/DejaVuSansMono.ttf") format("truetype"); }
|
||||
|
||||
:root{
|
||||
--ink:#1C2B39; /* deep slate navy — headings, dark fields */
|
||||
--ink-2:#3C4A57; /* body text */
|
||||
--muted:#6E7A86; /* meta, captions */
|
||||
--hair:#E4E8EC; /* hairlines */
|
||||
--hair-2:#C9D1D8; /* stronger hairlines */
|
||||
--accent:#BC5B3E; /* terracotta accent */
|
||||
--accent-d:#9A4530; /* darker terracotta for small text */
|
||||
--accent-tint:#FBF1EC;/* pale terracotta wash */
|
||||
--cream:#F8F5F0; /* warm panel */
|
||||
--paper:#FFFFFF;
|
||||
--ok:#2E7D5B;
|
||||
--warn:#C0892E;
|
||||
--no:#B23A48;
|
||||
--serif:'Caladea','Bitstream Charter','DejaVu Serif',Georgia,serif;
|
||||
--sans:'Carlito','DejaVu Sans','Noto Sans',system-ui,sans-serif;
|
||||
--mono:'DejaVu Sans Mono','Liberation Mono',monospace;
|
||||
}
|
||||
|
||||
*{ -webkit-print-color-adjust:exact; print-color-adjust:exact; box-sizing:border-box; }
|
||||
html,body{ margin:0; padding:0; }
|
||||
body{
|
||||
font-family:var(--sans);
|
||||
font-size:10.25pt;
|
||||
line-height:1.55;
|
||||
color:var(--ink-2);
|
||||
background:var(--paper);
|
||||
-webkit-font-smoothing:antialiased;
|
||||
}
|
||||
|
||||
@page{ size:Letter; margin:15mm 16mm 18mm 16mm; }
|
||||
@page :first{ margin:0; }
|
||||
|
||||
p{ margin:6pt 0; }
|
||||
strong,b{ font-weight:700; color:var(--ink); }
|
||||
em,i{ font-style:italic; }
|
||||
a{ color:var(--accent-d); text-decoration:none; }
|
||||
|
||||
code{
|
||||
font-family:var(--mono); font-size:8.6pt;
|
||||
background:var(--cream); border:.5pt solid var(--hair);
|
||||
border-radius:3pt; padding:.5pt 3pt; color:var(--ink);
|
||||
}
|
||||
|
||||
ul,ol{ margin:6pt 0; padding-left:17pt; }
|
||||
li{ margin:3pt 0; line-height:1.5; color:var(--ink-2); padding-left:2pt; }
|
||||
li::marker{ color:var(--accent); }
|
||||
ol li::marker{ color:var(--accent-d); font-weight:700; }
|
||||
|
||||
/* ---------------- COVER ---------------- */
|
||||
.cover{
|
||||
width:216mm; min-height:279mm;
|
||||
background:var(--ink);
|
||||
color:#EAEDF0;
|
||||
padding:30mm 26mm 24mm;
|
||||
display:flex; flex-direction:column;
|
||||
position:relative; overflow:hidden;
|
||||
}
|
||||
.cover::after{ /* faint geometric corner motif */
|
||||
content:""; position:absolute; right:-60mm; top:-60mm;
|
||||
width:150mm; height:150mm; border-radius:50%;
|
||||
background:radial-gradient(circle at center, rgba(188,91,62,.18), rgba(188,91,62,0) 70%);
|
||||
}
|
||||
.cover .top{ position:relative; z-index:2; }
|
||||
.cover .rule{ width:46pt; height:3pt; background:var(--accent); margin-bottom:14pt; }
|
||||
.cover .eyebrow{
|
||||
font-family:var(--sans); font-size:10pt; font-weight:700;
|
||||
letter-spacing:.34em; text-transform:uppercase; color:#D89A82;
|
||||
}
|
||||
.cover .mid{ position:relative; z-index:2; margin-top:auto; margin-bottom:auto; padding:18mm 0; }
|
||||
.cover h1{
|
||||
font-family:var(--serif); font-weight:700;
|
||||
font-size:37pt; line-height:1.06; letter-spacing:-.01em;
|
||||
margin:0; color:#FFFFFF; max-width:150mm;
|
||||
}
|
||||
.cover .client{
|
||||
margin-top:16pt; font-family:var(--sans); font-size:12.5pt; color:#C9D1D8;
|
||||
}
|
||||
.cover .client b{ color:var(--accent); font-weight:700; }
|
||||
.cover .meta{ position:relative; z-index:2; }
|
||||
.cover .meta-grid{
|
||||
display:grid; grid-template-columns:34mm 1fr;
|
||||
gap:7pt 14pt; border-top:.6pt solid rgba(255,255,255,.18);
|
||||
padding-top:14pt;
|
||||
}
|
||||
.cover .meta-grid dt{
|
||||
font-family:var(--sans); font-size:7.5pt; font-weight:700;
|
||||
letter-spacing:.12em; text-transform:uppercase; color:#8FA0AD; padding-top:1.5pt;
|
||||
}
|
||||
.cover .meta-grid dd{ margin:0; font-size:9.5pt; color:#DDE3E8; line-height:1.45; }
|
||||
.cover .meta-grid dd .who{ display:block; }
|
||||
.cover .meta-grid dd .who b{ color:#FFFFFF; font-weight:700; }
|
||||
.cover .meta-grid dd .who span{ color:#9FB0BC; }
|
||||
.cover .conf{
|
||||
position:relative; z-index:2; margin-top:18pt;
|
||||
display:flex; justify-content:space-between; align-items:baseline;
|
||||
font-family:var(--sans); font-size:8pt; letter-spacing:.06em;
|
||||
text-transform:uppercase; color:#7C8B97;
|
||||
border-top:.6pt solid rgba(255,255,255,.12); padding-top:10pt;
|
||||
}
|
||||
.cover .conf .badge{ color:var(--accent); font-weight:700; }
|
||||
|
||||
/* ---------------- TOC ---------------- */
|
||||
.toc{ break-before:page; padding-top:6mm; }
|
||||
.toc h2{
|
||||
font-family:var(--serif); font-size:20pt; color:var(--ink);
|
||||
margin:0 0 2pt; font-weight:700;
|
||||
}
|
||||
.toc .kick{
|
||||
font-family:var(--sans); font-size:8pt; font-weight:700; letter-spacing:.2em;
|
||||
text-transform:uppercase; color:var(--accent-d); margin-bottom:14pt;
|
||||
}
|
||||
.toc .rule{ width:46pt; height:2.5pt; background:var(--accent); margin:6pt 0 16pt; }
|
||||
.toc-row{ display:flex; align-items:baseline; gap:9pt; padding:6.5pt 0; border-bottom:.5pt solid var(--hair); }
|
||||
.toc-row .n{ font-family:var(--serif); font-weight:700; font-size:11pt; color:var(--accent); min-width:24pt; }
|
||||
.toc-row .t{ font-family:var(--serif); font-size:11.5pt; color:var(--ink); }
|
||||
.toc-row.section .t{ font-weight:700; }
|
||||
.toc-row .dots{ flex:1; border-bottom:.6pt dotted var(--hair-2); transform:translateY(-3pt); }
|
||||
.toc-row .pg{ font-family:var(--sans); font-size:9.5pt; color:var(--muted); font-variant-numeric:tabular-nums; min-width:14pt; text-align:right; }
|
||||
.toc-row.annex{ margin-top:2pt; }
|
||||
.toc-row.annex .n,.toc-row.annex .t{ color:var(--ink); }
|
||||
.toc-row.annex .n{ color:var(--accent); }
|
||||
|
||||
/* ---------------- CONTENT ---------------- */
|
||||
.content{ break-before:page; }
|
||||
|
||||
.sec{ margin-top:20pt; }
|
||||
.sec:first-child{ margin-top:0; }
|
||||
.sec-head{
|
||||
display:flex; align-items:baseline; gap:14pt;
|
||||
margin:0 0 9pt; padding-bottom:8pt;
|
||||
border-bottom:1.2pt solid var(--ink); break-after:avoid;
|
||||
}
|
||||
.sec-head.no-num{ gap:0; }
|
||||
.sec-num{
|
||||
font-family:var(--serif); font-size:29pt; font-weight:700;
|
||||
color:var(--accent); line-height:.85; letter-spacing:-.02em; min-width:38pt;
|
||||
}
|
||||
.sec-head h2{
|
||||
font-family:var(--serif); font-size:18pt; font-weight:700;
|
||||
color:var(--ink); line-height:1.12; margin:0;
|
||||
}
|
||||
.sec-head .kick{
|
||||
display:block; font-family:var(--sans); font-size:7.5pt; font-weight:700;
|
||||
letter-spacing:.16em; text-transform:uppercase; color:var(--accent-d); margin-bottom:3pt;
|
||||
}
|
||||
|
||||
h3{ font-family:var(--sans); font-size:11.5pt; font-weight:700; color:var(--ink); margin:15pt 0 5pt; break-after:avoid; }
|
||||
h3 .sn{ color:var(--accent-d); font-weight:700; margin-right:7pt; }
|
||||
h4{ font-family:var(--sans); font-size:10pt; font-weight:700; color:var(--ink); margin:12pt 0 4pt; break-after:avoid; }
|
||||
|
||||
.mini-label{
|
||||
font-family:var(--sans); font-size:8pt; font-weight:700; letter-spacing:.1em;
|
||||
text-transform:uppercase; color:var(--accent-d); margin:10pt 0 4pt;
|
||||
}
|
||||
.lede{ font-size:11pt; line-height:1.62; color:var(--ink); }
|
||||
|
||||
/* drop cap for executive summary */
|
||||
.dropcap > p:first-of-type::first-letter{
|
||||
font-family:var(--serif); font-weight:700; color:var(--accent);
|
||||
font-size:38pt; line-height:.82; float:left; padding:2pt 7pt 0 0;
|
||||
}
|
||||
|
||||
/* ETAPA block */
|
||||
.etapa{ margin:16pt 0 5pt; padding-top:9pt; border-top:.8pt solid var(--hair-2); break-after:avoid; }
|
||||
.etapa .et-t{ font-family:var(--serif); font-size:13pt; font-weight:700; color:var(--ink); line-height:1.2; }
|
||||
.etapa .et-meta{ font-family:var(--sans); font-size:8.5pt; font-weight:700; letter-spacing:.05em; text-transform:uppercase; color:var(--accent-d); margin-top:3pt; }
|
||||
|
||||
/* ---------------- TABLES ---------------- */
|
||||
table{ width:100%; border-collapse:collapse; margin:10pt 0; font-size:9.2pt; }
|
||||
thead{ display:table-header-group; }
|
||||
th{
|
||||
text-align:left; font-family:var(--sans); font-weight:700; color:var(--ink);
|
||||
font-size:7.8pt; letter-spacing:.045em; text-transform:uppercase;
|
||||
padding:7pt 9pt; border-bottom:1.4pt solid var(--ink); vertical-align:bottom;
|
||||
}
|
||||
td{ padding:6.5pt 9pt; border-bottom:.6pt solid var(--hair); vertical-align:top; color:var(--ink-2); line-height:1.42; }
|
||||
tr{ break-inside:avoid; }
|
||||
td.k{ color:var(--ink); font-weight:600; }
|
||||
.num,th.num{ text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
|
||||
.ctr,th.ctr{ text-align:center; }
|
||||
tr.total td{ font-weight:700; color:var(--ink); background:var(--cream); border-top:1.2pt solid var(--ink); border-bottom:1.2pt solid var(--ink); }
|
||||
tr.sub-total td{ font-weight:700; color:var(--ink); background:var(--accent-tint); border-top:1pt solid var(--accent); }
|
||||
.cov{ font-size:11pt; text-align:center; line-height:1; }
|
||||
table.compact td,table.compact th{ padding:5.5pt 8pt; }
|
||||
|
||||
/* ---------------- CALLOUTS ---------------- */
|
||||
.callout{
|
||||
break-inside:avoid; background:var(--accent-tint);
|
||||
border-left:3pt solid var(--accent); border-radius:0 4pt 4pt 0;
|
||||
padding:9pt 14pt; margin:11pt 0; font-size:9.4pt; line-height:1.5; color:var(--ink-2);
|
||||
}
|
||||
.callout strong,.callout b{ color:var(--accent-d); }
|
||||
.callout.cool{ background:var(--cream); border-left-color:var(--ink); }
|
||||
.callout.cool strong,.callout.cool b{ color:var(--ink); }
|
||||
|
||||
/* ---------------- FLOW CHIPS ---------------- */
|
||||
.flow{
|
||||
break-inside:avoid; display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
|
||||
gap:6pt; margin:14pt 0; padding:14pt 12pt; background:var(--cream); border-radius:7pt;
|
||||
}
|
||||
.chip{
|
||||
font-family:var(--sans); font-weight:600; font-size:9pt; color:var(--ink);
|
||||
background:#fff; border:.7pt solid var(--hair-2); padding:5pt 11pt; border-radius:20pt;
|
||||
box-shadow:0 1pt 2pt rgba(28,43,57,.05);
|
||||
}
|
||||
.chip.accent{ background:var(--accent); color:#fff; border-color:var(--accent); }
|
||||
.arrow{ color:var(--accent); font-weight:700; font-size:11pt; }
|
||||
|
||||
/* ---------------- SYNTHESIS CARDS ---------------- */
|
||||
.synthesis{ display:grid; grid-template-columns:1fr 1fr; gap:9pt; margin:12pt 0; break-inside:avoid; }
|
||||
.scard{ border:.7pt solid var(--hair); border-top:2.5pt solid var(--accent); border-radius:5pt; padding:9pt 12pt; background:#fff; }
|
||||
.scard .lab{ font-family:var(--sans); font-size:7.3pt; font-weight:700; letter-spacing:.1em; text-transform:uppercase; color:var(--accent-d); margin-bottom:3pt; }
|
||||
.scard .big{ font-family:var(--serif); font-size:13pt; font-weight:700; color:var(--ink); line-height:1.15; }
|
||||
.scard .val{ font-size:9pt; color:var(--ink-2); line-height:1.42; }
|
||||
.scard .sm{ font-size:8.2pt; color:var(--muted); margin-top:2pt; }
|
||||
|
||||
/* sign-off */
|
||||
.signoff{ margin-top:24pt; padding-top:14pt; border-top:1.2pt solid var(--ink); break-inside:avoid; }
|
||||
.signoff .nm{ font-family:var(--serif); font-size:14pt; font-weight:700; color:var(--ink); }
|
||||
.signoff .rl{ font-family:var(--sans); font-size:9pt; color:var(--muted); margin-top:2pt; letter-spacing:.03em; }
|
||||
|
||||
hr.div{ border:none; border-top:.6pt solid var(--hair); margin:16pt 0; }
|
||||
.spacer{ height:4pt; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ============ COVER ============ -->
|
||||
<div class="cover">
|
||||
<div class="top">
|
||||
<div class="rule"></div>
|
||||
<div class="eyebrow">Adenda 01 · Propuesta Comercial</div>
|
||||
</div>
|
||||
|
||||
<div class="mid">
|
||||
<h1>Integración Jira → BIND</h1>
|
||||
<div class="client">Generación automática de cotizaciones desde los tickets de facturación — <b>Balam</b></div>
|
||||
</div>
|
||||
|
||||
<div class="meta">
|
||||
<dl class="meta-grid">
|
||||
<dt>Preparada para</dt>
|
||||
<dd>Noe Rocha (CTO) · Araceli Sánchez Jiménez (CEO/Operaciones) · Erika Chávez (PM) · Pedro Alberto Ayala Elizondo (Contacto técnico)</dd>
|
||||
|
||||
<dt>Preparada por</dt>
|
||||
<dd>Johann Velazquez — Consultor de Software · Monterrey, N.L.</dd>
|
||||
|
||||
<dt>Fecha</dt>
|
||||
<dd>28 de julio de 2026</dd>
|
||||
|
||||
<dt>Referencia</dt>
|
||||
<dd>Propuesta Comercial v1.2 · Contrato de servicios firmado el 26-jun-2026 · §10 — Control de cambios</dd>
|
||||
|
||||
<dt>Vigencia</dt>
|
||||
<dd>30 días naturales a partir de la fecha de emisión</dd>
|
||||
</dl>
|
||||
|
||||
<div class="conf">
|
||||
<span class="badge">Documento confidencial</span>
|
||||
<span>Adenda a la propuesta v1.2 — no sustituye al contrato</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ============ CONTENT ============ -->
|
||||
<main class="content">
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">01</div><div><h2>Antecedente</h2></div></div>
|
||||
|
||||
<p>La propuesta v1.2 dejó Jira explícitamente <strong>fuera del alcance</strong> del MVP (§1.3 y Anexo A.4), conforme a la información disponible al momento de cotizar. Durante el Discovery y las sesiones de julio, la dirección confirmó que el proceso interno evolucionó: <strong>hoy todo el flujo de facturación de Balam nace y se gobierna en Jira</strong> — <em>"lo que no está en Jira no se procesa"</em> — con una bandeja dedicada (<strong>Facturación</strong>, llave <code>FAC-</code>) y un flujo de estatus formal que culmina en "resuelto".</p>
|
||||
|
||||
<p>En la sesión del 22 de julio el CTO planteó incorporar esta conectividad como ajuste de alcance; en la validación del prototipo del 24 de julio se ratificó, y en la sesión técnica del 27 de julio con Pedro Ayala quedó confirmada la viabilidad: la API de Jira cubre <strong>lectura y escritura</strong> de tickets, se entregó el token de integración (<strong>"PAF"</strong>, vigente al 27-jul-2027) y se documentaron los límites de consumo del lado de Atlassian. La estimación preliminar (~10 h) se comunicó a la PM el 21 de julio; esta adenda la formaliza por escrito, como lo prevé el control de cambios de la propuesta.</p>
|
||||
</section>
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">02</div><div><h2>Alcance del cambio</h2></div></div>
|
||||
|
||||
<p>La integración agrega a la primera etapa las siguientes capacidades:</p>
|
||||
|
||||
<ol>
|
||||
<li><strong>Conexión con la API de Jira</strong> mediante el token PAF y lectura de los tickets de la bandeja <strong>Facturación (<code>FAC-</code>)</strong>, con consumo autorregulado conforme a los límites de velocidad documentados por Atlassian.</li>
|
||||
<li><strong>Generación automática de la cotización en BIND</strong> cuando un ticket alcanza el estatus disparador que Balam defina (candidato natural: la entrada del ticket al proceso de facturación, previo a "resuelto"), a través de la misma <strong>capa de escritura controlada</strong> del MVP.</li>
|
||||
<li><strong>Trazabilidad ticket ↔ cotización ↔ prefactura/factura</strong>, visible en la plataforma y registrada en la bitácora de auditoría. Los tickets leídos alimentan además la vista <em>"qué necesita atención"</em> del tablero.</li>
|
||||
<li><strong>Pruebas controladas:</strong> scripts de consulta y de creación/edición sobre un registro de prueba, y una <strong>prueba observada</strong> con el equipo de Balam antes de habilitar la generación automática en operación (según lo acordado en la sesión del 27 de julio).</li>
|
||||
</ol>
|
||||
|
||||
<div class="flow">
|
||||
<span class="chip">Ticket Jira <small>(FAC)</small></span><span class="arrow">→</span>
|
||||
<span class="chip accent">Cotización BIND <small>(automática)</small></span><span class="arrow">→</span>
|
||||
<span class="chip">Prefactura</span><span class="arrow">→</span>
|
||||
<span class="chip">Aprobación humana</span><span class="arrow">→</span>
|
||||
<span class="chip">Timbrado <small>(PAC de BIND)</small></span>
|
||||
</div>
|
||||
|
||||
<div class="callout"><strong>El control fiscal no cambia.</strong> La integración crea <strong>cotizaciones, nunca facturas</strong>: se mantiene la cadena acordada — cotización → prefactura → <strong>aprobación humana</strong> → timbrado por el PAC de BIND — con modo de simulación (<em>dry-run</em>), feature flag y registro en bitácora. No existe timbrado automático.</div>
|
||||
</section>
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">03</div><div><h2>Qué no incluye</h2></div></div>
|
||||
|
||||
<ul>
|
||||
<li><strong>Alta automática de clientes en BIND.</strong> Si el cliente del ticket no existe en BIND, la plataforma lo <strong>detecta y lo notifica</strong>; darlo de alta automáticamente es una decisión de proceso aún abierta y, de aprobarse, se estima por separado.</li>
|
||||
<li><strong>Tickets con múltiples facturas.</strong> El supuesto de esta adenda es <em>un ticket → una cotización</em>. El manejo del caso masivo (un ticket con un listado de decenas de facturas) se define junto con Balam; si requiere desarrollo adicional, se estima por separado.</li>
|
||||
<li><strong>Otros usos de Jira</strong> — reporteo de horas de consultores, tableros sobre otras bandejas o el espacio comercial para pipeline de ventas — así como los módulos diferidos del Anexo B, permanecen fuera del alcance.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">04</div><div><h2>Estimación e inversión</h2></div></div>
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Concepto</th><th class="num">Horas</th><th class="num">Inversión (MXN)</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td class="k">Primera etapa — propuesta v1.2 (Etapas 0 a 3)</td><td class="num">112 – 136</td><td class="num">$67,200 – $81,600</td></tr>
|
||||
<tr><td class="k">Adenda 01 — Integración Jira → BIND: lectura de la bandeja FAC, disparador por estatus, cotización automática, trazabilidad y pruebas</td><td class="num">9 – 12</td><td class="num">$5,400 – $7,200</td></tr>
|
||||
<tr class="total"><td>Total de la primera etapa con adenda</td><td class="num">121 – 148</td><td class="num">$72,600 – $88,800</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<ul>
|
||||
<li><strong>Tarifa vigente:</strong> $600 MXN/h + IVA (§3.3). El rango es consistente con la estimación de ~10 h comunicada el 21 de julio y opera bajo el mismo esquema de horas reales <strong>con tope</strong>: al aproximarse al máximo, el trabajo se detiene y se revisa con Balam.</li>
|
||||
<li><strong>Facturación:</strong> como el resto de los avances — semanal (viernes) por horas efectivamente trabajadas, con pago a 30 días naturales.</li>
|
||||
<li>Cifras antes de IVA.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">05</div><div><h2>Supuestos y dependencias</h2></div></div>
|
||||
|
||||
<ol>
|
||||
<li><strong>Definición del flujo de facturación</strong> por parte de Balam (actualmente en revisión interna; sesión por agendar): de ella salen el estatus disparador y las reglas de prefactura. La implementación de esta adenda inicia una vez cerrada esa definición.</li>
|
||||
<li><strong>Token PAF vigente</strong> con visibilidad de la bandeja FAC (entregado el 27 de julio) y un interlocutor técnico (Pedro) para dudas de Jira, con respuesta en menos de 48 horas.</li>
|
||||
<li><strong>Diagrama del flujo Jira de facturación</strong> en tamaño legible (comprometido por Balam en la sesión del 22 de julio).</li>
|
||||
<li><strong>Bandeja FAC como fuente.</strong> FAC opera como bandeja "padre" del proceso de facturación; si las pruebas muestran que algún disparador nace en otra bandeja sin reflejarse en FAC, el ajuste se revisa en conjunto.</li>
|
||||
<li><strong>Sin ambiente de pruebas de BIND:</strong> toda prueba de escritura será acotada, acordada previamente y observada, como se convino con el CTO.</li>
|
||||
</ol>
|
||||
</section>
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">06</div><div><h2>Condiciones</h2></div></div>
|
||||
|
||||
<p>Todo lo no modificado por esta adenda — condiciones comerciales (§3.3), garantía de 45 días, propiedad del código, metodología de desarrollo y supuestos generales — permanece en los términos de la propuesta v1.2 y del contrato de servicios firmado. La mención de Jira como "fuera de alcance" (§1.3 y Anexo A) queda sustituida por el alcance acotado que esta adenda define.</p>
|
||||
</section>
|
||||
|
||||
<section class="sec">
|
||||
<div class="sec-head"><div class="sec-num">07</div><div><h2>Aceptación</h2></div></div>
|
||||
|
||||
<p>Conforme a la §10 de la propuesta (control de cambios), esta adenda se ejecuta tras su <strong>aprobación por escrito</strong>; basta la confirmación por correo electrónico. No requiere un nuevo contrato.</p>
|
||||
|
||||
<div class="signoff">
|
||||
<div class="nm">Johann Velazquez</div>
|
||||
<div class="rl">Consultor de Software · Monterrey, Nuevo León</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"input_html": "Adenda-01-Integracion-Jira.html",
|
||||
"output_pdf": "Adenda-01-Integracion-Jira-Balam.pdf",
|
||||
|
||||
"page_size": "Letter",
|
||||
"cover_full_bleed": true,
|
||||
"render_timeout_ms": 30000,
|
||||
|
||||
"metadata": {
|
||||
"title": "Adenda 01 — Integración Jira → BIND · Plataforma de Automatización Financiera · Balam",
|
||||
"author": "Johann Velazquez",
|
||||
"subject": "Solicitud de cambio a la propuesta v1.2: generación automática de cotizaciones en BIND desde tickets de Jira",
|
||||
"keywords": "adenda, Jira, BIND, Balam, control de cambios, cotizaciones"
|
||||
},
|
||||
|
||||
"footer": {
|
||||
"text": "Adenda 01 · Integración Jira → BIND · Balam — Confidencial",
|
||||
"skip_first_page": true,
|
||||
"skip_pages": [],
|
||||
"page_number_format": "{page} / {pages}",
|
||||
"rule": true,
|
||||
"font_size_pt": 7.5,
|
||||
"margin_mm": 12,
|
||||
"color": [0.46, 0.51, 0.57]
|
||||
},
|
||||
|
||||
"fonts": {
|
||||
"footer_ttf": "fonts/Carlito-Regular.ttf"
|
||||
},
|
||||
|
||||
"toc": {}
|
||||
}
|
||||
Reference in New Issue
Block a user