fix(missing-skus): reconcile stale false positives against Oracle
SKUs mapped externally (via SSH script or direct SQL) never triggered resolve_missing_sku(), leaving them stuck as unresolved=0 indefinitely. New reconcile_unresolved_missing_skus() revalidates ALL unresolved SKUs against Oracle at sync, rescan, and CSV import time. Fail-soft on Oracle down. Clears the 7 prod false positives on next sync or manual rescan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ from typing import Optional
|
||||
import io
|
||||
import asyncio
|
||||
|
||||
from ..services import mapping_service, sqlite_service
|
||||
from ..services import mapping_service, sqlite_service, validation_service
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -168,6 +168,7 @@ async def import_csv(file: UploadFile = File(...)):
|
||||
content = await file.read()
|
||||
text = content.decode("utf-8-sig")
|
||||
result = mapping_service.import_csv(text)
|
||||
await validation_service.reconcile_unresolved_missing_skus()
|
||||
return result
|
||||
|
||||
@router.get("/api/mappings/export-csv")
|
||||
|
||||
@@ -58,6 +58,8 @@ async def scan_and_validate():
|
||||
if tracked:
|
||||
new_missing += 1
|
||||
|
||||
rec = await validation_service.reconcile_unresolved_missing_skus()
|
||||
|
||||
total_skus_scanned = len(all_skus)
|
||||
new_missing_count = len(result["missing"])
|
||||
unchanged = total_skus_scanned - new_missing_count
|
||||
@@ -72,7 +74,7 @@ async def scan_and_validate():
|
||||
# Fields consumed by the rescan progress banner in missing_skus.html
|
||||
"total_skus_scanned": total_skus_scanned,
|
||||
"new_missing": new_missing_count,
|
||||
"auto_resolved": 0,
|
||||
"auto_resolved": rec["resolved"],
|
||||
"unchanged": unchanged,
|
||||
"skus": {
|
||||
"mapped": len(result["mapped"]),
|
||||
|
||||
@@ -468,6 +468,11 @@ async def run_sync(id_pol: int = None, id_sectie: int = None, run_id: str = None
|
||||
if resolved_count:
|
||||
_log_line(run_id, f"Auto-resolved {resolved_count} previously missing SKUs")
|
||||
|
||||
# Reconcile stale unresolved SKUs that got mappings outside the current JSON batch
|
||||
rec = await validation_service.reconcile_unresolved_missing_skus(conn=conn)
|
||||
if rec["resolved"]:
|
||||
_log_line(run_id, f"Reconciliere: {rec['resolved']} SKU rezolvate suplimentar")
|
||||
|
||||
# Step 2d: Pre-validate prices for importable articles
|
||||
if id_pol and (truly_importable or already_in_roa):
|
||||
_update_progress("validation", "Validating prices...", 0, len(truly_importable))
|
||||
|
||||
@@ -1,8 +1,39 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from .. import database
|
||||
from . import sqlite_service
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def reconcile_unresolved_missing_skus(conn=None) -> dict:
|
||||
"""Revalidate all resolved=0 SKUs in missing_skus against Oracle.
|
||||
Fail-soft: logs warning and returns zero if Oracle is unavailable.
|
||||
Returns {"checked": N, "resolved": M, "error": str|None}.
|
||||
"""
|
||||
db = await sqlite_service.get_sqlite()
|
||||
try:
|
||||
cursor = await db.execute("SELECT sku FROM missing_skus WHERE resolved = 0")
|
||||
rows = await cursor.fetchall()
|
||||
finally:
|
||||
await db.close()
|
||||
|
||||
if not rows:
|
||||
return {"checked": 0, "resolved": 0, "error": None}
|
||||
|
||||
unresolved_set = {row[0] for row in rows}
|
||||
|
||||
try:
|
||||
result = await asyncio.to_thread(validate_skus, unresolved_set, conn)
|
||||
except Exception as e:
|
||||
logger.warning(f"reconcile_unresolved_missing_skus: Oracle unavailable — {e}")
|
||||
return {"checked": len(unresolved_set), "resolved": 0, "error": str(e)}
|
||||
|
||||
resolved_set = result["mapped"] | result["direct"]
|
||||
resolved_count = await sqlite_service.resolve_missing_skus_batch(resolved_set)
|
||||
logger.info(f"reconcile_unresolved_missing_skus: checked={len(unresolved_set)}, resolved={resolved_count}")
|
||||
return {"checked": len(unresolved_set), "resolved": resolved_count, "error": None}
|
||||
|
||||
def check_orders_in_roa(min_date, conn) -> dict:
|
||||
"""Check which orders already exist in Oracle COMENZI by date range.
|
||||
Returns: {comanda_externa: id_comanda} for all existing orders.
|
||||
|
||||
Reference in New Issue
Block a user