SPB Git

Repository Public

valuation.ts 4.6 KB 73 lines typescript

1// UQO Éval — Métré : méthode du coût (valeur indiquée) à partir d'une révision d'estimation. Module PUR.2/**3 *   Coût à neuf utilisé  = coût de la révision × (1 + ajustement de base %)   [reproduction ↔ remplacement]4 *   Coût à neuf total    = coût à neuf utilisé + améliorations du site admissibles5 *   D_physique           = coût à neuf total × min(âge effectif / vie économique, 90 %)   (âge-vie) ou × % saisi6 *   D_fonctionnelle      = Σ curables (coût de correction) + Σ incurables (perte de valeur)7 *                          — une déficience « éliminée par la conception de remplacement » n'est PAS déduite8 *                            quand la base est le coût de REMPLACEMENT (sinon double déduction)9 *   D_externe            = montant saisi (≥ 0)10 *   Améliorations dépréciées = max(0, coût à neuf total − D_phys − D_fonct − D_ext)11 *   Valeur indiquée      = terrain + améliorations dépréciées12 */13import type { ValuationInput, ValuationResult } from "./types";14import { fromCents, mulCents, pctOf, sumCents, toCents } from "./money";1516export const VALUATION_VERSION = "metre-valuation-1.0";17export const MAX_PHYSICAL_PCT = 90;1819export function computeValuation(v: ValuationInput): ValuationResult {20  const warnings: string[] = [];21  const costNewC = toCents(Math.max(0, v.costNew));22  const basisAdjC = pctOf(costNewC, v.basisAdjustmentPct || 0);23  if (v.basis === "reproduction" && v.basisAdjustmentPct) warnings.push("ajustement de base appliqué sur un coût de reproduction : vérifier qu'il ne s'agit pas d'une obsolescence fonctionnelle déjà comptée");24  const usedC = costNewC + basisAdjC;25  const siteC = toCents(Math.max(0, v.siteImprovements || 0));26  const totalNewC = usedC + siteC;2728  let physicalPct: number;29  if (v.physical.method === "percent") {30    physicalPct = Math.min(MAX_PHYSICAL_PCT, Math.max(0, v.physical.percent ?? 0));31  } else {32    const life = Math.max(1, v.physical.economicLife || 1);33    const age = Math.max(0, v.physical.effectiveAge ?? 0);34    if (v.physical.effectiveAge == null) warnings.push("âge effectif non saisi : dépréciation physique nulle");35    physicalPct = Math.min(MAX_PHYSICAL_PCT, (100 * age) / life);36  }37  const physC = mulCents(totalNewC, physicalPct / 100);3839  const skipped: ValuationResult["functionalSkipped"] = [];40  let curC = 0, incC = 0;41  for (const f of v.functional) {42    const amt = toCents(Math.max(0, f.amount || 0));43    if (v.basis === "replacement" && f.eliminatedByReplacement) { skipped.push({ id: f.id, label: f.label, amount: fromCents(amt) }); continue; }44    if (f.curable) curC += amt; else incC += amt;45  }46  if (skipped.length) warnings.push(`${skipped.length} déficience(s) non déduite(s) : déjà éliminée(s) par la conception de remplacement`);47  const extC = toCents(Math.max(0, v.external.amount || 0));48  let depC = sumCents([physC, curC, incC, extC]);49  if (depC > totalNewC) { warnings.push("dépréciation totale plafonnée au coût à neuf"); depC = totalNewC; }50  const depImpC = totalNewC - depC;51  const landC = toCents(Math.max(0, v.land.value || 0));52  if (!(v.land.value > 0)) warnings.push("valeur du terrain nulle ou absente");53  const valueC = landC + depImpC;54  return {55    costNewUsed: fromCents(usedC), basisAdjustment: fromCents(basisAdjC), siteImprovements: fromCents(siteC), totalCostNew: fromCents(totalNewC),56    physicalPct: Math.round(physicalPct * 100) / 100, physical: fromCents(physC), functionalCurable: fromCents(curC), functionalIncurable: fromCents(incC), functionalSkipped: skipped,57    external: fromCents(extC), totalDepreciation: fromCents(depC), depreciatedImprovements: fromCents(depImpC), landValue: fromCents(landC), indicatedValue: fromCents(valueC),58    steps: [59      { label: v.basis === "replacement" ? "Coût de remplacement à neuf (utilité équivalente)" : "Coût de reproduction à neuf (réplique)", amount: fromCents(usedC) },60      { label: "+ Améliorations du site admissibles", amount: fromCents(siteC) },61      { label: "= Coût à neuf total", amount: fromCents(totalNewC) },62      { label: `− Détérioration physique (${Math.round(physicalPct * 100) / 100} %)`, amount: -fromCents(physC) },63      { label: "− Obsolescence fonctionnelle curable", amount: -fromCents(curC) },64      { label: "− Obsolescence fonctionnelle incurable", amount: -fromCents(incC) },65      { label: "− Obsolescence externe / économique", amount: -fromCents(extC) },66      { label: "= Améliorations dépréciées", amount: fromCents(depImpC) },67      { label: "+ Valeur du terrain", amount: fromCents(landC) },68      { label: "= Valeur indiquée par la méthode du coût", amount: fromCents(valueC) },69    ],70    warnings,71  };72}73
Files main
Menu

Theme