workspace-bilans: agent bilans AIRTRIA (fiche, outil, donnees), renvoi maison
- Nouvel agent « bilans » : AGENTS.md tire de reference-bilans.md (AIRTRIA_BILAN), scripts/bilans.py et bilans/airtria-balances.json identiques au pack /mnt/projects/analyse-bilans. Joignable dans le groupe WhatsApp « Bilans AIRTRIA » du compte Samsung (binding peer groupe dans openclaw.json, non versionne). - Agent maison : §4 « MAILS », §4bis renvoi des bilans vers le groupe. - .gitignore : liste blanche de workspace-bilans (memoire et etat exclus).
This commit is contained in:
399
workspace-bilans/scripts/bilans.py
Executable file
399
workspace-bilans/scripts/bilans.py
Executable file
@@ -0,0 +1,399 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Analyse des bilans AIRTRIA — outil OpenClaw (python3 >= 3.11, bibliothèque standard seule).
|
||||
|
||||
Lit bilans/airtria-balances.json (balance par compte de chaque exercice, produite par
|
||||
extract.py) et répond en texte français prêt à relayer tel quel.
|
||||
|
||||
bilans.py liste exercices disponibles, CA et résultat
|
||||
bilans.py resume [AN] synthèse d'un exercice (défaut : le dernier)
|
||||
bilans.py compare AN1 AN2 évolution des indicateurs entre deux exercices
|
||||
bilans.py evolution [INDICATEUR] série sur tous les exercices (sans argument : liste)
|
||||
bilans.py charges [AN] détail des charges par compte
|
||||
bilans.py compte MOTIF [AN] compte(s) dont le numéro commence par / le libellé contient MOTIF
|
||||
bilans.py ratios [AN] ratios avec leur formule
|
||||
bilans.py sources provenance des chiffres et contrôles de cohérence
|
||||
Option globale : --json (sortie brute pour débogage).
|
||||
|
||||
Exercice N = du 01/10/N-1 au 30/09/N.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
DATA = Path(os.environ.get("BILANS_DATA", Path(__file__).resolve().parent.parent / "bilans/airtria-balances.json"))
|
||||
|
||||
|
||||
# ── Chargement ────────────────────────────────────────────────────────────────
|
||||
|
||||
def charger():
|
||||
try:
|
||||
return json.loads(DATA.read_text(encoding="utf-8"))
|
||||
except FileNotFoundError:
|
||||
sortir(f"ERREUR : fichier de données introuvable : {DATA}", 2)
|
||||
|
||||
|
||||
def sortir(msg, code=1):
|
||||
print(msg)
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
# ── Agrégats (Plan comptable général) ─────────────────────────────────────────
|
||||
|
||||
def somme(comptes, *prefixes, signe=1):
|
||||
"""Somme des soldes (débit - crédit) des comptes commençant par l'un des préfixes.
|
||||
signe=-1 pour les comptes à solde normalement créditeur (produits, passif)."""
|
||||
return signe * sum(c["solde"] for n, c in comptes.items() if n.startswith(prefixes))
|
||||
|
||||
|
||||
def somme_signee(comptes, prefixes, debiteur):
|
||||
"""Somme des seuls comptes débiteurs (actif) ou créditeurs (passif), compte par compte :
|
||||
un compte fournisseur débiteur est une créance, une banque créditrice une dette."""
|
||||
tot = 0.0
|
||||
for n, c in comptes.items():
|
||||
if n.startswith(prefixes):
|
||||
if debiteur and c["solde"] > 0:
|
||||
tot += c["solde"]
|
||||
elif not debiteur and c["solde"] < 0:
|
||||
tot -= c["solde"]
|
||||
return tot
|
||||
|
||||
|
||||
def indicateurs(comptes):
|
||||
s = lambda *p: somme(comptes, *p)
|
||||
p = lambda *p: somme(comptes, *p, signe=-1)
|
||||
i = {}
|
||||
# Compte de résultat
|
||||
i["ca"] = p("70")
|
||||
i["autres_produits_exploit"] = p("71", "72", "74", "75", "781", "791")
|
||||
i["achats_charges_externes"] = s("60", "61", "62")
|
||||
i["impots_taxes"] = s("63")
|
||||
i["remuneration_dirigeant"] = s("641")
|
||||
i["charges_sociales"] = s("645", "646", "647", "648")
|
||||
i["dotations_amortissements"] = s("681")
|
||||
i["autres_charges_exploit"] = s("65")
|
||||
i["resultat_exploitation"] = (i["ca"] + i["autres_produits_exploit"] - i["achats_charges_externes"]
|
||||
- i["impots_taxes"] - s("64") - i["dotations_amortissements"]
|
||||
- i["autres_charges_exploit"])
|
||||
i["produits_financiers"] = p("76", "786", "796")
|
||||
i["charges_financieres"] = s("66", "686")
|
||||
i["resultat_financier"] = i["produits_financiers"] - i["charges_financieres"]
|
||||
i["resultat_exceptionnel"] = p("77", "787", "797") - s("67", "687")
|
||||
i["impot_societes"] = s("69")
|
||||
i["resultat_net"] = p("6", "7")
|
||||
# Soldes intermédiaires de gestion
|
||||
i["valeur_ajoutee"] = i["ca"] + p("71", "72") - i["achats_charges_externes"]
|
||||
i["ebe"] = i["valeur_ajoutee"] + p("74") - i["impots_taxes"] - s("64")
|
||||
i["caf"] = (i["resultat_net"] + s("68") - p("78") + s("675") - p("775"))
|
||||
# Bilan
|
||||
i["immobilisations_brutes"] = s("20", "21", "22", "23", "26", "27")
|
||||
i["amortissements_cumules"] = p("28", "29")
|
||||
i["actif_immobilise_net"] = i["immobilisations_brutes"] - i["amortissements_cumules"]
|
||||
i["creances"] = somme_signee(comptes, ("40", "41", "42", "43", "44", "45", "46", "47", "48"), True)
|
||||
i["vmp"] = s("50")
|
||||
i["disponibilites"] = somme_signee(comptes, ("51", "53"), True)
|
||||
i["total_actif"] = i["actif_immobilise_net"] + i["creances"] + i["vmp"] + i["disponibilites"]
|
||||
i["capitaux_propres"] = p("10", "11", "12", "13", "14") + i["resultat_net"]
|
||||
i["emprunts"] = p("16") + somme_signee(comptes, ("51",), False)
|
||||
i["dettes_fournisseurs"] = somme_signee(comptes, ("40",), False)
|
||||
i["dettes_fiscales_sociales"] = somme_signee(comptes, ("42", "43", "44"), False)
|
||||
i["compte_courant_associe"] = somme_signee(comptes, ("455",), False)
|
||||
i["autres_dettes"] = somme_signee(comptes, ("41", "45", "46", "47", "48"), False) - i["compte_courant_associe"]
|
||||
i["total_passif"] = (i["capitaux_propres"] + i["emprunts"] + i["dettes_fournisseurs"]
|
||||
+ i["dettes_fiscales_sociales"] + i["compte_courant_associe"] + i["autres_dettes"])
|
||||
i["tresorerie_nette"] = i["disponibilites"] + i["vmp"] - somme_signee(comptes, ("51",), False)
|
||||
i["fonds_de_roulement"] = i["capitaux_propres"] + p("16") - i["actif_immobilise_net"]
|
||||
i["bfr"] = i["creances"] - (i["dettes_fournisseurs"] + i["dettes_fiscales_sociales"]
|
||||
+ i["compte_courant_associe"] + i["autres_dettes"])
|
||||
return {k: round(v, 2) for k, v in i.items()}
|
||||
|
||||
|
||||
def ratios(i):
|
||||
def pct(a, b):
|
||||
return None if not b else round(100 * a / b, 1)
|
||||
return {
|
||||
"marge_nette": (pct(i["resultat_net"], i["ca"]), "résultat net / CA"),
|
||||
"taux_ebe": (pct(i["ebe"], i["ca"]), "EBE / CA"),
|
||||
"taux_valeur_ajoutee": (pct(i["valeur_ajoutee"], i["ca"]), "valeur ajoutée / CA"),
|
||||
"poids_charges_externes": (pct(i["achats_charges_externes"], i["ca"]), "achats et charges externes / CA"),
|
||||
"poids_remuneration": (pct(i["remuneration_dirigeant"] + i["charges_sociales"], i["ca"]),
|
||||
"(rémunération dirigeant + charges sociales) / CA"),
|
||||
"autonomie_financiere": (pct(i["capitaux_propres"], i["total_passif"]), "capitaux propres / total bilan"),
|
||||
"endettement": (pct(i["emprunts"], i["capitaux_propres"]), "emprunts et découverts / capitaux propres"),
|
||||
"liquidite_immediate": (pct(i["disponibilites"] + i["vmp"],
|
||||
i["dettes_fournisseurs"] + i["dettes_fiscales_sociales"] + i["autres_dettes"]),
|
||||
"(disponibilités + VMP) / dettes à court terme hors compte courant"),
|
||||
}
|
||||
|
||||
|
||||
LIBELLES = {
|
||||
"ca": "Chiffre d'affaires", "autres_produits_exploit": "Autres produits d'exploitation",
|
||||
"achats_charges_externes": "Achats et charges externes", "impots_taxes": "Impôts et taxes",
|
||||
"remuneration_dirigeant": "Rémunération du dirigeant", "charges_sociales": "Charges sociales",
|
||||
"dotations_amortissements": "Dotations aux amortissements", "autres_charges_exploit": "Autres charges d'exploitation",
|
||||
"resultat_exploitation": "Résultat d'exploitation", "produits_financiers": "Produits financiers",
|
||||
"charges_financieres": "Charges financières", "resultat_financier": "Résultat financier",
|
||||
"resultat_exceptionnel": "Résultat exceptionnel", "impot_societes": "Impôt sur les sociétés",
|
||||
"resultat_net": "Résultat net", "valeur_ajoutee": "Valeur ajoutée", "ebe": "EBE",
|
||||
"caf": "Capacité d'autofinancement", "immobilisations_brutes": "Immobilisations brutes",
|
||||
"amortissements_cumules": "Amortissements cumulés", "actif_immobilise_net": "Actif immobilisé net",
|
||||
"creances": "Créances", "vmp": "Valeurs mobilières de placement", "disponibilites": "Disponibilités",
|
||||
"total_actif": "Total bilan", "capitaux_propres": "Capitaux propres", "emprunts": "Emprunts et découverts",
|
||||
"dettes_fournisseurs": "Dettes fournisseurs", "dettes_fiscales_sociales": "Dettes fiscales et sociales",
|
||||
"compte_courant_associe": "Compte courant d'associé", "autres_dettes": "Autres dettes",
|
||||
"total_passif": "Total passif", "tresorerie_nette": "Trésorerie nette (dispo + VMP - découverts)",
|
||||
"fonds_de_roulement": "Fonds de roulement", "bfr": "Besoin en fonds de roulement",
|
||||
}
|
||||
NOMS_RATIOS = {"marge_nette": "Marge nette", "taux_ebe": "Taux d'EBE", "taux_valeur_ajoutee": "Taux de valeur ajoutée",
|
||||
"poids_charges_externes": "Poids des charges externes", "poids_remuneration": "Poids de la rémunération",
|
||||
"autonomie_financiere": "Autonomie financière", "endettement": "Endettement",
|
||||
"liquidite_immediate": "Liquidité immédiate"}
|
||||
ALIAS = {"chiffre_affaires": "ca", "chiffre": "ca", "resultat": "resultat_net", "benefice": "resultat_net",
|
||||
"tresorerie": "tresorerie_nette", "treso": "tresorerie_nette", "fr": "fonds_de_roulement",
|
||||
"remuneration": "remuneration_dirigeant", "salaire": "remuneration_dirigeant",
|
||||
"charges_externes": "achats_charges_externes", "cp": "capitaux_propres", "total_bilan": "total_actif",
|
||||
"va": "valeur_ajoutee", "amortissements": "dotations_amortissements", "dettes": "emprunts"}
|
||||
|
||||
|
||||
# ── Mise en forme ─────────────────────────────────────────────────────────────
|
||||
|
||||
def eur(v):
|
||||
if v is None:
|
||||
return "n.d."
|
||||
n = round(v)
|
||||
s = f"{abs(n):,}".replace(",", " ")
|
||||
return f"{'-' if n < 0 else ''}{s} €"
|
||||
|
||||
|
||||
def pc(v):
|
||||
return "n.d." if v is None else f"{v:.1f} %".replace(".", ",")
|
||||
|
||||
|
||||
def variation(a, b):
|
||||
"""Évolution de a (ancien) vers b (récent)."""
|
||||
d = b - a
|
||||
sgn = "+" if d >= 0 else "-"
|
||||
txt = f"{sgn}{eur(abs(d))}"
|
||||
if a and abs(a) >= 1:
|
||||
txt += f" ({sgn}{pc(abs(100 * d / a))})" if (a > 0) else ""
|
||||
return txt
|
||||
|
||||
|
||||
def exercice(data, an):
|
||||
if an is None:
|
||||
an = max(data["exercices"])
|
||||
an = str(an)
|
||||
if an not in data["exercices"]:
|
||||
sortir(f"Exercice {an} absent. Exercices disponibles : {', '.join(data['exercices'])} "
|
||||
f"(exercice N = du 01/10/N-1 au 30/09/N).")
|
||||
return an, data["exercices"][an]
|
||||
|
||||
|
||||
def entete(an, e):
|
||||
return f"AIRTRIA — exercice {an} (du {fr_date(e['debut'])} au {fr_date(e['fin'])})"
|
||||
|
||||
|
||||
def fr_date(iso):
|
||||
y, m, d = iso.split("-")
|
||||
return f"{d}/{m}/{y}"
|
||||
|
||||
|
||||
# ── Commandes ─────────────────────────────────────────────────────────────────
|
||||
|
||||
def cmd_liste(data, args):
|
||||
lignes = ["AIRTRIA — exercices disponibles (clôture au 30/09)", ""]
|
||||
for an, e in data["exercices"].items():
|
||||
i = indicateurs(e["comptes"])
|
||||
lignes.append(f"{an} : CA {eur(i['ca'])}, résultat {eur(i['resultat_net'])}"
|
||||
+ (" (*)" if "note" in e else ""))
|
||||
if any("note" in e for e in data["exercices"].values()):
|
||||
lignes += ["", "(*) remarque sur la source : voir « resume AN » ou « sources »."]
|
||||
return "\n".join(lignes)
|
||||
|
||||
|
||||
def cmd_resume(data, args):
|
||||
an, e = exercice(data, args[0] if args else None)
|
||||
i = indicateurs(e["comptes"])
|
||||
r = ratios(i)
|
||||
prec = data["exercices"].get(str(int(an) - 1))
|
||||
ip = indicateurs(prec["comptes"]) if prec else None
|
||||
vs = lambda k: f" ({variation(ip[k], i[k])} vs {int(an) - 1})" if ip else ""
|
||||
L = [entete(an, e), "",
|
||||
"ACTIVITÉ ET RÉSULTAT",
|
||||
f"- Chiffre d'affaires : {eur(i['ca'])}{vs('ca')}",
|
||||
f"- Achats et charges externes : {eur(i['achats_charges_externes'])}",
|
||||
f"- Impôts et taxes : {eur(i['impots_taxes'])}",
|
||||
f"- Rémunération dirigeant + charges sociales : {eur(i['remuneration_dirigeant'] + i['charges_sociales'])}",
|
||||
f"- EBE : {eur(i['ebe'])} ({pc(r['taux_ebe'][0])} du CA)",
|
||||
f"- Dotations aux amortissements : {eur(i['dotations_amortissements'])}",
|
||||
f"- Résultat d'exploitation : {eur(i['resultat_exploitation'])}",
|
||||
f"- Résultat financier : {eur(i['resultat_financier'])}",
|
||||
]
|
||||
if i["resultat_exceptionnel"]:
|
||||
L.append(f"- Résultat exceptionnel : {eur(i['resultat_exceptionnel'])}")
|
||||
if i["impot_societes"]:
|
||||
L.append(f"- Impôt sur les sociétés : {eur(i['impot_societes'])}")
|
||||
L += [f"- RÉSULTAT NET : {eur(i['resultat_net'])}{vs('resultat_net')}",
|
||||
f"- Capacité d'autofinancement : {eur(i['caf'])}",
|
||||
"",
|
||||
"BILAN AU " + fr_date(e["fin"]),
|
||||
f"- Actif immobilisé net : {eur(i['actif_immobilise_net'])}",
|
||||
f"- Disponibilités : {eur(i['disponibilites'])} ; placements (VMP) : {eur(i['vmp'])}",
|
||||
f"- Créances : {eur(i['creances'])}",
|
||||
f"- Capitaux propres : {eur(i['capitaux_propres'])}",
|
||||
f"- Emprunts et découverts : {eur(i['emprunts'])}",
|
||||
f"- Dettes fournisseurs, fiscales et sociales : {eur(i['dettes_fournisseurs'] + i['dettes_fiscales_sociales'])}",
|
||||
f"- Compte courant d'associé : {eur(i['compte_courant_associe'])}",
|
||||
f"- Total bilan : {eur(i['total_actif'])}",
|
||||
"",
|
||||
f"Marge nette {pc(r['marge_nette'][0])} · autonomie financière {pc(r['autonomie_financiere'][0])}"
|
||||
f" · trésorerie nette {eur(i['tresorerie_nette'])}",
|
||||
]
|
||||
off = e.get("officiel")
|
||||
if off:
|
||||
bits = [f"{lbl} {eur(off[k])}" for k, lbl in (("chiffre_affaires", "CA"), ("resultat_net", "résultat"),
|
||||
("total_bilan", "total bilan")) if k in off]
|
||||
L += ["", f"Chiffres officiels déposés : {', '.join(bits)}."]
|
||||
if "note" in e:
|
||||
L += ["", "Remarque : " + e["note"]]
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def cmd_compare(data, args):
|
||||
if len(args) != 2:
|
||||
sortir("Usage : bilans.py compare AN1 AN2")
|
||||
a1, e1 = exercice(data, min(args))
|
||||
a2, e2 = exercice(data, max(args))
|
||||
i1, i2 = indicateurs(e1["comptes"]), indicateurs(e2["comptes"])
|
||||
cles = ["ca", "achats_charges_externes", "impots_taxes", "remuneration_dirigeant", "charges_sociales",
|
||||
"ebe", "dotations_amortissements", "resultat_exploitation", "resultat_financier", "resultat_net",
|
||||
"caf", "disponibilites", "vmp", "capitaux_propres", "emprunts", "total_actif"]
|
||||
L = [f"AIRTRIA — comparaison des exercices {a1} et {a2}", ""]
|
||||
for k in cles:
|
||||
if i1[k] or i2[k]:
|
||||
L.append(f"- {LIBELLES[k]} : {eur(i1[k])} → {eur(i2[k])} ({variation(i1[k], i2[k])})")
|
||||
r1, r2 = ratios(i1), ratios(i2)
|
||||
L += ["", f"Marge nette : {pc(r1['marge_nette'][0])} → {pc(r2['marge_nette'][0])}",
|
||||
f"Autonomie financière : {pc(r1['autonomie_financiere'][0])} → {pc(r2['autonomie_financiere'][0])}"]
|
||||
for a, e in ((a1, e1), (a2, e2)):
|
||||
if "note" in e:
|
||||
L.append(f"Remarque {a} : {e['note']}")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def cmd_evolution(data, args):
|
||||
if not args:
|
||||
return ("Indicateurs disponibles pour « evolution » :\n"
|
||||
+ "\n".join(f"- {k} : {v}" for k, v in LIBELLES.items())
|
||||
+ "\nAlias acceptés : " + ", ".join(sorted(ALIAS)))
|
||||
k = args[0].lower().replace("-", "_").replace("'", "_")
|
||||
k = ALIAS.get(k, k)
|
||||
if k not in LIBELLES:
|
||||
sortir(f"Indicateur « {args[0]} » inconnu. Lance « bilans.py evolution » pour la liste.")
|
||||
serie = [(an, indicateurs(e["comptes"])[k]) for an, e in data["exercices"].items()]
|
||||
L = [f"AIRTRIA — {LIBELLES[k]} par exercice", ""]
|
||||
prev = None
|
||||
for an, v in serie:
|
||||
L.append(f"{an} : {eur(v)}" + (f" ({variation(prev, v)})" if prev is not None else ""))
|
||||
prev = v
|
||||
vals = [v for _, v in serie]
|
||||
hi = max(serie, key=lambda x: x[1])
|
||||
lo = min(serie, key=lambda x: x[1])
|
||||
L += ["", f"Plus haut : {hi[0]} ({eur(hi[1])}) · plus bas : {lo[0]} ({eur(lo[1])})"
|
||||
f" · moyenne : {eur(sum(vals) / len(vals))}"]
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def cmd_charges(data, args):
|
||||
an, e = exercice(data, args[0] if args else None)
|
||||
ch = [(n, c["lib"], c["solde"]) for n, c in e["comptes"].items() if n.startswith("6") and c["solde"]]
|
||||
ch.sort(key=lambda x: -x[2])
|
||||
tot = sum(x[2] for x in ch)
|
||||
ca = indicateurs(e["comptes"])["ca"]
|
||||
L = [entete(an, e), f"Charges : {eur(tot)} au total ({pc(100 * tot / ca if ca else None)} du CA)", ""]
|
||||
for n, lib, v in ch:
|
||||
L.append(f"- {n} {lib.capitalize()} : {eur(v)} ({pc(100 * v / tot)})")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def cmd_compte(data, args):
|
||||
if not args:
|
||||
sortir("Usage : bilans.py compte MOTIF [AN] (MOTIF = début de numéro, ex. 626, ou mot du libellé, ex. assurance)")
|
||||
motif = args[0].upper()
|
||||
ans = [str(args[1])] if len(args) > 1 else list(data["exercices"])
|
||||
for a in ans:
|
||||
exercice(data, a)
|
||||
trouves = {}
|
||||
for a in ans:
|
||||
for n, c in data["exercices"][a]["comptes"].items():
|
||||
if n.startswith(motif) or motif in c["lib"].upper():
|
||||
trouves.setdefault((n, c["lib"]), {})[a] = c
|
||||
if not trouves:
|
||||
return f"Aucun compte ne correspond à « {args[0]} » ({', '.join(ans) if len(ans) < 3 else 'tous exercices'})."
|
||||
L = [f"AIRTRIA — comptes correspondant à « {args[0]} »", ""]
|
||||
for (n, lib), par_an in sorted(trouves.items()):
|
||||
L.append(f"{n} {lib}")
|
||||
for a, c in par_an.items():
|
||||
sens = "débiteur" if c["solde"] > 0 else "créditeur" if c["solde"] < 0 else "soldé"
|
||||
L.append(f" {a} : solde {eur(abs(c['solde']))} {sens} (débit {eur(c['debit'])}, crédit {eur(c['credit'])})")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def cmd_ratios(data, args):
|
||||
an, e = exercice(data, args[0] if args else None)
|
||||
i = indicateurs(e["comptes"])
|
||||
L = [entete(an, e), ""]
|
||||
for k, (v, formule) in ratios(i).items():
|
||||
L.append(f"- {NOMS_RATIOS[k]} : {pc(v)} [{formule}]")
|
||||
L += [f"- Fonds de roulement : {eur(i['fonds_de_roulement'])} [capitaux propres + emprunts - actif immobilisé net]",
|
||||
f"- BFR : {eur(i['bfr'])} [créances - dettes d'exploitation et compte courant]",
|
||||
f"- Trésorerie nette : {eur(i['tresorerie_nette'])}"]
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
def cmd_sources(data, args):
|
||||
L = [f"Données générées le {data['genere_le']} depuis /mnt/gestion/BILAN.",
|
||||
data["societe"]["exercice"], ""]
|
||||
for c in data["controles"]:
|
||||
an = str(c["exercice"])
|
||||
e = data["exercices"][an]
|
||||
etat = []
|
||||
if c["resultat_officiel"] is not None:
|
||||
etat.append(f"liasse/PV {eur(c['resultat_officiel'])} {'OK' if c['ok_officiel'] else 'ÉCART'}")
|
||||
if c["resultat_repris_n_plus_1"] is not None:
|
||||
etat.append(f"repris en {int(an) + 1} : {eur(c['resultat_repris_n_plus_1'])}"
|
||||
f" {'OK' if c['ok_report'] else 'ÉCART'}")
|
||||
L.append(f"{an} : résultat {eur(c['resultat_calcule'])} — {'; '.join(etat) or 'pas de contrôle externe'}")
|
||||
L.append(f" source : {e['source']}")
|
||||
if "note" in e:
|
||||
L.append(f" remarque : {e['note']}")
|
||||
return "\n".join(L)
|
||||
|
||||
|
||||
COMMANDES = {"liste": cmd_liste, "resume": cmd_resume, "compare": cmd_compare, "evolution": cmd_evolution,
|
||||
"charges": cmd_charges, "compte": cmd_compte, "ratios": cmd_ratios, "sources": cmd_sources}
|
||||
|
||||
|
||||
def main(argv):
|
||||
as_json = "--json" in argv
|
||||
argv = [a for a in argv if a != "--json"]
|
||||
if not argv or argv[0] in ("-h", "--help", "aide"):
|
||||
print(__doc__.strip())
|
||||
return 0
|
||||
cmd, args = argv[0].lower(), argv[1:]
|
||||
if cmd not in COMMANDES:
|
||||
sortir(f"Commande « {cmd} » inconnue. Commandes : {', '.join(COMMANDES)}.")
|
||||
data = charger()
|
||||
if as_json:
|
||||
ans = [a for a in args if a.isdigit()] or list(data["exercices"])
|
||||
out = {a: {"indicateurs": indicateurs(data["exercices"][a]["comptes"]),
|
||||
"ratios": {k: v for k, (v, _) in ratios(indicateurs(data["exercices"][a]["comptes"])).items()}}
|
||||
for a in ans if a in data["exercices"]}
|
||||
print(json.dumps(out, ensure_ascii=False, indent=1))
|
||||
return 0
|
||||
print(COMMANDES[cmd](data, args))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
Reference in New Issue
Block a user