"""Punct de intrare: de la contractul intern la xlsx-ul de import ROA. Citeste balanta_.csv, aplica maparea (mapare.py) si scrie: init___.xlsx - xlsx-ul de import mapare_.xlsx - propunerea completa (doar unealta scrie) corectii_.xlsx - creat gol la prima rulare a firmei docs/verificare_.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_.xlsx (docs/decizii_import.md pct. 16). Randurile de diferenta raman calculate in cod. Daca exista parteneri_.csv / facturi_.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_.csv din --dir") parser.add_argument("--dir", default="date", help="de unde se citeste balanta (implicit date/)") parser.add_argument("--dir-iesire", dest="dir_iesire", default="iesiri", help="unde se scriu xlsx-urile (implicit iesiri/)") a = parser.parse_args() os.makedirs(a.dir, exist_ok=True) os.makedirs(a.dir_iesire, 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, # drumul FDB (exista parteneri_): postarile direct pe sintetic raman brute brut=os.path.exists(os.path.join(a.dir, "parteneri_%s.csv" % a.firma))) xlsx_path = os.path.join(a.dir_iesire, "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=a.dir_iesire) 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_iesire, "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()