fix(import): resolve duplicate article + order_items repopulation on retry
Two production bugs from VENDING (order 485224762, 2026-04-22): 1. Oracle: ORA-20000 when a GoMag order contains a kit SKU whose expansion includes CODMAT X plus a second item with SKU=X. Two article-insert call-sites in PACK_IMPORT_COMENZI bypassed merge_or_insert_articol — line 622 (NOM_ARTICOLE fallback) and line 538 (kit discount line). Both now use merge_or_insert_articol for consistent dedup semantics. Regression test added in test_complete_import.py covering the exact kit-plus-direct scenario. 2. SQLite: retry_service._download_and_reimport refreshed orders row but never repopulated order_items. Combined with mark_order_deleted_in_roa (which wipes items), any retry/resync left the UI showing "Niciun articol" despite successful Oracle import. Retry now rebuilds items from the fresh GoMag download on both success and error paths, mirroring sync_service. Includes scripts/backfill_order_items.py — one-shot recovery for orders already in this bad state. Reads settings, re-fetches from GoMag, rewrites order_items without touching Oracle or order status. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ async def _download_and_reimport(order_number: str, order_date_str: str, custome
|
||||
Does NOT check status guard — caller is responsible.
|
||||
Returns: {"success": bool, "message": str, "status": str|None}
|
||||
"""
|
||||
from . import sqlite_service, gomag_client, import_service, order_reader
|
||||
from . import sqlite_service, gomag_client, import_service, order_reader, validation_service
|
||||
|
||||
# Parse order date for narrow download window
|
||||
try:
|
||||
@@ -75,6 +75,28 @@ async def _download_and_reimport(order_number: str, order_date_str: str, custome
|
||||
)
|
||||
return {"success": False, "message": f"Eroare import: {e}"}
|
||||
|
||||
# Build order_items data from fresh GoMag download (mirrors sync_service:882-891).
|
||||
# Resolves ARTICOLE_TERTI mapping so UI shows mapped/direct badge.
|
||||
try:
|
||||
skus = {item.sku for item in target_order.items if item.sku}
|
||||
validation = await asyncio.to_thread(
|
||||
validation_service.validate_skus, skus, None, id_gestiuni
|
||||
) if skus else {"mapped": set(), "direct": set()}
|
||||
except Exception as e:
|
||||
logger.warning(f"Retry: validate_skus failed for {order_number}, defaulting mapping_status=direct: {e}")
|
||||
validation = {"mapped": set(), "direct": set()}
|
||||
|
||||
order_items_data = [
|
||||
{
|
||||
"sku": item.sku, "product_name": item.name,
|
||||
"quantity": item.quantity, "price": item.price,
|
||||
"baseprice": item.baseprice, "vat": item.vat,
|
||||
"mapping_status": "mapped" if item.sku in validation["mapped"] else "direct",
|
||||
"codmat": None, "id_articol": None, "cantitate_roa": None,
|
||||
}
|
||||
for item in target_order.items
|
||||
]
|
||||
|
||||
if result.get("success"):
|
||||
await sqlite_service.upsert_order(
|
||||
sync_run_id="retry",
|
||||
@@ -92,7 +114,8 @@ async def _download_and_reimport(order_number: str, order_date_str: str, custome
|
||||
id_adresa_facturare=result.get("id_adresa_facturare"),
|
||||
id_adresa_livrare=result.get("id_adresa_livrare"),
|
||||
)
|
||||
logger.info(f"Retry successful for order {order_number} → IMPORTED")
|
||||
await sqlite_service.add_order_items(order_number, order_items_data)
|
||||
logger.info(f"Retry successful for order {order_number} → IMPORTED ({len(order_items_data)} items)")
|
||||
return {"success": True, "message": "Comanda reimportata cu succes", "status": "IMPORTED"}
|
||||
else:
|
||||
error = result.get("error", "Unknown error")
|
||||
@@ -104,6 +127,7 @@ async def _download_and_reimport(order_number: str, order_date_str: str, custome
|
||||
status="ERROR",
|
||||
error_message=f"Retry: {error}",
|
||||
)
|
||||
await sqlite_service.add_order_items(order_number, order_items_data)
|
||||
return {"success": False, "message": f"Import esuat: {error}", "status": "ERROR"}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user