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:
2026-05-26 05:26:47 +00:00
parent 79d3368041
commit f742cdaa42
2 changed files with 46 additions and 1 deletions

View File

@@ -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

View File

@@ -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(