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:
|
||||
msg = (msg + " | " if msg else "") + "; ".join(cause_msgs)
|
||||
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
|
||||
except Exception:
|
||||
pass
|
||||
@@ -153,7 +159,7 @@ def build_item_payload(
|
||||
"listing_type_id": listing_type_id,
|
||||
"condition": "new",
|
||||
"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": [],
|
||||
}
|
||||
|
||||
@@ -196,6 +202,34 @@ def build_item_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
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -279,6 +313,10 @@ def validate_items(
|
||||
if not svc:
|
||||
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.execute(
|
||||
"""
|
||||
@@ -373,6 +411,10 @@ def publish_items(
|
||||
if not svc:
|
||||
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()
|
||||
|
||||
# Batch fetch inventory rows
|
||||
|
||||
@@ -183,6 +183,9 @@ class MeliService:
|
||||
def get_category_attributes(self, category_id: str) -> list:
|
||||
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 ──────────────────────────────────────────────────────────
|
||||
|
||||
def get_orders(
|
||||
|
||||
Reference in New Issue
Block a user