diff --git a/api/app/database.py b/api/app/database.py index 80eb869..77dd0c9 100644 --- a/api/app/database.py +++ b/api/app/database.py @@ -1,12 +1,8 @@ import oracledb import aiosqlite import sqlite3 -import json -import re -import unicodedata import logging import os -from pathlib import Path from .config import settings logger = logging.getLogger(__name__) @@ -375,33 +371,7 @@ def init_sqlite(): def _backfill_address_mismatch(conn): """Recompute address_mismatch from stored address JSON for all orders.""" - _ADDR_WORDS = re.compile( - r'\b(STR|STRADA|NR|NUMAR|NUMARUL|BL|BLOC|SC|SCARA|AP|APART|APARTAMENT|' - r'ET|ETAJ|COM|COMUNA|SAT|MUN|MUNICIPIUL|JUD|JUDETUL|CARTIER|PARTER|SECTOR|ORAS)\b' - ) - - def norm(s): - s = unicodedata.normalize('NFD', s or '') - s = re.sub(r'[\u0300-\u036f]', '', s).upper() - s = _ADDR_WORDS.sub('', s) - return re.sub(r'[^A-Z0-9]', '', s) - - def addr_match(gomag_json, roa_json): - if not gomag_json or not roa_json: - return True - try: - g = json.loads(gomag_json) if isinstance(gomag_json, str) else gomag_json - r = json.loads(roa_json) if isinstance(roa_json, str) else roa_json - except (json.JSONDecodeError, TypeError): - return True - g_street = norm(g.get('address') or g.get('strada') or '') - r_street = norm((r.get('strada') or '') + (r.get('numar') or '')) - g_city = norm(g.get('city') or g.get('localitate') or '') - r_city = norm(r.get('localitate') or '') - g_region = norm(g.get('region') or g.get('judet') or '') - r_region = norm(r.get('judet') or '') - return g_street == r_street and g_city == r_city and g_region == r_region - + from .services.sync_service import _addr_match try: rows = conn.execute(""" SELECT order_number, adresa_livrare_gomag, adresa_livrare_roa, @@ -411,8 +381,8 @@ def _backfill_address_mismatch(conn): """).fetchall() updated = 0 for r in rows: - livr_ok = addr_match(r[1], r[2]) - fact_ok = addr_match(r[3], r[4]) + livr_ok = _addr_match(r[1], r[2]) + fact_ok = _addr_match(r[3], r[4]) new_val = 1 if (not livr_ok or not fact_ok) else 0 conn.execute( "UPDATE orders SET address_mismatch = ? WHERE order_number = ?", diff --git a/api/app/services/import_service.py b/api/app/services/import_service.py index ca5c932..020a3fa 100644 --- a/api/app/services/import_service.py +++ b/api/app/services/import_service.py @@ -338,28 +338,32 @@ def import_single_order(order, id_pol: int = None, id_sectie: int = None, app_se # Different person: use shipping address for BOTH billing and shipping in ROA addr_fact_id = addr_livr_id else: - # Same person: use billing address as-is - id_adresa_fact = cur.var(oracledb.DB_TYPE_NUMBER) + # Same person: compute billing addr, short-circuit if identical to shipping 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() + if addr_livr_id and order.shipping and billing_addr == shipping_addr: + # billing = shipping: reuse addr_livr_id to avoid duplicate Oracle address + addr_fact_id = addr_livr_id + else: + id_adresa_fact = cur.var(oracledb.DB_TYPE_NUMBER) + 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() - if addr_fact_id is None: - cur.execute("SELECT PACK_IMPORT_PARTENERI.get_last_error FROM dual") - plsql_err = cur.fetchone()[0] - err_msg = f"Billing address creation failed for partner {partner_id}" - if plsql_err: - err_msg += f": {plsql_err}" - logger.error(f"Order {order_number}: {err_msg}") - result["error"] = err_msg - return result + if addr_fact_id is None: + cur.execute("SELECT PACK_IMPORT_PARTENERI.get_last_error FROM dual") + plsql_err = cur.fetchone()[0] + err_msg = f"Billing address creation failed for partner {partner_id}" + if plsql_err: + err_msg += f": {plsql_err}" + logger.error(f"Order {order_number}: {err_msg}") + result["error"] = err_msg + return result if addr_fact_id is not None: result["id_adresa_facturare"] = int(addr_fact_id) diff --git a/api/app/services/sync_service.py b/api/app/services/sync_service.py index 57bc739..b6c7e31 100644 --- a/api/app/services/sync_service.py +++ b/api/app/services/sync_service.py @@ -31,8 +31,9 @@ def _addr_match(gomag_json, roa_json): except (json.JSONDecodeError, TypeError): return True _ADDR_WORDS = re.compile( - r'\b(STR|STRADA|NR|NUMAR|NUMARUL|BL|BLOC|SC|SCARA|AP|APART|APARTAMENT|' - r'ET|ETAJ|COM|COMUNA|SAT|MUN|MUNICIPIUL|JUD|JUDETUL|CARTIER|PARTER|SECTOR|ORAS)\b' + r'\bSECTORUL\s*\d*' + r'|\b(STR|STRADA|NR|NUMAR|NUMARUL|BL|BLOC|SC|SCARA|AP|APART|APARTAMENT|' + r'ET|ETAJ|COM|COMUNA|SAT|MUN|MUNICIPIUL|JUD|JUDETUL|CARTIER|PARTER|SECTOR|SECTORUL|ORAS)(?:\b|(?=\d))' ) def norm(s): s = unicodedata.normalize('NFD', s or '') @@ -40,7 +41,7 @@ def _addr_match(gomag_json, roa_json): s = _ADDR_WORDS.sub('', s) return re.sub(r'[^A-Z0-9]', '', s) g_street = norm(g.get('address') or g.get('strada') or '') - r_street = norm((r.get('strada') or '') + (r.get('numar') or '') + (r.get('bloc') or '') + (r.get('scara') or '') + (r.get('apart') or '')) + r_street = norm((r.get('strada') or '') + (r.get('numar') or '') + (r.get('bloc') or '') + (r.get('scara') or '') + (r.get('apart') or '') + (r.get('etaj') or '')) g_city = norm(g.get('city') or g.get('localitate') or '') r_city = norm(r.get('localitate') or '') g_region = norm(g.get('region') or g.get('judet') or '') diff --git a/api/app/static/js/shared.js b/api/app/static/js/shared.js index 72cebe1..0a4829d 100644 --- a/api/app/static/js/shared.js +++ b/api/app/static/js/shared.js @@ -850,11 +850,11 @@ function addrMatch(gomag, roa) { function norm(s) { return (s || '').normalize('NFD').replace(/[\u0300-\u036f]/g, '') .toUpperCase() - .replace(/\b(STR|STRADA|NR|NUMAR|NUMARUL|BL|BLOC|SC|SCARA|AP|APART|APARTAMENT|ET|ETAJ|COM|COMUNA|SAT|MUN|MUNICIPIUL|JUD|JUDETUL|CARTIER|PARTER|SECTOR|ORAS)\b/g, '') + .replace(/\b(STR|STRADA|NR|NUMAR|NUMARUL|BL|BLOC|SC|SCARA|AP|APART|APARTAMENT|ET|ETAJ|COM|COMUNA|SAT|MUN|MUNICIPIUL|JUD|JUDETUL|CARTIER|PARTER|SECTOR|SECTORUL|ORAS)(?:\b|(?=\d))/g, '') .replace(/[^A-Z0-9]/g, ''); } const gStreet = norm(gomag.address || gomag.strada || ''); - const rStreet = norm((roa.strada||'') + (roa.numar||'') + (roa.bloc||'') + (roa.scara||'') + (roa.apart||'')); + const rStreet = norm((roa.strada||'') + (roa.numar||'') + (roa.bloc||'') + (roa.scara||'') + (roa.apart||'') + (roa.etaj||'')); const gCity = norm(gomag.city || gomag.localitate || ''); const rCity = norm(roa.localitate || ''); const gRegion = norm(gomag.region || gomag.judet || ''); diff --git a/api/app/templates/base.html b/api/app/templates/base.html index 03aa49d..f70c6dd 100644 --- a/api/app/templates/base.html +++ b/api/app/templates/base.html @@ -168,7 +168,7 @@ - +