Python 64.6%
TypeScript 33.7%
CSS 0.8%
1"""Template: loan amortisation schedule."""23from __future__ import annotations45from typing import Any67from app.tools.coerce import num, pct8910def _f(p: dict[str, Any], key: str, default: float) -> float:11 """Tolerant numeric param; keys ending in `_pct` / starting with `taux` are ratios."""12 raw = p.get(key)13 v = pct(raw, None) if (key.endswith("_pct") or key.startswith("taux")) else num(raw, None)14 return float(default) if v is None else v151617def build(p: dict[str, Any]) -> dict[str, Any]:18 principal = _f(p, "capital", 350000)19 rate = _f(p, "taux_annuel", 0.055)20 years = int(_f(p, "amortissement_ans", 25))21 ppy = int(_f(p, "versements_par_an", 12))22 n_show = min(years * ppy, 360)23 inputs = [24 {"cell": "B4", "label": "Capital emprunté ($)", "value": principal, "format": "currency",25 "name": "Capital"},26 {"cell": "B5", "label": "Taux nominal annuel", "value": rate, "format": "percent",27 "name": "Taux"},28 {"cell": "B6", "label": "Amortissement (ans)", "value": years, "format": "integer"},29 {"cell": "B7", "label": "Versements par an", "value": ppy, "format": "integer"},30 {"cell": "B8", "label": "Taux périodique", "value": "=B5/B7", "format": "percent"},31 {"cell": "B9", "label": "Nombre de versements", "value": "=B6*B7", "format": "integer"},32 {"cell": "B10", "label": "Versement périodique ($)", "value": "=-PMT(B8,B9,B4)",33 "format": "currency", "name": "Versement"},34 ]35 rows = []36 for k in range(1, n_show + 1):37 r = 13 + k38 prev = "B4" if k == 1 else f"F{r - 1}"39 rows.append([k, f"={prev}", "=$B$10", f"=B{r}*$B$8", f"=C{r}-D{r}", f"=B{r}-E{r}"])40 table = {41 "anchor": "A13",42 "columns": [{"header": "Période", "type": "integer"}, {"header": "Solde début ($)", "type": "currency"},43 {"header": "Versement ($)", "type": "currency"}, {"header": "Intérêts ($)", "type": "currency"},44 {"header": "Capital ($)", "type": "currency"}, {"header": "Solde fin ($)", "type": "currency"}],45 "rows": rows,46 }47 return {48 "filename": p.get("filename", "tableau_amortissement.xlsx"),49 "style": "uqo",50 "sheets": [{51 "name": "Amortissement",52 "title": "Tableau d'amortissement d'un prêt hypothécaire",53 "inputs": inputs,54 "tables": [table],55 "charts": [{"type": "line", "title": "Solde du prêt", "categories_range": f"A14:A{13 + n_show}",56 "values_range": f"F14:F{13 + n_show}", "anchor": "H13"}],57 "notes": ["Versement = Capital × FRC = Capital × i / (1 − (1+i)^-n).",58 "Le taux périodique est le taux nominal divisé par le nombre de versements par an (capitalisation simple)."],59 }],60 }61