- US-001: mută queue_client.py în data_entry/services/ocr/ - US-002/003/004: oracle_receipt_writer + oracle_server_id în DB - US-005: receipt_handlers.py (PDF/photo/callback flow) - US-006: wire handlers în main.py, per-schema connect, seq_cod.nextval - US-007: .gitignore secrets/*.oracle_pass - US-008/009/010: teste unit + integration + E2E - setup-secrets.sh helper + template - docs/telegram/README.md actualizat cu arhitectura nouă Testat E2E pe DB live (MARIUSM_AUTO). COD din seq_cod.nextval. pypdfium2 fallback pentru PDF decode (fără poppler). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
"""Shared helper for writing receipts to Oracle via PACK_CONTAFIN."""
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
import oracledb
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_CUI_TO_CONT = {
|
|
"11201891": "6022", # MOL
|
|
"1590082": "6022", # OMV Petrom
|
|
"14991381": "6022", # MOL Romania
|
|
"10562600": "6021", # Dedeman
|
|
}
|
|
|
|
|
|
def _get_cont_cheltuiala(cui: str) -> str:
|
|
cui_clean = cui.upper().replace("RO", "").strip()
|
|
return _CUI_TO_CONT.get(cui_clean, "6028")
|
|
|
|
|
|
def _build_conn_params(oracle_cfg) -> dict:
|
|
if isinstance(oracle_cfg, dict):
|
|
return oracle_cfg
|
|
return {
|
|
"user": oracle_cfg.user,
|
|
"password": oracle_cfg.password,
|
|
"dsn": oracle_cfg.get_dsn(),
|
|
}
|
|
|
|
|
|
def write_receipt(receipt_dict: dict, oracle_cfg, *, commit: bool = True) -> tuple[int, str]:
|
|
"""Write a receipt to Oracle ACT_TEMP via PACK_CONTAFIN.
|
|
|
|
Args:
|
|
receipt_dict: Keys: partner_name, cui, receipt_date, receipt_number, amount, tva_total
|
|
oracle_cfg: Dict with user/password/dsn, OracleServerConfig instance, or
|
|
oracledb.Connection (pre-acquired from pool — caller manages lifecycle)
|
|
commit: If False, rolls back after FINALIZEAZA (dry-run mode)
|
|
|
|
Returns:
|
|
(cod, mesaj) — Oracle document code and result message from PACK_CONTAFIN
|
|
"""
|
|
if isinstance(oracle_cfg, oracledb.Connection):
|
|
conn = oracle_cfg
|
|
own_conn = False
|
|
else:
|
|
conn_params = _build_conn_params(oracle_cfg)
|
|
conn = oracledb.connect(**conn_params)
|
|
own_conn = True
|
|
cursor = conn.cursor()
|
|
|
|
try:
|
|
receipt_date = receipt_dict.get("receipt_date")
|
|
_now = datetime.now()
|
|
an = receipt_date.year if receipt_date else _now.year
|
|
luna = receipt_date.month if receipt_date else _now.month
|
|
act_date = receipt_date or _now.date()
|
|
|
|
id_util = 0
|
|
id_sucursala = 0
|
|
|
|
cursor.callproc("PACK_CONTAFIN.INITIALIZEAZA_SCRIERE_ACT_RUL", [
|
|
id_util,
|
|
datetime.now(),
|
|
an,
|
|
luna,
|
|
0, # suprascriere_cod
|
|
0, # suprascriere_anluna
|
|
0, # scrie_sterge (0=scrie)
|
|
id_sucursala,
|
|
])
|
|
|
|
# Globally unique document COD from sequence (NOT MAX+1 per period —
|
|
# that races and reuses CODs across (AN, LUNA) tuples).
|
|
cursor.execute("SELECT seq_cod.nextval FROM DUAL")
|
|
cod = cursor.fetchone()[0]
|
|
|
|
cui = receipt_dict.get("cui") or ""
|
|
cui_clean = cui.upper().replace("RO", "").strip()
|
|
cursor.execute(
|
|
"SELECT ID_PART FROM NOM_PARTENERI WHERE COD_FISCAL = :cui OR COD_FISCAL = :cui2",
|
|
cui=cui_clean, cui2="RO" + cui_clean,
|
|
)
|
|
row = cursor.fetchone()
|
|
id_part = row[0] if row else 0
|
|
|
|
total = float(receipt_dict.get("amount") or 0)
|
|
tva = float(receipt_dict.get("tva_total") or 0)
|
|
fara_tva = total - tva
|
|
receipt_number = str(receipt_dict.get("receipt_number") or "")
|
|
nract = int(receipt_number) if receipt_number.isdigit() else 0
|
|
cont = _get_cont_cheltuiala(cui)
|
|
partner_name = receipt_dict.get("partner_name") or "N/A"
|
|
expl = f"OCR: {partner_name}"
|
|
|
|
lines = [
|
|
(cont, "401", fara_tva, expl, id_part, 0),
|
|
("401", "5311", total, f"Plata {expl}", 0, id_part),
|
|
]
|
|
if tva > 0:
|
|
lines.insert(1, ("4426", "401", tva, f"TVA {expl}", id_part, 0))
|
|
|
|
for scd, scc, suma, e, id_partc, id_partd in lines:
|
|
cursor.execute("""
|
|
INSERT INTO ACT_TEMP (
|
|
LUNA, AN, COD, DATAIREG, DATAACT, NRACT,
|
|
EXPLICATIA, SCD, SCC, SUMA,
|
|
ID_PARTC, ID_PARTD, ID_UTIL, DATAORA
|
|
) VALUES (
|
|
:luna, :an, :cod, TRUNC(SYSDATE), :dataact, :nract,
|
|
:expl, :scd, :scc, :suma,
|
|
:id_partc, :id_partd, :id_util, SYSDATE
|
|
)
|
|
""", luna=luna, an=an, cod=cod, dataact=act_date, nract=nract,
|
|
expl=e, scd=scd, scc=scc, suma=suma,
|
|
id_partc=id_partc, id_partd=id_partd, id_util=id_util)
|
|
|
|
mesaj_var = cursor.var(oracledb.STRING, 4000)
|
|
cursor.callproc("PACK_CONTAFIN.FINALIZEAZA_SCRIERE_ACT_RUL", [
|
|
id_util,
|
|
cod,
|
|
0, # scrie_sterge
|
|
0, # modificare_nota
|
|
0, # scrie_cump_vanz
|
|
mesaj_var,
|
|
])
|
|
mesaj = mesaj_var.getvalue() or ""
|
|
|
|
if commit:
|
|
conn.commit()
|
|
logger.info("write_receipt: saved COD=%s mesaj=%r", cod, mesaj)
|
|
else:
|
|
conn.rollback()
|
|
logger.info("write_receipt: dry-run rollback COD would be %s", cod)
|
|
|
|
return cod, mesaj
|
|
|
|
except Exception:
|
|
conn.rollback()
|
|
raise
|
|
finally:
|
|
cursor.close()
|
|
if own_conn:
|
|
conn.close()
|