refactor(price): remove price comparison UI and catalog sync
GoMag vs ROA price comparison generated too many false positives (kits, volume discounts, special prices). Removes comparison columns, dots, badges, catalog sync endpoints, and ~950 lines of dead code. Keeps WRITE path (sync_prices_from_order) for kit pricing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -103,80 +103,3 @@ async def download_orders(
|
||||
return {"pages": total_pages, "total": total_orders, "files": saved_files}
|
||||
|
||||
|
||||
async def download_products(
|
||||
api_key: str = None,
|
||||
api_shop: str = None,
|
||||
products_url: str = None,
|
||||
log_fn: Callable[[str], None] = None,
|
||||
) -> list[dict]:
|
||||
"""Download all products from GoMag Products API.
|
||||
Returns list of product dicts with: sku, price, vat, vat_included, bundleItems.
|
||||
"""
|
||||
def _log(msg: str):
|
||||
logger.info(msg)
|
||||
if log_fn:
|
||||
log_fn(msg)
|
||||
|
||||
effective_key = api_key or settings.GOMAG_API_KEY
|
||||
effective_shop = api_shop or settings.GOMAG_API_SHOP
|
||||
default_url = "https://api.gomag.ro/api/v1/product/read/json"
|
||||
effective_url = products_url or default_url
|
||||
|
||||
if not effective_key or not effective_shop:
|
||||
_log("GoMag API keys neconfigurați, skip product download")
|
||||
return []
|
||||
|
||||
headers = {
|
||||
"Apikey": effective_key,
|
||||
"ApiShop": effective_shop,
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
all_products = []
|
||||
total_pages = 1
|
||||
|
||||
async with httpx.AsyncClient(timeout=30) as client:
|
||||
page = 1
|
||||
while page <= total_pages:
|
||||
params = {"page": page, "limit": 100}
|
||||
try:
|
||||
response = await client.get(effective_url, headers=headers, params=params)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
except httpx.HTTPError as e:
|
||||
_log(f"GoMag Products API eroare pagina {page}: {e}")
|
||||
break
|
||||
except Exception as e:
|
||||
_log(f"GoMag Products eroare neașteptată pagina {page}: {e}")
|
||||
break
|
||||
|
||||
if page == 1:
|
||||
total_pages = int(data.get("pages", 1))
|
||||
_log(f"GoMag Products: {data.get('total', '?')} produse în {total_pages} pagini")
|
||||
|
||||
products = data.get("products", [])
|
||||
if isinstance(products, dict):
|
||||
# GoMag returns products as {"1": {...}, "2": {...}} dict
|
||||
first_val = next(iter(products.values()), None) if products else None
|
||||
if isinstance(first_val, dict):
|
||||
products = list(products.values())
|
||||
else:
|
||||
products = [products]
|
||||
if isinstance(products, list):
|
||||
for p in products:
|
||||
if isinstance(p, dict) and p.get("sku"):
|
||||
all_products.append({
|
||||
"sku": p["sku"],
|
||||
"price": p.get("price", "0"),
|
||||
"vat": p.get("vat", "19"),
|
||||
"vat_included": str(p.get("vat_included", "1")),
|
||||
"bundleItems": p.get("bundleItems", []),
|
||||
})
|
||||
|
||||
page += 1
|
||||
if page <= total_pages:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
_log(f"GoMag Products: {len(all_products)} produse cu SKU descărcate")
|
||||
return all_products
|
||||
|
||||
@@ -1,264 +0,0 @@
|
||||
"""Catalog price sync service — syncs product prices from GoMag catalog to ROA Oracle."""
|
||||
import asyncio
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from . import gomag_client, validation_service, sqlite_service
|
||||
from .. import database
|
||||
from ..config import settings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_tz = ZoneInfo("Europe/Bucharest")
|
||||
|
||||
_price_sync_lock = asyncio.Lock()
|
||||
_current_price_sync = None
|
||||
|
||||
|
||||
def _now():
|
||||
return datetime.now(_tz).replace(tzinfo=None)
|
||||
|
||||
|
||||
async def prepare_price_sync() -> dict:
|
||||
global _current_price_sync
|
||||
if _price_sync_lock.locked():
|
||||
return {"error": "Price sync already running"}
|
||||
run_id = _now().strftime("%Y%m%d_%H%M%S") + "_ps_" + uuid.uuid4().hex[:6]
|
||||
_current_price_sync = {
|
||||
"run_id": run_id, "status": "running",
|
||||
"started_at": _now().isoformat(), "finished_at": None,
|
||||
"phase_text": "Starting...",
|
||||
}
|
||||
# Create SQLite record
|
||||
db = await sqlite_service.get_sqlite()
|
||||
try:
|
||||
await db.execute(
|
||||
"INSERT INTO price_sync_runs (run_id, started_at, status) VALUES (?, ?, 'running')",
|
||||
(run_id, _now().strftime("%d.%m.%Y %H:%M:%S"))
|
||||
)
|
||||
await db.commit()
|
||||
finally:
|
||||
await db.close()
|
||||
return {"run_id": run_id}
|
||||
|
||||
|
||||
async def get_price_sync_status() -> dict:
|
||||
if _current_price_sync and _current_price_sync.get("status") == "running":
|
||||
return _current_price_sync
|
||||
# Return last run from SQLite
|
||||
db = await sqlite_service.get_sqlite()
|
||||
try:
|
||||
cursor = await db.execute(
|
||||
"SELECT * FROM price_sync_runs ORDER BY started_at DESC LIMIT 1"
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if row:
|
||||
return {"status": "idle", "last_run": dict(row)}
|
||||
return {"status": "idle"}
|
||||
except Exception:
|
||||
return {"status": "idle"}
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
async def run_catalog_price_sync(run_id: str):
|
||||
global _current_price_sync
|
||||
async with _price_sync_lock:
|
||||
log_lines = []
|
||||
def _log(msg):
|
||||
logger.info(msg)
|
||||
log_lines.append(f"[{_now().strftime('%H:%M:%S')}] {msg}")
|
||||
if _current_price_sync:
|
||||
_current_price_sync["phase_text"] = msg
|
||||
|
||||
try:
|
||||
app_settings = await sqlite_service.get_app_settings()
|
||||
id_pol = int(app_settings.get("id_pol") or 0) or None
|
||||
id_pol_productie = int(app_settings.get("id_pol_productie") or 0) or None
|
||||
|
||||
if not id_pol:
|
||||
_log("Politica de preț nu e configurată — skip sync")
|
||||
await _finish_run(run_id, "error", log_lines, error="No price policy")
|
||||
return
|
||||
|
||||
# Fetch products from GoMag
|
||||
_log("Descărcare produse din GoMag API...")
|
||||
products = await gomag_client.download_products(
|
||||
api_key=app_settings.get("gomag_api_key"),
|
||||
api_shop=app_settings.get("gomag_api_shop"),
|
||||
products_url=app_settings.get("gomag_products_url") or None,
|
||||
log_fn=_log,
|
||||
)
|
||||
|
||||
if not products:
|
||||
_log("Niciun produs descărcat")
|
||||
await _finish_run(run_id, "completed", log_lines, products_total=0)
|
||||
return
|
||||
|
||||
# Index products by SKU for kit component lookup
|
||||
products_by_sku = {p["sku"]: p for p in products}
|
||||
|
||||
# Connect to Oracle
|
||||
conn = await asyncio.to_thread(database.get_oracle_connection)
|
||||
try:
|
||||
# Get all mappings from ARTICOLE_TERTI
|
||||
_log("Citire mapări ARTICOLE_TERTI...")
|
||||
mapped_data = await asyncio.to_thread(
|
||||
validation_service.resolve_mapped_codmats,
|
||||
{p["sku"] for p in products}, conn
|
||||
)
|
||||
|
||||
# Get direct articles from NOM_ARTICOLE
|
||||
_log("Identificare articole directe...")
|
||||
direct_id_map = {}
|
||||
with conn.cursor() as cur:
|
||||
all_skus = list({p["sku"] for p in products})
|
||||
for i in range(0, len(all_skus), 500):
|
||||
batch = all_skus[i:i+500]
|
||||
placeholders = ",".join([f":s{j}" for j in range(len(batch))])
|
||||
params = {f"s{j}": sku for j, sku in enumerate(batch)}
|
||||
cur.execute(f"""
|
||||
SELECT codmat, id_articol, cont FROM nom_articole
|
||||
WHERE codmat IN ({placeholders}) AND sters = 0 AND inactiv = 0
|
||||
""", params)
|
||||
for row in cur:
|
||||
if row[0] not in mapped_data:
|
||||
direct_id_map[row[0]] = {"id_articol": row[1], "cont": row[2]}
|
||||
|
||||
matched = 0
|
||||
updated = 0
|
||||
errors = 0
|
||||
|
||||
for product in products:
|
||||
sku = product["sku"]
|
||||
try:
|
||||
price_str = product.get("price", "0")
|
||||
price = float(price_str) if price_str else 0
|
||||
if price <= 0:
|
||||
continue
|
||||
|
||||
vat = float(product.get("vat", "19"))
|
||||
|
||||
# Calculate price with TVA (vat_included can be int 1 or str "1")
|
||||
if str(product.get("vat_included", "1")) == "1":
|
||||
price_cu_tva = price
|
||||
else:
|
||||
price_cu_tva = price * (1 + vat / 100)
|
||||
|
||||
# For kits, sync each component individually from standalone GoMag prices
|
||||
mapped_comps = mapped_data.get(sku, [])
|
||||
is_kit = len(mapped_comps) > 1 or (
|
||||
len(mapped_comps) == 1 and (mapped_comps[0].get("cantitate_roa") or 1) > 1
|
||||
)
|
||||
if is_kit:
|
||||
for comp in mapped_data[sku]:
|
||||
comp_codmat = comp["codmat"]
|
||||
|
||||
# Skip components that have their own ARTICOLE_TERTI mapping
|
||||
# (they'll be synced with correct cantitate_roa in individual path)
|
||||
if comp_codmat in mapped_data:
|
||||
continue
|
||||
|
||||
comp_product = products_by_sku.get(comp_codmat)
|
||||
if not comp_product:
|
||||
continue # Component not in GoMag as standalone product
|
||||
|
||||
comp_price_str = comp_product.get("price", "0")
|
||||
comp_price = float(comp_price_str) if comp_price_str else 0
|
||||
if comp_price <= 0:
|
||||
continue
|
||||
|
||||
comp_vat = float(comp_product.get("vat", "19"))
|
||||
|
||||
# vat_included can be int 1 or str "1"
|
||||
if str(comp_product.get("vat_included", "1")) == "1":
|
||||
comp_price_cu_tva = comp_price
|
||||
else:
|
||||
comp_price_cu_tva = comp_price * (1 + comp_vat / 100)
|
||||
|
||||
comp_cont_str = str(comp.get("cont") or "").strip()
|
||||
comp_pol = id_pol_productie if (comp_cont_str in ("341", "345") and id_pol_productie) else id_pol
|
||||
|
||||
matched += 1
|
||||
result = await asyncio.to_thread(
|
||||
validation_service.compare_and_update_price,
|
||||
comp["id_articol"], comp_pol, comp_price_cu_tva, conn
|
||||
)
|
||||
if result and result["updated"]:
|
||||
updated += 1
|
||||
_log(f" {comp_codmat}: {result['old_price']:.2f} → {result['new_price']:.2f} (kit {sku})")
|
||||
elif result is None:
|
||||
_log(f" {comp_codmat}: LIPSESTE din politica {comp_pol} — adauga manual in ROA (kit {sku})")
|
||||
continue
|
||||
|
||||
# Determine id_articol and policy
|
||||
id_articol = None
|
||||
cantitate_roa = 1
|
||||
|
||||
if sku in mapped_data and len(mapped_data[sku]) == 1 and (mapped_data[sku][0].get("cantitate_roa") or 1) <= 1:
|
||||
comp = mapped_data[sku][0]
|
||||
id_articol = comp["id_articol"]
|
||||
cantitate_roa = comp.get("cantitate_roa") or 1
|
||||
elif sku in direct_id_map:
|
||||
id_articol = direct_id_map[sku]["id_articol"]
|
||||
else:
|
||||
continue # SKU not in ROA
|
||||
|
||||
matched += 1
|
||||
price_per_unit = price_cu_tva / cantitate_roa if cantitate_roa != 1 else price_cu_tva
|
||||
|
||||
# Determine policy
|
||||
cont = None
|
||||
if sku in mapped_data and len(mapped_data[sku]) == 1 and (mapped_data[sku][0].get("cantitate_roa") or 1) <= 1:
|
||||
cont = mapped_data[sku][0].get("cont")
|
||||
elif sku in direct_id_map:
|
||||
cont = direct_id_map[sku].get("cont")
|
||||
|
||||
cont_str = str(cont or "").strip()
|
||||
pol = id_pol_productie if (cont_str in ("341", "345") and id_pol_productie) else id_pol
|
||||
|
||||
result = await asyncio.to_thread(
|
||||
validation_service.compare_and_update_price,
|
||||
id_articol, pol, price_per_unit, conn
|
||||
)
|
||||
if result and result["updated"]:
|
||||
updated += 1
|
||||
_log(f" {result['codmat']}: {result['old_price']:.2f} → {result['new_price']:.2f}")
|
||||
|
||||
except Exception as e:
|
||||
errors += 1
|
||||
_log(f"Eroare produs {sku}: {e}")
|
||||
|
||||
_log(f"Sync complet: {len(products)} produse, {matched} potrivite, {updated} actualizate, {errors} erori")
|
||||
|
||||
finally:
|
||||
await asyncio.to_thread(database.pool.release, conn)
|
||||
|
||||
await _finish_run(run_id, "completed", log_lines,
|
||||
products_total=len(products), matched=matched,
|
||||
updated=updated, errors=errors)
|
||||
|
||||
except Exception as e:
|
||||
_log(f"Eroare critică: {e}")
|
||||
logger.error(f"Catalog price sync error: {e}", exc_info=True)
|
||||
await _finish_run(run_id, "error", log_lines, error=str(e))
|
||||
|
||||
|
||||
async def _finish_run(run_id, status, log_lines, products_total=0,
|
||||
matched=0, updated=0, errors=0, error=None):
|
||||
global _current_price_sync
|
||||
db = await sqlite_service.get_sqlite()
|
||||
try:
|
||||
await db.execute("""
|
||||
UPDATE price_sync_runs SET
|
||||
finished_at = ?, status = ?, products_total = ?,
|
||||
matched = ?, updated = ?, errors = ?,
|
||||
log_text = ?
|
||||
WHERE run_id = ?
|
||||
""", (_now().strftime("%d.%m.%Y %H:%M:%S"), status, products_total, matched, updated, errors,
|
||||
"\n".join(log_lines), run_id))
|
||||
await db.commit()
|
||||
finally:
|
||||
await db.close()
|
||||
_current_price_sync = None
|
||||
@@ -1026,23 +1026,6 @@ async def get_skipped_orders_with_sku(sku: str) -> list[str]:
|
||||
|
||||
# ── Price Sync Runs ───────────────────────────────
|
||||
|
||||
async def get_price_sync_runs(page: int = 1, per_page: int = 20):
|
||||
"""Get paginated price sync run history."""
|
||||
db = await get_sqlite()
|
||||
try:
|
||||
offset = (page - 1) * per_page
|
||||
cursor = await db.execute("SELECT COUNT(*) FROM price_sync_runs")
|
||||
total = (await cursor.fetchone())[0]
|
||||
cursor = await db.execute(
|
||||
"SELECT * FROM price_sync_runs ORDER BY started_at DESC LIMIT ? OFFSET ?",
|
||||
(per_page, offset)
|
||||
)
|
||||
runs = [dict(r) for r in await cursor.fetchall()]
|
||||
return {"runs": runs, "total": total, "page": page, "pages": (total + per_page - 1) // per_page}
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
|
||||
# ── ANAF Cache ───────────────────────────────────
|
||||
|
||||
async def get_anaf_cache(bare_cui: str) -> dict | None:
|
||||
|
||||
@@ -588,193 +588,3 @@ def sync_prices_from_order(orders, mapped_codmat_data: dict, direct_id_map: dict
|
||||
return updated
|
||||
|
||||
|
||||
def get_prices_for_order(items: list[dict], app_settings: dict, conn=None) -> dict:
|
||||
"""Compare GoMag prices with ROA prices for order items.
|
||||
|
||||
Args:
|
||||
items: list of order items, each with 'sku', 'price', 'quantity', 'codmat_details'
|
||||
(codmat_details = [{"codmat", "cantitate_roa", "id_articol"?, "cont"?, "direct"?}])
|
||||
app_settings: dict with 'id_pol', 'id_pol_productie'
|
||||
conn: Oracle connection (optional, will acquire if None)
|
||||
|
||||
Returns: {
|
||||
"items": {idx: {"pret_roa": float|None, "match": bool|None, "pret_gomag": float}},
|
||||
"summary": {"mismatches": int, "checked": int, "oracle_available": bool}
|
||||
}
|
||||
"""
|
||||
try:
|
||||
id_pol = int(app_settings.get("id_pol", 0) or 0)
|
||||
id_pol_productie = int(app_settings.get("id_pol_productie", 0) or 0)
|
||||
except (ValueError, TypeError):
|
||||
id_pol = 0
|
||||
id_pol_productie = 0
|
||||
|
||||
def _empty_result(oracle_available: bool) -> dict:
|
||||
return {
|
||||
"items": {
|
||||
idx: {"pret_roa": None, "match": None, "pret_gomag": float(item.get("price") or 0)}
|
||||
for idx, item in enumerate(items)
|
||||
},
|
||||
"summary": {"mismatches": 0, "checked": 0, "oracle_available": oracle_available}
|
||||
}
|
||||
|
||||
if not items or not id_pol:
|
||||
return _empty_result(oracle_available=False)
|
||||
|
||||
own_conn = conn is None
|
||||
try:
|
||||
if own_conn:
|
||||
conn = database.get_oracle_connection()
|
||||
|
||||
# Step 1: Collect codmats; use id_articol/cont from codmat_details when already known
|
||||
pre_resolved = {} # {codmat: {"id_articol": int, "cont": str}}
|
||||
all_codmats = set()
|
||||
for item in items:
|
||||
for cd in (item.get("codmat_details") or []):
|
||||
codmat = cd.get("codmat")
|
||||
if not codmat:
|
||||
continue
|
||||
all_codmats.add(codmat)
|
||||
if cd.get("id_articol") and codmat not in pre_resolved:
|
||||
pre_resolved[codmat] = {
|
||||
"id_articol": cd["id_articol"],
|
||||
"cont": cd.get("cont") or "",
|
||||
}
|
||||
|
||||
# Step 2: Resolve missing id_articols via nom_articole
|
||||
need_resolve = all_codmats - set(pre_resolved.keys())
|
||||
if need_resolve:
|
||||
db_resolved = resolve_codmat_ids(need_resolve, conn=conn)
|
||||
pre_resolved.update(db_resolved)
|
||||
|
||||
codmat_info = pre_resolved # {codmat: {"id_articol": int, "cont": str}}
|
||||
|
||||
# Step 3: Get PRETURI_CU_TVA flag once per policy
|
||||
policies = {id_pol}
|
||||
if id_pol_productie and id_pol_productie != id_pol:
|
||||
policies.add(id_pol_productie)
|
||||
|
||||
pol_cu_tva = {} # {id_pol: bool}
|
||||
with conn.cursor() as cur:
|
||||
for pol in policies:
|
||||
cur.execute(
|
||||
"SELECT PRETURI_CU_TVA FROM CRM_POLITICI_PRETURI WHERE ID_POL = :pol",
|
||||
{"pol": pol},
|
||||
)
|
||||
row = cur.fetchone()
|
||||
pol_cu_tva[pol] = (int(row[0] or 0) == 1) if row else False
|
||||
|
||||
# Step 4: Batch query PRET + PROC_TVAV for all id_articols across both policies
|
||||
all_id_articols = list({
|
||||
info["id_articol"]
|
||||
for info in codmat_info.values()
|
||||
if info.get("id_articol")
|
||||
})
|
||||
price_map = {} # {(id_pol, id_articol): (pret, proc_tvav)}
|
||||
|
||||
if all_id_articols:
|
||||
pol_list = list(policies)
|
||||
pol_placeholders = ",".join([f":p{k}" for k in range(len(pol_list))])
|
||||
with conn.cursor() as cur:
|
||||
for i in range(0, len(all_id_articols), 500):
|
||||
batch = all_id_articols[i:i + 500]
|
||||
art_placeholders = ",".join([f":a{j}" for j in range(len(batch))])
|
||||
params = {f"a{j}": aid for j, aid in enumerate(batch)}
|
||||
for k, pol in enumerate(pol_list):
|
||||
params[f"p{k}"] = pol
|
||||
cur.execute(f"""
|
||||
SELECT ID_POL, ID_ARTICOL, PRET, PROC_TVAV
|
||||
FROM CRM_POLITICI_PRET_ART
|
||||
WHERE ID_POL IN ({pol_placeholders}) AND ID_ARTICOL IN ({art_placeholders})
|
||||
""", params)
|
||||
for row in cur:
|
||||
price_map[(row[0], row[1])] = (row[2], row[3])
|
||||
|
||||
# Step 5: Compute pret_roa per item and compare with GoMag price
|
||||
result_items = {}
|
||||
mismatches = 0
|
||||
checked = 0
|
||||
|
||||
for idx, item in enumerate(items):
|
||||
pret_gomag = float(item.get("price") or 0)
|
||||
result_items[idx] = {"pret_gomag": pret_gomag, "pret_roa": None, "match": None}
|
||||
|
||||
codmat_details = item.get("codmat_details") or []
|
||||
if not codmat_details:
|
||||
continue
|
||||
|
||||
is_kit = len(codmat_details) > 1 or (
|
||||
len(codmat_details) == 1
|
||||
and float(codmat_details[0].get("cantitate_roa") or 1) != 1
|
||||
)
|
||||
|
||||
if is_kit:
|
||||
# Kit/pachet: prețul GoMag e comercial, ROA e suma componente din lista
|
||||
# de prețuri — diferența e gestionată de discount line
|
||||
result_items[idx]["kit"] = True
|
||||
continue
|
||||
|
||||
pret_roa_total = 0.0
|
||||
all_resolved = True
|
||||
|
||||
for cd in codmat_details:
|
||||
codmat = cd.get("codmat")
|
||||
if not codmat:
|
||||
all_resolved = False
|
||||
break
|
||||
|
||||
info = codmat_info.get(codmat, {})
|
||||
id_articol = info.get("id_articol")
|
||||
if not id_articol:
|
||||
all_resolved = False
|
||||
break
|
||||
|
||||
# Dual-policy routing: cont 341/345 → production, else → sales
|
||||
cont = str(info.get("cont") or cd.get("cont") or "").strip()
|
||||
if cont in ("341", "345") and id_pol_productie:
|
||||
pol = id_pol_productie
|
||||
else:
|
||||
pol = id_pol
|
||||
|
||||
price_entry = price_map.get((pol, id_articol))
|
||||
if price_entry is None:
|
||||
all_resolved = False
|
||||
break
|
||||
|
||||
pret, proc_tvav = price_entry
|
||||
proc_tvav = float(proc_tvav or 1.19)
|
||||
|
||||
if pol_cu_tva.get(pol):
|
||||
pret_cu_tva = float(pret or 0)
|
||||
else:
|
||||
pret_cu_tva = float(pret or 0) * proc_tvav
|
||||
|
||||
cantitate_roa = float(cd.get("cantitate_roa") or 1)
|
||||
if is_kit:
|
||||
pret_roa_total += pret_cu_tva * cantitate_roa
|
||||
else:
|
||||
pret_roa_total = pret_cu_tva # cantitate_roa==1 for simple items
|
||||
|
||||
if not all_resolved:
|
||||
continue
|
||||
|
||||
pret_roa = round(pret_roa_total, 4)
|
||||
match = pret_gomag <= pret_roa + 0.01
|
||||
result_items[idx]["pret_roa"] = pret_roa
|
||||
result_items[idx]["match"] = match
|
||||
checked += 1
|
||||
if not match:
|
||||
mismatches += 1
|
||||
|
||||
logger.info(f"get_prices_for_order: {checked}/{len(items)} checked, {mismatches} mismatches")
|
||||
return {
|
||||
"items": result_items,
|
||||
"summary": {"mismatches": mismatches, "checked": checked, "oracle_available": True},
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"get_prices_for_order failed: {e}")
|
||||
return _empty_result(oracle_available=False)
|
||||
finally:
|
||||
if own_conn and conn:
|
||||
database.pool.release(conn)
|
||||
|
||||
Reference in New Issue
Block a user