/* ── Tipografía y layout ───────────────────────────────────────────────── */
body { font-family: 'Inter', 'Segoe UI', sans-serif; color: #1a1a2e; }
h1, h2, h3 { font-weight: 600; }
h2 { border-bottom: 2px solid #e9ecef; padding-bottom: .4rem; margin-top: 2.5rem; }
/* ── KPI Cards ───────────────────────────────────────────────────────────── */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fill,minmax(160px,1fr)); gap: 14px; margin-bottom: 2rem; }
.kpi-card { background:#fff; border:1px solid #e9ecef; border-radius:10px; padding:16px 18px; box-shadow:0 1px 4px rgba(0,0,0,.06); }
.kpi-card .label { font-size:.72rem; text-transform:uppercase; letter-spacing:.06em; color:#868e96; margin-bottom:4px; }
.kpi-card .value { font-size:1.55rem; font-weight:700; color:#2E4057; line-height:1.1; }
.kpi-card .delta { font-size:.75rem; color:#868e96; margin-top:3px; }
.kpi-card.accent { border-left:4px solid #2E4057; }
.kpi-card.accent2 { border-left:4px solid #048A81; }
/* ── Callout-style insight ───────────────────────────────────────────────── */
.insight { background:#f8f9fa; border-left:4px solid #2E4057; border-radius:0 8px 8px 0; padding:12px 16px; margin:1.2rem 0; font-size:.9rem; }
.insight strong { color:#2E4057; }
/* ── Section divider ─────────────────────────────────────────────────────── */
.section-intro { color:#495057; font-size:.95rem; margin-bottom:1.2rem; }
resumen_proy <- foco |>
group_by(Proyecto = Project_OS) |>
summarise(
Unidades = n(),
Facturacion = sum(Purchase.price, na.rm=TRUE),
`Ticket_prom` = mean(Purchase.price, na.rm=TRUE),
`Precio_m2 med.` = median(precio_m2, na.rm=TRUE),
`Pct_Recompra` = mean(es_recompra, na.rm=TRUE),
`Vendedores` = n_distinct(Seller.full.name),
.groups="drop"
) |>
arrange(desc(Facturacion)) |>
mutate(
Facturacion = MXN(Facturacion),
`Ticket_prom` = MXN(`Ticket_prom`),
`Precio_m2 med.` = MXN(`Precio_m2 med.`),
`Pct_Recompra` = PCT(`Pct_Recompra`)
)
DT::datatable(resumen_proy,
options = list(dom='t', pageLength=10, ordering=FALSE),
rownames = FALSE, class="compact stripe hover"
)
Tabla 1 — KPIs por proyecto foco
top_proy <- foco |> count(Project_OS, wt=Purchase.price) |> slice_max(n,n=1) |> pull(Project_OS)
top_fact <- foco |> filter(Project_OS==top_proy) |> summarise(s=sum(Purchase.price)) |> pull(s)
top_pct <- top_fact / kpi$facturacion
Oficinas Pininfarina concentra el 44.7% de la facturación total del universo foco ($870,218,786 MXN), seguido de Silenzio y Nativ T1. Los seis proyectos suman $1,944,739,819 MXN en 160 unidades desde 2022.
Serie histórica mensual desde el primer cierre registrado. Los picos y valles permiten identificar campañas de venta, lanzamientos y estacionalidad.
mensual <- foco |>
group_by(mes) |>
summarise(
n_uds = n(),
fact = sum(Purchase.price, na.rm=TRUE),
.groups = "drop"
) |>
arrange(mes) |>
mutate(fact_cum = cumsum(fact))
# Detectar pico
pico <- mensual |> slice_max(n_uds, n=1, with_ties=FALSE)
fig_ev <- plot_ly(mensual, x = ~mes) |>
add_bars(y = ~n_uds, name = "Unidades",
marker = list(color = "#2E4057", opacity=.85),
hovertemplate = "<b>%{x|%b %Y}</b><br>Unidades: %{y}<extra></extra>") |>
add_lines(y = ~fact/1e6, name = "Facturacion (M MXN)",
yaxis = "y2", line=list(color="#048A81", width=2.5),
hovertemplate = "<b>%{x|%b %Y}</b><br>Facturacion: $%{y:.1f}M<extra></extra>") |>
add_annotations(
x = pico$mes, y = pico$n_uds + .8, text = paste0("🏆 Pico:<br>", pico$n_uds, " uds"),
font=list(size=11, color="#2E4057"), showarrow=TRUE, arrowhead=1, arrowcolor="#2E4057",
ay=-40, bgcolor="white", bordercolor="#2E4057", borderpad=4
) |>
layout(
yaxis = list(title="Unidades", side="left", showgrid=TRUE, gridcolor="#f0f0f0"),
yaxis2 = list(title="Facturacion (M MXN)", overlaying="y", side="right", showgrid=FALSE),
legend = list(orientation="h", x=0, y=1.12),
hovermode = "x unified",
plot_bgcolor = "white", paper_bgcolor = "white",
margin = list(t=30, r=60)
)
fig_ev
mensual_proy <- foco |>
group_by(mes, Project_OS) |>
summarise(fact = sum(Purchase.price, na.rm=TRUE), .groups="drop")
fig_proy <- plot_ly()
for (p in FOCUS_PROJECTS) {
d <- mensual_proy |> filter(Project_OS == p)
fig_proy <- fig_proy |>
add_bars(data=d, x=~mes, y=~fact/1e6, name=p,
marker=list(color=pal_proyectos[p]),
hovertemplate=paste0("<b>",p,"</b><br>%{x|%b %Y}<br>$%{y:.1f}M MXN<extra></extra>"))
}
fig_proy <- fig_proy |>
layout(
barmode = "stack",
xaxis = list(title=""),
yaxis = list(title="Facturacion (M MXN)", gridcolor="#f0f0f0"),
legend = list(orientation="h", x=0, y=1.1),
plot_bgcolor="white", paper_bgcolor="white",
hovermode="x unified"
)
fig_proy
mensual_origen <- foco |>
group_by(mes, grupo_agg) |>
summarise(n=n(), fact=sum(Purchase.price, na.rm=TRUE), .groups="drop")
fig_oa <- plot_ly(mensual_origen, x=~mes, y=~fact/1e6, color=~grupo_agg,
colors = pal_grupo, type="bar",
hovertemplate="%{x|%b %Y}<br>$%{y:.1f}M<extra>%{fullData.name}</extra>") |>
layout(barmode="stack",
xaxis=list(title=""),
yaxis=list(title="Facturacion (M MXN)", gridcolor="#f0f0f0"),
legend=list(orientation="h",x=0,y=1.1),
plot_bgcolor="white", paper_bgcolor="white",
hovermode="x unified")
fig_oa
ult6 <- foco |>
filter(mes >= max(mes, na.rm=TRUE) %m-% months(6)) |>
count(grupo_agg, wt=Purchase.price) |>
mutate(pct=n/sum(n))
gbr_rec <- ult6 |> filter(grupo_agg=="GBR") |> pull(pct)
gbr_hist <- mean(foco$grupo_agg=="GBR")
En los últimos 6 meses, GBR representa el 11.5% de la facturación vs 44.4% histórico. <U+0001F4C9> Producci<U+00F3>n directa sigue siendo el motor principal.
Analizamos quién trae los clientes: ventas directas del equipo, embajadores o canales externos (GBR). El origen explica el costo de adquisición y la predictibilidad del flujo.
mix_origen <- foco |>
group_by(Origin_OS, grupo_origen, grupo_agg) |>
summarise(
n_uds = n(),
fact = sum(Purchase.price, na.rm=TRUE),
.groups = "drop"
) |>
arrange(desc(fact)) |>
mutate(
pct_fact = fact / sum(fact),
Origin_display = ifelse(nchar(Origin_OS)==0, "Sin origen", Origin_OS)
)
col_fn <- function(o) { v <- pal_origen[o]; if(is.na(v)) "#ADB5BD" else v }
fig_mix <- plot_ly(mix_origen,
x = ~reorder(Origin_display, fact), y = ~fact/1e6,
type="bar", orientation="v",
marker = list(color = sapply(mix_origen$Origin_display, col_fn)),
text = ~paste0(round(pct_fact*100,1), "%"),
textposition = "outside",
hovertemplate = "<b>%{x}</b><br>Facturacion: $%{y:.1f}M MXN<br>%{text} del total<extra></extra>"
) |>
layout(
xaxis = list(title=""),
yaxis = list(title="Facturacion (M MXN)", gridcolor="#f0f0f0"),
plot_bgcolor="white", paper_bgcolor="white",
showlegend=FALSE
)
fig_mix
cross <- foco |>
group_by(Project_OS, grupo_agg) |>
summarise(fact=sum(Purchase.price, na.rm=TRUE), .groups="drop") |>
group_by(Project_OS) |>
mutate(pct=fact/sum(fact)) |>
ungroup()
fig_cross <- plot_ly(cross, x=~grupo_agg, y=~Project_OS, z=~round(pct*100,1),
type="heatmap",
colorscale=list(c(0,"#EDF2FB"), c(1,"#2E4057")),
text=~paste0(round(pct*100,1),"%\n$",round(fact/1e6,1),"M"),
hovertemplate="<b>%{y}</b><br>%{x}<br>%{text}<extra></extra>",
showscale=TRUE
) |>
layout(
xaxis=list(title=""),
yaxis=list(title=""),
plot_bgcolor="white", paper_bgcolor="white"
)
fig_cross
tabla_ox <- foco |>
group_by(Origen=Origin_OS, Proyecto=Project_OS) |>
summarise(Uds=n(), Facturacion=sum(Purchase.price, na.rm=TRUE), .groups="drop") |>
mutate(
Grupo = grupo_origen_fn(Origen),
`Pct_total` = PCT(Facturacion / kpi$facturacion),
Facturacion = MXN(Facturacion)
) |>
arrange(Proyecto, desc(Uds))
DT::datatable(tabla_ox,
filter="top",
options=list(pageLength=15, dom="ftip",
columnDefs=list(list(className="dt-right", targets=c(2,3)))),
rownames=FALSE, class="compact stripe hover"
)
El 23.1% de las unidades en proyectos foco son recompras (clientes que ya compraron antes). Esto es -0.3 pp por debajo del benchmark del portafolio.
rc_proy <- foco |>
group_by(Project_OS) |>
summarise(
n_total = n(),
n_recompra = sum(es_recompra),
tasa = mean(es_recompra),
.groups = "drop"
) |>
arrange(desc(tasa))
fig_rc <- plot_ly(rc_proy,
x=~tasa*100, y=~reorder(Project_OS, tasa),
type="bar", orientation="h",
marker=list(color=sapply(rc_proy$Project_OS, function(p) pal_proyectos[p])),
text=~paste0(round(tasa*100,1),"% (", n_recompra,"/",n_total," uds)"),
textposition="outside",
hovertemplate="<b>%{y}</b><br>%{text}<extra></extra>"
) |>
add_segments(x=kpi$b_recompra*100, xend=kpi$b_recompra*100,
y=0.4, yend=nrow(rc_proy)+0.6, line=list(color="grey50", dash="dot"),
showlegend=TRUE, name=paste0("Benchmark (",PCT(kpi$b_recompra),")")) |>
layout(
xaxis=list(title="% recompra", ticksuffix="%", gridcolor="#f0f0f0"),
yaxis=list(title=""),
plot_bgcolor="white", paper_bgcolor="white",
legend=list(x=0.6, y=0.05)
)
fig_rc
## Warning: Can't display both discrete & non-discrete data on same axis
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...
ticket_rc <- foco |>
group_by(`Tipo_cliente`=ifelse(es_recompra,"Recompra","Primera vez")) |>
summarise(
Unidades = n(),
`Ticket_prom` = mean(Purchase.price, na.rm=TRUE),
`Ticket mediana` = median(Purchase.price, na.rm=TRUE),
.groups="drop"
)
fig_trc <- plot_ly(ticket_rc,
x=~`Tipo_cliente`, y=~`Ticket_prom`/1e6,
type="bar",
marker=list(color=c("#2E4057","#048A81")),
text=~paste0(MXN(`Ticket_prom`),"\nn=",Unidades),
textposition="outside",
hovertemplate="<b>%{x}</b><br>Ticket prom: $%{y:.2f}M MXN<extra></extra>"
) |>
layout(
yaxis=list(title="Ticket promedio (M MXN)", gridcolor="#f0f0f0"),
xaxis=list(title=""),
plot_bgcolor="white", paper_bgcolor="white", showlegend=FALSE
)
fig_trc
clientes_rc <- foco |>
group_by(`Cliente`=Client.full.name) |>
summarise(
`N_Compras` = n(),
Proyectos = paste(sort(unique(Project_OS)), collapse=", "),
`Facturacion total` = sum(Purchase.price, na.rm=TRUE),
.groups="drop"
) |>
filter(`N_Compras` > 1) |>
arrange(desc(`Facturacion total`)) |>
mutate(`Facturacion total` = MXN(`Facturacion total`))
DT::datatable(clientes_rc,
options=list(pageLength=10, dom="ftp"),
rownames=FALSE, class="compact stripe hover"
)
Comparamos la distribución de precio por m² entre proyectos para entender posicionamiento de producto. Un precio/m² más alto puede reflejar acabados premium, ubicación o escasez de inventario.
foco_pm2 <- foco |> filter(!is.na(precio_m2), precio_m2 > 0, precio_m2 < 300000)
fig_box <- plot_ly(foco_pm2, x=~precio_m2, y=~Project_OS,
type="box", color=~Project_OS, colors=pal_proyectos,
boxmean=TRUE, jitter=0.3, pointpos=0,
hovertemplate="<b>%{y}</b><br>$%{x:,.0f}/m²<extra></extra>"
) |>
add_segments(
x=kpi$b_pm2, xend=kpi$b_pm2,
y=0.4, yend=length(FOCUS_PROJECTS)+0.6,
line=list(color="grey50", dash="dot"),
name=paste0("Benchmark (",MXN(kpi$b_pm2),"/m²)"),
showlegend=TRUE, inherit=FALSE
) |>
layout(
xaxis=list(title="Precio_m2 (MXN)", tickformat="$,.0f", gridcolor="#f0f0f0"),
yaxis=list(title=""),
showlegend=TRUE, legend=list(x=0.7, y=0.05),
plot_bgcolor="white", paper_bgcolor="white"
)
fig_box
## Warning: Can't display both discrete & non-discrete data on same axis
fig_sc <- plot_ly(foco_pm2,
x=~m2, y=~Purchase.price/1e6,
color=~Project_OS, colors=pal_proyectos,
type="scatter", mode="markers",
size=~Purchase.price, sizes=c(6,30),
text=~paste0(Project_OS,"<br>",round(m2,0)," m²<br>",MXN(Purchase.price),"<br>",MXN(precio_m2),"/m²"),
hovertemplate="%{text}<extra></extra>",
marker=list(opacity=0.75, line=list(width=0.5, color="white"))
) |>
layout(
xaxis=list(title="Superficie (m²)", gridcolor="#f0f0f0"),
yaxis=list(title="Precio de venta (M MXN)", gridcolor="#f0f0f0"),
legend=list(orientation="h", x=0, y=1.1),
plot_bgcolor="white", paper_bgcolor="white"
)
fig_sc
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.
## Warning: `line.width` does not currently support multiple values.
pm2_evol <- foco_pm2 |>
group_by(mes, Project_OS) |>
summarise(med_pm2=median(precio_m2, na.rm=TRUE), .groups="drop")
fig_pm2 <- plot_ly()
for (p in FOCUS_PROJECTS) {
d <- pm2_evol |> filter(Project_OS==p)
if (nrow(d) > 1) {
fig_pm2 <- fig_pm2 |>
add_lines(data=d, x=~mes, y=~med_pm2, name=p,
line=list(color=pal_proyectos[p], width=2),
hovertemplate=paste0("<b>",p,"</b><br>%{x|%b %Y}<br>$%{y:,.0f}/m²<extra></extra>"))
}
}
fig_pm2 <- fig_pm2 |>
layout(
xaxis=list(title=""),
yaxis=list(title="Precio_m2 mediano (MXN)", tickformat="$,.0f", gridcolor="#f0f0f0"),
legend=list(orientation="h", x=0, y=1.1),
plot_bgcolor="white", paper_bgcolor="white",
hovermode="x unified"
)
fig_pm2
Entender quién vende y por qué canal es crítico para replicar el éxito. La concentración en pocos vendedores es un riesgo operativo; el HHI cuantifica eso.
top_vend <- foco |>
group_by(Vendedor=Seller.full.name) |>
summarise(
Unidades = n(),
Facturacion = sum(Purchase.price, na.rm=TRUE),
`Ticket_prom` = mean(Purchase.price, na.rm=TRUE),
`Origen_principal` = names(sort(table(Origin_OS), decreasing=TRUE))[1],
`Proyectos` = paste(sort(unique(Project_OS)), collapse=", "),
.groups="drop"
) |>
filter(Vendedor != "Sin vendedor") |>
arrange(desc(Facturacion)) |>
head(15) |>
mutate(
`Pct_total` = PCT(Facturacion / kpi$facturacion),
Facturacion = MXN(Facturacion),
`Ticket_prom`= MXN(`Ticket_prom`)
)
DT::datatable(top_vend,
options=list(pageLength=15, dom="t", ordering=FALSE),
rownames=FALSE, class="compact stripe hover"
)
top10_v <- foco |>
group_by(Seller.full.name) |>
summarise(f=sum(Purchase.price, na.rm=TRUE)) |>
filter(Seller.full.name!="Sin vendedor") |>
slice_max(f, n=10) |>
pull(Seller.full.name)
hm_data <- foco |>
filter(Seller.full.name %in% top10_v) |>
group_by(Vendedor=Seller.full.name, Proyecto=Project_OS) |>
summarise(fact=sum(Purchase.price, na.rm=TRUE), n=n(), .groups="drop")
fig_hm <- plot_ly(hm_data,
x=~Proyecto, y=~Vendedor, z=~round(fact/1e6,1),
type="heatmap",
colorscale=list(c(0,"#EDF2FB"), c(0.5,"#7EC8E3"), c(1,"#2E4057")),
text=~paste0("$",round(fact/1e6,1),"M\n",n," uds"),
hovertemplate="<b>%{y}</b><br>%{x}<br>%{text}<extra></extra>",
showscale=TRUE
) |>
layout(
xaxis=list(title="", tickangle=-20),
yaxis=list(title=""),
plot_bgcolor="white", paper_bgcolor="white"
)
fig_hm
shares <- foco |>
group_by(Seller.full.name) |>
summarise(f=sum(Purchase.price, na.rm=TRUE)) |>
filter(Seller.full.name!="Sin vendedor") |>
mutate(s=f/sum(f))
hhi <- sum(shares$s^2)
top1_share <- max(shares$s)
top1_name <- shares$Seller.full.name[which.max(shares$s)]
top3_share <- sum(sort(shares$s, decreasing=TRUE)[1:3])
fig_lorenz <- plot_ly() |>
add_lines(
x=c(0, cumsum(sort(shares$s))/sum(shares$s)),
y=c(0, cumsum(sort(shares$f))/sum(shares$f)),
name="Curva de Lorenz", line=list(color="#2E4057", width=2.5)
) |>
add_lines(x=c(0,1), y=c(0,1), name="Igualdad perfecta",
line=list(color="#ADB5BD", dash="dot")) |>
layout(
xaxis=list(title="Fracción acumulada de vendedores", tickformat=".0%"),
yaxis=list(title="Fracción acumulada de facturación", tickformat=".0%"),
legend=list(x=0.05, y=0.95),
plot_bgcolor="white", paper_bgcolor="white",
annotations=list(x=0.65, y=0.2,
text=paste0("HHI = ", round(hhi,3),
"<br>Top 1: ", PCT(top1_share),
" (", top1_name, ")",
"<br>Top 3: ", PCT(top3_share)),
showarrow=FALSE, bgcolor="white",
bordercolor="#dee2e6", borderpad=8, font=list(size=12)
)
)
fig_lorenz
riesgo <- ifelse(hhi > 0.25, "⚠️ concentración alta (HHI > 0.25)",
ifelse(hhi > 0.15, "moderada (0.15 < HHI < 0.25)", "baja (HHI < 0.15)"))
HHI = 0.165 — concentración moderada (0.15 < HHI < 0.25). Daniel Loeza King acumula el 26.2% de la facturación foco. Los tres vendedores principales concentran el 66.8%. Un HHI > 0.25 indica dependencia de pocos comerciales.
Tabla completa de todas las unidades vendidas en proyectos foco. Filtra por cualquier columna para drill-down.
detalle <- foco |>
select(
Proyecto = Project_OS,
Unidad = X_id,
Fecha = fecha_venta,
Vendedor = Seller.full.name,
Cliente = Client.full.name,
Origen = Origin_OS,
`Grupo_origen` = grupo_agg,
m2,
Precio = Purchase.price,
`Precio_m2` = precio_m2,
Recompra = es_recompra,
Estatus = Status_OS
) |>
mutate(
Precio = MXN(Precio),
`Precio_m2` = MXN(`Precio_m2`),
m2 = round(m2, 1),
Recompra = ifelse(Recompra, "✓", "")
) |>
arrange(Proyecto, desc(Fecha))
DT::datatable(detalle,
filter="top",
extensions="Buttons",
options=list(
pageLength=20, dom="Bfrtip",
buttons=list("excel","csv"),
scrollX=TRUE,
columnDefs=list(list(visible=FALSE, targets=1))
),
rownames=FALSE, class="compact stripe hover"
)
gbr_pct <- mean(foco$grupo_agg=="GBR")
dir_pct <- mean(foco$grupo_agg=="Directo + Prod. Directa")
top_orig <- foco |> count(Origin_OS, wt=Purchase.price) |> slice_max(n,n=1) |> pull(Origin_OS)
top_orig_pct <- foco |> count(Origin_OS, wt=Purchase.price) |>
mutate(p=n/sum(n)) |> filter(Origin_OS==top_orig) |> pull(p)
cat(glue::glue("
**Universo analizado:** {kpi$n_uds} unidades — {kpi$n_origenes} orígenes distintos — {kpi$n_vendedores} vendedores — rango 2022–2026.
**Origen dominante:** {top_orig} ({PCT(top_orig_pct)} de la facturación). La producción propia (Directo + Prod. Directa) explica el {PCT(dir_pct)}, lo que indica un modelo mayoritariamente autosustentado. GBR representa el {PCT(gbr_pct)} restante.
**Recompra por encima del benchmark:** {PCT(kpi$pct_recompra)} vs {PCT(kpi$b_recompra)} del resto del portafolio, señal de alta satisfacción y fidelización en los proyectos foco.
**Concentración comercial:** {top1_name} concentra {PCT(top1_share)} de la facturación (HHI {round(hhi,3)}). Una estrategia de diversificación de vendedores reduciría el riesgo.
**Precio_m2:** la mediana del foco ({MXN(kpi$med_pm2)}/m²) es ligeramente inferior al benchmark ({MXN(kpi$b_pm2)}/m²). Oficinas Pininfarina lidera en volumen absoluto; Silenzio muestra los precios/m² más altos del grupo.
", .open="{{", .close="}}"))
Universo analizado: {kpi\(n_uds} unidades <U+2014> {kpi\)n_origenes} or<U+00ED>genes distintos <U+2014> {kpi$n_vendedores} vendedores <U+2014> rango 2022<U+2013>2026.
Origen dominante: {top_orig} ({PCT(top_orig_pct)} de la facturaci<U+00F3>n). La producci<U+00F3>n propia (Directo + Prod. Directa) explica el {PCT(dir_pct)}, lo que indica un modelo mayoritariamente autosustentado. GBR representa el {PCT(gbr_pct)} restante.
Recompra por encima del benchmark: {PCT(kpi\(pct_recompra)} vs {PCT(kpi\)b_recompra)} del resto del portafolio, se<U+00F1>al de alta satisfacci<U+00F3>n y fidelizaci<U+00F3>n en los proyectos foco.
Concentraci<U+00F3>n comercial: {top1_name} concentra {PCT(top1_share)} de la facturaci<U+00F3>n (HHI {round(hhi,3)}). Una estrategia de diversificaci<U+00F3>n de vendedores reducir<U+00ED>a el riesgo.
Precio_m2: la mediana del foco ({MXN(kpi\(med_pm2)}/m<U+00B2>) es ligeramente inferior al benchmark ({MXN(kpi\)b_pm2)}/m<U+00B2>). Oficinas Pininfarina lidera en volumen absoluto; Silenzio muestra los precios/m<U+00B2> m<U+00E1>s altos del grupo.
Datos: latest.rds — actualizado 2026-05-25 15:56. Grano:
soldproperty (1 fila = 1 unidad). Cierres = Firmadas + En
proceso con Approval.in.Progress = TRUE. Excluidos:
cancelados, draft, anulados. Benchmark = resto del portafolio con los
mismos filtros de estatus.