diff --git a/packages/web/components/InputsTab.tsx b/packages/web/components/InputsTab.tsx index 736ea56..fbc956d 100644 --- a/packages/web/components/InputsTab.tsx +++ b/packages/web/components/InputsTab.tsx @@ -791,10 +791,16 @@ export function InputsTab({ scenarioId, inputsJson, onSaved }: Props) { const solarBOS = solarItems.filter(it => ["solar_inverter", "solar_dc_bos", "solar_ac_bos", "solar_hr"].includes(it.id)).reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); const solarModule = solarItems.filter(it => it.id === "solar_module").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); const windWTG = windItems.filter(it => ["wind_wtg", "wind_tower", "wind_bop", "wind_e_and_c"].includes(it.id)).reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); - const allLand = [...solarItems, ...windItems].filter(it => it.id.includes("land")).reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const solarLandCost = solarItems.filter(it => it.id.includes("land") && it.attribution === "SolarOnly").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const windLandCost = windItems.filter(it => it.id.includes("land") && it.attribution === "WindOnly").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); const bessAll = bessItems.reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); - const epcAll = [...solarItems, ...windItems, ...bessItems].filter(it => it.category === "EPCOverhead").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); - const contAll = [...solarItems, ...windItems].filter(it => it.category === "Contingency").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const solarEPC = solarItems.filter(it => it.category === "EPCOverhead").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const windEPC = windItems.filter(it => it.category === "EPCOverhead").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const solarCont = solarItems.filter(it => it.category === "Contingency" && it.attribution === "SolarOnly").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const windCont = windItems.filter(it => it.category === "Contingency" && it.attribution === "WindOnly").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + // EPC Margins + const epcMarginWTG = [...windItems, ...bessItems].filter(it => it.category === "EPCMargin" && it.attribution === "WindOnly").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); + const epcMarginSolarBOS = solarItems.filter(it => it.category === "EPCMargin" && it.attribution === "SolarOnly").reduce((acc, it) => acc + (computeItemCr(it, solarDcMwp, windMw, bessMwh, 0, effectiveLandAcres) ?? 0), 0); // Financing const idcRate = gv(inputs, "capex", "interest_rate_annual", 0.09); const constrMonths = gv(inputs, "capex", "construction_months", 24); @@ -802,6 +808,15 @@ export function InputsTab({ scenarioId, inputsJson, onSaved }: Props) { const idcCost = totalCostCr * debtFrac * idcRate * constrMonths / 12; const upfrontPct = gv(inputs, "capex", "upfront_fee_pct", 0.01); const upfrontCost = totalCostCr * debtFrac * upfrontPct; + const bankGuaranteePct = gv(inputs, "capex", "bank_guarantee_pct", 0.001); + const bankGuaranteeCost = totalCostCr * bankGuaranteePct; + // DSRA (Debt Service Reserve Account) - typically 1-2 months of debt service + const dsraMonths = gv(inputs, "capex", "dsra_months", 2); + const annualDebtService = totalCostCr * debtFrac * 0.12; // approximate annual debt service + const dsraCost = annualDebtService * dsraMonths / 12; + + // Compute Total Hard Cost (sum of all component costs before financing) + const totalHardCost = solarModule + solarBOS + windWTG + solarLandCost + windLandCost + bessAll + dsraCost + solarEPC + windEPC + epcMarginWTG + epcMarginSolarBOS + solarCont + windCont; return (