import html import json import logging import oracledb from datetime import datetime, timedelta from .. import database logger = logging.getLogger(__name__) # Diacritics to ASCII mapping (Romanian) _DIACRITICS = str.maketrans({ '\u0103': 'a', # ă '\u00e2': 'a', # â '\u00ee': 'i', # î '\u0219': 's', # ș '\u021b': 't', # ț '\u0102': 'A', # Ă '\u00c2': 'A', # Â '\u00ce': 'I', # Î '\u0218': 'S', # Ș '\u021a': 'T', # Ț # Older Unicode variants '\u015f': 's', # ş (cedilla) '\u0163': 't', # ţ (cedilla) '\u015e': 'S', # Ş '\u0162': 'T', # Ţ }) def clean_web_text(text: str) -> str: """Port of VFP CleanWebText: unescape HTML entities + diacritics to ASCII.""" if not text: return "" result = html.unescape(text) result = result.translate(_DIACRITICS) # Remove any remaining
tags for br in ('
', '
', '
'): result = result.replace(br, ' ') return result.strip() def convert_web_date(date_str: str) -> datetime: """Port of VFP ConvertWebDate: parse web date to datetime.""" if not date_str: return datetime.now() try: return datetime.strptime(date_str[:10], '%Y-%m-%d') except ValueError: return datetime.now() def format_address_for_oracle(address: str, city: str, region: str) -> str: """Port of VFP FormatAddressForOracle.""" region_clean = clean_web_text(region) city_clean = clean_web_text(city) address_clean = clean_web_text(address) return f"JUD:{region_clean};{city_clean};{address_clean}" def build_articles_json(items) -> str: """Build JSON string for Oracle PACK_IMPORT_COMENZI.importa_comanda.""" articles = [] for item in items: articles.append({ "sku": item.sku, "quantity": str(item.quantity), "price": str(item.price), "vat": str(item.vat), "name": clean_web_text(item.name) }) return json.dumps(articles) def import_single_order(order, id_pol: int = None, id_sectie: int = None) -> dict: """Import a single order into Oracle ROA. Returns dict with: success: bool id_comanda: int or None id_partener: int or None error: str or None """ result = { "success": False, "id_comanda": None, "id_partener": None, "error": None } try: order_number = clean_web_text(order.number) order_date = convert_web_date(order.date) if database.pool is None: raise RuntimeError("Oracle pool not initialized") with database.pool.acquire() as conn: with conn.cursor() as cur: # Step 1: Process partner id_partener = cur.var(oracledb.DB_TYPE_NUMBER) if order.billing.is_company: denumire = clean_web_text(order.billing.company_name) cod_fiscal = clean_web_text(order.billing.company_code) or None registru = clean_web_text(order.billing.company_reg) or None is_pj = 1 else: denumire = clean_web_text( f"{order.billing.firstname} {order.billing.lastname}" ) cod_fiscal = None registru = None is_pj = 0 cur.callproc("PACK_IMPORT_PARTENERI.cauta_sau_creeaza_partener", [ cod_fiscal, denumire, registru, is_pj, id_partener ]) partner_id = id_partener.getvalue() if not partner_id or partner_id <= 0: result["error"] = f"Partner creation failed for {denumire}" return result result["id_partener"] = int(partner_id) # Step 2: Process billing address id_adresa_fact = cur.var(oracledb.DB_TYPE_NUMBER) billing_addr = format_address_for_oracle( order.billing.address, order.billing.city, order.billing.region ) cur.callproc("PACK_IMPORT_PARTENERI.cauta_sau_creeaza_adresa", [ partner_id, billing_addr, order.billing.phone or "", order.billing.email or "", id_adresa_fact ]) addr_fact_id = id_adresa_fact.getvalue() # Step 3: Process shipping address (if different) addr_livr_id = None if order.shipping: id_adresa_livr = cur.var(oracledb.DB_TYPE_NUMBER) shipping_addr = format_address_for_oracle( order.shipping.address, order.shipping.city, order.shipping.region ) cur.callproc("PACK_IMPORT_PARTENERI.cauta_sau_creeaza_adresa", [ partner_id, shipping_addr, order.shipping.phone or "", order.shipping.email or "", id_adresa_livr ]) addr_livr_id = id_adresa_livr.getvalue() # Step 4: Build articles JSON and import order articles_json = build_articles_json(order.items) # Use CLOB for the JSON clob_var = cur.var(oracledb.DB_TYPE_CLOB) clob_var.setvalue(0, articles_json) id_comanda = cur.var(oracledb.DB_TYPE_NUMBER) cur.callproc("PACK_IMPORT_COMENZI.importa_comanda", [ order_number, # p_nr_comanda_ext order_date, # p_data_comanda partner_id, # p_id_partener clob_var, # p_json_articole (CLOB) addr_livr_id, # p_id_adresa_livrare addr_fact_id, # p_id_adresa_facturare id_pol, # p_id_pol id_sectie, # p_id_sectie id_comanda # v_id_comanda (OUT) ]) comanda_id = id_comanda.getvalue() if comanda_id and comanda_id > 0: conn.commit() result["success"] = True result["id_comanda"] = int(comanda_id) logger.info(f"Order {order_number} imported: ID={comanda_id}") else: conn.rollback() result["error"] = "importa_comanda returned invalid ID" except oracledb.DatabaseError as e: error_msg = str(e) result["error"] = error_msg logger.error(f"Oracle error importing order {order.number}: {error_msg}") except Exception as e: result["error"] = str(e) logger.error(f"Error importing order {order.number}: {e}") return result