Lane integrare: extrage.py si genereaza.py cu parametri, maparea legata
Firmele si lunile nu mai sunt hardcodate. extrage.py dispecerizeaza catre cele trei cititoare (pdf / xlsx / fdb, dedus din extensie, extensie necunoscuta = eroare) si scrie contractul intern; genereaza.py aplica maparea si scrie init_<FIRMA>_<an>_<luna>.xlsx plus mapare_<FIRMA>.xlsx. genereaza_xlsx.py devine biblioteca: an/luna parametri, data si scadenta calculate din ele, sablonul cautat langa script. Cand exista parteneri_ si facturi_ (drumul FDB) se emite cate un FACTURA per document, cu cod fiscal real, si numai daca suma documentelor da netul contului; altfel ramane comportamentul de azi, un FACTURA agregat. Corectat in orchestrare: la redenumirea unui cont cu parteneri, generatorul lua primul analitic ca sa afle contul sintetic. Daca analiticele erau mapate pe conturi diferite, BALANTA agregat si randurile FACTURA cadeau pe conturi diferite, tacut. Acum se opreste cu eroare; colapsarea pe acelasi cont ramane legala. Doua teste acopera ambele cazuri. 29 de teste trec, inclusiv regresia pe etalon cu generatorul modificat. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
This commit is contained in:
123
genereaza.py
Normal file
123
genereaza.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""Punct de intrare: de la contractul intern la xlsx-ul de import ROA.
|
||||
|
||||
Citeste balanta_<FIRMA>.csv, aplica maparea (mapare.py) si scrie:
|
||||
init_<FIRMA>_<an>_<luna>.xlsx - xlsx-ul de import
|
||||
mapare_<FIRMA>.xlsx - propunerea completa (doar unealta scrie)
|
||||
corectii_<FIRMA>.xlsx - creat gol la prima rulare a firmei
|
||||
docs/verificare_<FIRMA>.md - verificarile obligatorii
|
||||
|
||||
Maparea hotaraste cont/acont pentru conturile obisnuite. La conturile cu parteneri
|
||||
forma lui acont ramane a generatorului: maparea suprascrie doar ce i se da explicit
|
||||
in corectii_<FIRMA>.xlsx (docs/decizii_import.md pct. 16). Randurile de diferenta
|
||||
raman calculate in cod.
|
||||
|
||||
Daca exista parteneri_<FIRMA>.csv / facturi_<FIRMA>.csv (drumul FDB), se folosesc:
|
||||
cod fiscal real si un rand FACTURA per document. Lipsa lor = comportamentul de azi
|
||||
(un FACTURA per partener, sold total).
|
||||
|
||||
Utilizare:
|
||||
py genereaza.py --firma FIRMA --an 2025 --luna 12 [--balanta balanta_FIRMA.csv]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
import os
|
||||
|
||||
import genereaza_xlsx as generator
|
||||
import mapare
|
||||
|
||||
|
||||
def _citeste_csv(path):
|
||||
if not os.path.exists(path):
|
||||
return []
|
||||
with open(path, encoding="utf-8-sig", newline="") as f:
|
||||
return list(csv.DictReader(f))
|
||||
|
||||
|
||||
def _mapare_si_exclusi(rezultat):
|
||||
"""{cont_saga: {cont, acont}} pentru corectiile explicite + multimea exclusilor."""
|
||||
override = {}
|
||||
exclusi = set()
|
||||
for r in rezultat:
|
||||
if r["exclus"]:
|
||||
exclusi.add(r["cont_saga"])
|
||||
elif r["sursa"] == mapare.SURSA_CORECTAT:
|
||||
override[r["cont_saga"]] = {"cont": r["cont"], "acont": r["acont"]}
|
||||
return override, exclusi
|
||||
|
||||
|
||||
def _fara_exclusi(rows, exclusi):
|
||||
"""Un cont exclus iese cu tot cu subarborele lui (un parinte fara copii ar rupe arborele)."""
|
||||
if not exclusi:
|
||||
return rows
|
||||
out = []
|
||||
for r in rows:
|
||||
c = r["cont"]
|
||||
if any(c == e or c.startswith(e + ".") for e in exclusi):
|
||||
continue
|
||||
out.append(r)
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--firma", required=True)
|
||||
parser.add_argument("--an", type=int, required=True)
|
||||
parser.add_argument("--luna", type=int, required=True)
|
||||
parser.add_argument("--balanta",
|
||||
help="implicit balanta_<FIRMA>.csv din --dir")
|
||||
parser.add_argument("--dir", default=".", help="directorul de iesire")
|
||||
a = parser.parse_args()
|
||||
|
||||
os.makedirs(a.dir, exist_ok=True)
|
||||
balanta = a.balanta or os.path.join(a.dir, "balanta_%s.csv" % a.firma)
|
||||
if not os.path.exists(balanta):
|
||||
raise SystemExit("lipseste balanta: %s" % balanta)
|
||||
|
||||
header = generator.citeste_header()
|
||||
if len(header) != 39:
|
||||
raise SystemExit("cap de tabel neasteptat: %d coloane" % len(header))
|
||||
rows = generator.citeste_balanta(balanta)
|
||||
|
||||
rezultat = mapare.genereaza_mapare(rows, a.firma, a.dir)
|
||||
override, exclusi = _mapare_si_exclusi(rezultat)
|
||||
rows = _fara_exclusi(rows, exclusi)
|
||||
|
||||
parteneri = _citeste_csv(os.path.join(a.dir, "parteneri_%s.csv" % a.firma))
|
||||
facturi = _citeste_csv(os.path.join(a.dir, "facturi_%s.csv" % a.firma))
|
||||
|
||||
out, diffs, leaf_map, leaf_rep, negative = generator.genereaza(
|
||||
rows, header, an=a.an, luna=a.luna, mapare=override,
|
||||
parteneri=parteneri, facturi=facturi)
|
||||
|
||||
xlsx_path = os.path.join(a.dir, "init_%s_%d_%d.xlsx"
|
||||
% (a.firma, a.an, a.luna))
|
||||
generator.scrie_xlsx(header, out, xlsx_path)
|
||||
rez = generator.verifica(a.firma, balanta, xlsx_path, rows, out, diffs,
|
||||
leaf_map, leaf_rep, negative, header,
|
||||
dir_verificare=os.path.join(a.dir, "docs"))
|
||||
|
||||
print("=== %s ===" % a.firma)
|
||||
print(" rows: %d totdeb=%s totcred=%s net=%s"
|
||||
% (len(out), rez["totdeb"], rez["totcred"], rez["net"]))
|
||||
print(" balanta=%s frunze=%s parteneri=%s lungimi=%s"
|
||||
% ("OK" if rez["bal"] else "ESEC",
|
||||
"OK" if rez["leaves"] else "ESEC",
|
||||
"OK" if rez["part"] else "ESEC",
|
||||
"OK" if rez["lung"] else "ESEC"))
|
||||
print(" scris %s si %s" % (xlsx_path,
|
||||
os.path.join(a.dir, "docs",
|
||||
"verificare_%s.md" % a.firma)))
|
||||
if rez["negative"]:
|
||||
print(" analitice cu semn negativ: %s" % (rez["negative"],))
|
||||
if rez["pierdute"] or rez["dubluri_leaf"] or rez["dubluri_bal"] or rez["lungimi"]:
|
||||
print(" ATENTIE: %s %s %s %s"
|
||||
% (rez["pierdute"], rez["dubluri_leaf"], rez["dubluri_bal"],
|
||||
rez["lungimi"]))
|
||||
|
||||
toate = rez["bal"] and rez["leaves"] and rez["part"] and rez["lung"]
|
||||
raise SystemExit(0 if toate else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user