From e0ac9e844f874757d1898920c9e05d381859ffbf Mon Sep 17 00:00:00 2001 From: Daniel Arroyo Date: Fri, 21 Aug 2026 10:00:11 -0400 Subject: [PATCH] feat(calculadora): complete cost-split coverage in all modes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ranking de rentabilidad: add 3 columns (C. Cristales / C. Ore / C. Fee) alongside the existing Costo column. Update rankingFiltrado() to include the 3 sub-costs in its map output. - Totales Presupuesto (3 sub-vistas: simple/maximizado/mezcla): add Distribución del costo block with bar + legend under existing 3 cards. - Totales Objetivo: extend objetivoTotales() to aggregate sub-costs, then add the same distribution block. - Totales Plan cristales: same distribution block (planTotalesCristales already aggregated sub-costs). - Add 3 generic helpers pctCOf/pctOOf/pctFOf that take a totals object (handles both 'costoTotal' and 'costo' field names). - Fix x-show condition for Presupuesto distribution: use .costo (the field actually returned by planTotalesPresupuesto) instead of .costoTotal. Verified in browser across all 5 distribution points; percentages sum to 100% and math matches per-row calculations. --- .../templates/PageResource/calculadora.html | 97 ++++++++++++++++++- 1 file changed, 95 insertions(+), 2 deletions(-) diff --git a/src/main/resources/templates/PageResource/calculadora.html b/src/main/resources/templates/PageResource/calculadora.html index f20d36a..02169fc 100644 --- a/src/main/resources/templates/PageResource/calculadora.html +++ b/src/main/resources/templates/PageResource/calculadora.html @@ -271,6 +271,9 @@ Shots + C. Cristales + C. Ore + C. Fee Costo Venta vs Mercado @@ -294,6 +297,9 @@ :class="r.margenPct > 0 ? 'text-success' : r.margenPct < 0 ? 'text-error' : ''" x-text="fmtPct(r.margenPct)"> + + + @@ -473,6 +479,19 @@

+
+

Distribución del costo

+
+
+
+
+
+
+ Cristales + Ore + Fee +
+
@@ -972,6 +1043,21 @@ return t.costoTotal > 0 ? (t.costoDwarven * 100.0) / t.costoTotal : 0; }, + pctCOf(t) { + const total = t.costoTotal != null ? t.costoTotal : t.costo; + return total > 0 ? (t.costoCristales * 100.0) / total : 0; + }, + + pctOOf(t) { + const total = t.costoTotal != null ? t.costoTotal : t.costo; + return total > 0 ? (t.costoOre * 100.0) / total : 0; + }, + + pctFOf(t) { + const total = t.costoTotal != null ? t.costoTotal : t.costo; + return total > 0 ? (t.costoDwarven * 100.0) / total : 0; + }, + canSave() { return this.totalesGlobal().cristalesUsados > 0 && this.saveStatus !== 'saving'; }, @@ -1016,6 +1102,9 @@ margenPct, shotsObtenidos: c.shotsObtenidos, costo: c.costoTotal, + costoCristales: c.costoCristales, + costoOre: c.costoOre, + costoDwarven: c.costoDwarven, venta: c.valorVenta, precioMercado, costoPorShot, @@ -1141,16 +1230,20 @@ objetivoTotales() { const s = this.store().state; - if (!s) return { costo: 0, venta: 0, ganancia: 0, shots: 0 }; + if (!s) return { costo: 0, venta: 0, ganancia: 0, shots: 0, costoCristales: 0, costoOre: 0, costoDwarven: 0 }; let costo = 0, venta = 0, shots = 0; + let costoCristales = 0, costoOre = 0, costoDwarven = 0; for (const f of s.formulas) { const s2 = this.objetivoShots[f.id] || 0; if (s2 <= 0) continue; shots += s2; costo += this.objetivoCosto(f); venta += this.objetivoVenta(f); + costoCristales += this.objetivoCostoCristales(f); + costoOre += this.objetivoCostoOre(f); + costoDwarven += this.objetivoCostoDwarven(f); } - return { costo, venta, ganancia: venta - costo, shots }; + return { costo, venta, ganancia: venta - costo, shots, costoCristales, costoOre, costoDwarven }; }, planPorPresupuesto() {