fix: ML shipping config check + improved payload + actionable error messages
- Add get_shipping_preferences to meli_service.py - Add check_meli_shipping_config to validate ME2 adoption before publishing - Include local_pick_up and free_shipping in item payload - Translate ME2/mode errors to actionable Spanish messages - Check shipping config in both validate_items and publish_items
This commit is contained in:
@@ -120,6 +120,12 @@ def _extract_meli_error(err: MeliError) -> str:
|
|||||||
if cause_msgs:
|
if cause_msgs:
|
||||||
msg = (msg + " | " if msg else "") + "; ".join(cause_msgs)
|
msg = (msg + " | " if msg else "") + "; ".join(cause_msgs)
|
||||||
if msg:
|
if msg:
|
||||||
|
# Translate common account-configuration errors to actionable messages
|
||||||
|
lowered = msg.lower()
|
||||||
|
if "me2 adoption is mandatory" in lowered:
|
||||||
|
return msg + " | Debes activar MercadoEnvíos (ME2) en tu cuenta de MercadoLibre. Ve a Configuración > Envíos en el panel de vendedor de ML."
|
||||||
|
if "user has not mode" in lowered:
|
||||||
|
return msg + " | Tu cuenta no tiene configurado este modo de envío. Configura tus métodos de envío en MercadoLibre."
|
||||||
return msg
|
return msg
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
@@ -153,7 +159,7 @@ def build_item_payload(
|
|||||||
"listing_type_id": listing_type_id,
|
"listing_type_id": listing_type_id,
|
||||||
"condition": "new",
|
"condition": "new",
|
||||||
"pictures": [{"source": url} for url in images if url],
|
"pictures": [{"source": url} for url in images if url],
|
||||||
"shipping": {"mode": shipping_mode},
|
"shipping": {"mode": shipping_mode, "local_pick_up": False, "free_shipping": False},
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +202,34 @@ def build_item_payload(
|
|||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
def check_meli_shipping_config(svc: MeliService, cfg: dict) -> dict:
|
||||||
|
"""Check if the user's ML account has the required shipping modes configured.
|
||||||
|
|
||||||
|
Returns {"ok": True} or {"ok": False, "error": "...", "available_modes": [...]}.
|
||||||
|
"""
|
||||||
|
user_id = cfg.get("meli_user_id")
|
||||||
|
if not user_id:
|
||||||
|
return {"ok": False, "error": "Usuario de ML no configurado"}
|
||||||
|
try:
|
||||||
|
prefs = svc.get_shipping_preferences(str(user_id))
|
||||||
|
modes = prefs.get("modes", [])
|
||||||
|
mandatory = prefs.get("mandatory_mode_for_user", [])
|
||||||
|
if mandatory and not any(m in modes for m in mandatory):
|
||||||
|
return {
|
||||||
|
"ok": False,
|
||||||
|
"error": f"Tu cuenta requiere obligatoriamente los modos de envío: {', '.join(mandatory)}. Actualmente solo tienes: {', '.join(modes)}. Configúralos en el panel de vendedor de MercadoLibre.",
|
||||||
|
"available_modes": modes,
|
||||||
|
"mandatory_modes": mandatory,
|
||||||
|
}
|
||||||
|
return {"ok": True, "available_modes": modes, "mandatory_modes": mandatory}
|
||||||
|
except MeliError as e:
|
||||||
|
logger.warning("Failed to fetch shipping preferences: %s", e)
|
||||||
|
return {"ok": True} # Don't block on preference fetch failure
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Failed to fetch shipping preferences: %s", e)
|
||||||
|
return {"ok": True}
|
||||||
|
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
# LISTINGS CRUD
|
# LISTINGS CRUD
|
||||||
# ═══════════════════════════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════════════════════════
|
||||||
@@ -279,6 +313,10 @@ def validate_items(
|
|||||||
if not svc:
|
if not svc:
|
||||||
raise ValueError("MercadoLibre not configured")
|
raise ValueError("MercadoLibre not configured")
|
||||||
|
|
||||||
|
shipping_check = check_meli_shipping_config(svc, cfg)
|
||||||
|
if not shipping_check["ok"]:
|
||||||
|
return {"valid": [], "invalid": [{"inventory_id": "config", "error": shipping_check["error"]}]}
|
||||||
|
|
||||||
cur = tenant_conn.cursor()
|
cur = tenant_conn.cursor()
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
@@ -373,6 +411,10 @@ def publish_items(
|
|||||||
if not svc:
|
if not svc:
|
||||||
raise ValueError("MercadoLibre not configured")
|
raise ValueError("MercadoLibre not configured")
|
||||||
|
|
||||||
|
shipping_check = check_meli_shipping_config(svc, cfg)
|
||||||
|
if not shipping_check["ok"]:
|
||||||
|
return {"success": [], "failed": [{"inventory_id": "config", "error": shipping_check["error"]}]}
|
||||||
|
|
||||||
cur = tenant_conn.cursor()
|
cur = tenant_conn.cursor()
|
||||||
|
|
||||||
# Batch fetch inventory rows
|
# Batch fetch inventory rows
|
||||||
|
|||||||
@@ -183,6 +183,9 @@ class MeliService:
|
|||||||
def get_category_attributes(self, category_id: str) -> list:
|
def get_category_attributes(self, category_id: str) -> list:
|
||||||
return self._request("GET", f"/categories/{category_id}/attributes")
|
return self._request("GET", f"/categories/{category_id}/attributes")
|
||||||
|
|
||||||
|
def get_shipping_preferences(self, user_id: str) -> dict:
|
||||||
|
return self._request("GET", f"/users/{user_id}/shipping_preferences")
|
||||||
|
|
||||||
# ─── Orders ──────────────────────────────────────────────────────────
|
# ─── Orders ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def get_orders(
|
def get_orders(
|
||||||
|
|||||||
Reference in New Issue
Block a user