feat(address): ROA address cache refresh — 8-field format + manual refresh endpoint
Phase 5 address format upgrade (pre-existing working tree changes):
- import_service: extend vadrese_parteneri query to 8 fields (strada/numar/bloc/scara/apart/etaj/localitate/judet); strip trailing city name from address string passed to Oracle
- sync_service: extend _addr_match to compare bloc/scara/apart in addition to strada/numar
- 05_pack_import_parteneri.pck: updated PL/SQL package
New: address cache refresh mechanism:
- sqlite_service: add get_order_address_ids(), update_order_address_cache() (targeted 3-column update, no ANAF fields touched), get_orders_with_address_ids()
- sync.py: POST /api/orders/{order_number}/refresh-address endpoint (404/422/503/200); batch Oracle address refresh in refresh_invoices (single IN roundtrip, per-order mismatch recomputed)
- UI: refresh button (⟳) in ADRESE modal header (base.html); refreshOrderAddress() with loading state + toast (dashboard.js v43); window._detailOrderNumber global (shared.js v32)
- tests: TestRefreshOrderAddress — 4 tests (404, 422, 503, 200 with 8-field assert)
Oracle prod fix applied directly: ADRESE_PARTENERI id_adresa=4116 STRADA VASILE→VASILE GOLDIS
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,14 @@ def format_address_for_oracle(address: str, city: str, region: str) -> str:
|
||||
region_clean = clean_web_text(region)
|
||||
city_clean = clean_web_text(city)
|
||||
address_clean = clean_web_text(address)
|
||||
# Strip city name from end of address (users often type it)
|
||||
if city_clean:
|
||||
addr_upper = address_clean.upper().rstrip()
|
||||
city_upper = city_clean.upper().strip()
|
||||
if addr_upper.endswith(city_upper):
|
||||
stripped = address_clean[:len(address_clean.rstrip()) - len(city_upper)].rstrip()
|
||||
if stripped: # don't strip if nothing remains
|
||||
address_clean = stripped
|
||||
return f"JUD:{region_clean};{city_clean};{address_clean}"
|
||||
|
||||
|
||||
@@ -360,13 +368,21 @@ def import_single_order(order, id_pol: int = None, id_sectie: int = None, app_se
|
||||
|
||||
# Query address details from Oracle for sync back to SQLite
|
||||
if addr_livr_id:
|
||||
cur.execute("SELECT strada, numar, localitate, judet FROM vadrese_parteneri WHERE id_adresa = :1", [int(addr_livr_id)])
|
||||
cur.execute("""SELECT strada, numar, bloc, scara, apart, etaj, localitate, judet
|
||||
FROM vadrese_parteneri WHERE id_adresa = :1""", [int(addr_livr_id)])
|
||||
row = cur.fetchone()
|
||||
result["adresa_livrare_roa"] = {"strada": row[0], "numar": row[1], "localitate": row[2], "judet": row[3]} if row else None
|
||||
result["adresa_livrare_roa"] = {
|
||||
"strada": row[0], "numar": row[1], "bloc": row[2], "scara": row[3],
|
||||
"apart": row[4], "etaj": row[5], "localitate": row[6], "judet": row[7]
|
||||
} if row else None
|
||||
if addr_fact_id and addr_fact_id != addr_livr_id:
|
||||
cur.execute("SELECT strada, numar, localitate, judet FROM vadrese_parteneri WHERE id_adresa = :1", [int(addr_fact_id)])
|
||||
cur.execute("""SELECT strada, numar, bloc, scara, apart, etaj, localitate, judet
|
||||
FROM vadrese_parteneri WHERE id_adresa = :1""", [int(addr_fact_id)])
|
||||
row = cur.fetchone()
|
||||
result["adresa_facturare_roa"] = {"strada": row[0], "numar": row[1], "localitate": row[2], "judet": row[3]} if row else None
|
||||
result["adresa_facturare_roa"] = {
|
||||
"strada": row[0], "numar": row[1], "bloc": row[2], "scara": row[3],
|
||||
"apart": row[4], "etaj": row[5], "localitate": row[6], "judet": row[7]
|
||||
} if row else None
|
||||
elif addr_fact_id and addr_fact_id == addr_livr_id:
|
||||
result["adresa_facturare_roa"] = result.get("adresa_livrare_roa")
|
||||
|
||||
|
||||
@@ -1214,6 +1214,59 @@ async def update_gomag_addresses_batch(updates: list[dict]):
|
||||
await db.close()
|
||||
|
||||
|
||||
async def get_order_address_ids(order_number: str) -> dict | None:
|
||||
"""Return id_adresa_livrare, id_adresa_facturare, adresa_*_gomag for an order."""
|
||||
db = await get_sqlite()
|
||||
try:
|
||||
cursor = await db.execute("""SELECT id_adresa_livrare, id_adresa_facturare,
|
||||
adresa_livrare_gomag, adresa_facturare_gomag,
|
||||
adresa_livrare_roa
|
||||
FROM orders WHERE order_number = ?""", [order_number])
|
||||
row = await cursor.fetchone()
|
||||
return dict(row) if row else None
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
async def update_order_address_cache(order_number: str, livr_roa: dict | None,
|
||||
fact_roa: dict | None, mismatch: bool):
|
||||
"""Update ONLY the 3 address-cache columns — does NOT touch ANAF/partner fields."""
|
||||
db = await get_sqlite()
|
||||
try:
|
||||
await db.execute("""
|
||||
UPDATE orders SET
|
||||
adresa_livrare_roa = ?,
|
||||
adresa_facturare_roa = ?,
|
||||
address_mismatch = ?,
|
||||
updated_at = datetime('now')
|
||||
WHERE order_number = ?
|
||||
""", (
|
||||
json.dumps(livr_roa) if livr_roa else None,
|
||||
json.dumps(fact_roa) if fact_roa else None,
|
||||
1 if mismatch else 0,
|
||||
order_number,
|
||||
))
|
||||
await db.commit()
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
async def get_orders_with_address_ids() -> list[dict]:
|
||||
"""Get all orders that have Oracle address IDs stored (for batch refresh)."""
|
||||
db = await get_sqlite()
|
||||
try:
|
||||
cursor = await db.execute("""
|
||||
SELECT order_number, id_adresa_livrare, id_adresa_facturare,
|
||||
adresa_livrare_gomag, adresa_facturare_gomag
|
||||
FROM orders
|
||||
WHERE id_adresa_livrare IS NOT NULL OR id_adresa_facturare IS NOT NULL
|
||||
""")
|
||||
rows = await cursor.fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
async def get_orders_missing_anaf() -> list[dict]:
|
||||
"""Get orders with cod_fiscal_roa set but no ANAF data (for backfill)."""
|
||||
db = await get_sqlite()
|
||||
|
||||
@@ -40,7 +40,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_street = norm((r.get('strada') or '') + (r.get('numar') or '') + (r.get('bloc') or '') + (r.get('scara') or '') + (r.get('apart') 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 '')
|
||||
|
||||
Reference in New Issue
Block a user