Dimas Bueno.
← Todos los artículos

Por qué tu sincronización de stock falla (y cómo se arregla de verdad)

Duplicados, stock negativo, reintentos que empeoran el problema. Los cinco fallos que veo en casi todas las integraciones ERP ↔ tienda y cómo los resuelve un diseño que no confía en la red.

“Sincronizar el stock” suena a tarea de una tarde. Lees la cantidad en el ERP, la escribes en la tienda, listo. Y funciona. Durante dos semanas. Después aparece el primer producto vendido sin existencias, el primer SKU que se queda en 0 sin motivo y la primera conversación incómoda con el cliente.

No es mala suerte. Es que una sincronización entre dos sistemas que no se conocen tiene que estar diseñada para fallar bien, y casi nunca lo está. Estos son los cinco fallos que veo una y otra vez, y cómo los resuelvo. Los ejemplos salen de odoo-store-sync, un servicio open source que conecta Odoo con PrestaShop y que uso como base en proyectos reales.

Fallo 1: el mismo cambio se aplica dos veces

La red no es fiable. Una petición puede llegar al destino, aplicarse, y que la respuesta se pierda por el camino. El sistema que la envió cree que falló y la reenvía. Si la operación es “poner stock a 12”, no pasa nada. Si es “restar 3 unidades”, acabas de restar 6.

Y no hace falta que la red falle: un cron que se solapa con el anterior, un webhook que la plataforma reenvía “por si acaso”, dos instancias del servicio corriendo a la vez. Los duplicados son la norma, no la excepción.

Cómo se arregla. Cada operación lleva una clave de idempotencia: un identificador que describe exactamente ese cambio. En odoo-store-sync la clave es sku:cantidad:versión, donde la versión es el marcador de revisión del propio ERP (write_date en Odoo). La cola acepta cada clave una sola vez. Si el mismo cambio llega dos veces, la segunda se registra como skipped-unchanged (duplicate-job) y no toca la tienda.

Y una segunda red de seguridad: antes de escribir, el servicio compara la cantidad actual de la tienda con la que va a poner. Si ya coinciden, no escribe. Así una sincronización completa se puede relanzar las veces que haga falta sin romper nada.

Regla práctica: toda operación de escritura hacia la tienda tiene que poder ejecutarse dos veces con el mismo resultado que una. Si no puedes garantizar eso, no está lista.

Fallo 2: reintentar todo, siempre

Cuando algo falla, el reflejo es reintentar. Pero no todos los errores son iguales. Un timeout de red o un 503 del servidor merecen un segundo intento. Una clave de API caducada o un payload mal formado no: vas a fallar igual las diez veces, y de paso saturar al servidor que ya iba justo.

Peor todavía: reintentar sin esperar. Si la tienda ha devuelto un 429 porque la estás saturando, volver a pegarle inmediatamente es echar gasolina.

Cómo se arregla. Clasificar los errores. En el proyecto, solo los errores marcados como recuperables se reintentan: fallos de red, HTTP 429 y 5xx, y los bloqueos de concurrencia de la base de datos de Odoo. Errores de autenticación, respuestas inválidas y errores desconocidos fallan a la primera y quedan registrados.

Y los reintentos usan backoff exponencial con jitter: cada intento espera más que el anterior, con un componente aleatorio para que cien trabajos que fallan a la vez no vuelvan a pegar todos en el mismo milisegundo. El número de intentos es configurable y el registro guarda cuántos hicieron falta.

Fallo 3: el ERP y la tienda no hablan el mismo idioma de cantidades

Odoo permite stock negativo (vendiste antes de recibir) y cantidades con decimales (vendes a peso). Una tienda publica unidades enteras y no sabe qué hacer con un -3 o un 2,5. Si pasas el valor tal cual, el resultado va desde un error silencioso hasta un stock de 2,5 que el tema de la tienda pinta como “25”.

Cómo se arregla. Normalizar en la frontera. Las cantidades se redondean hacia abajo y se recortan a cero antes de salir hacia la tienda. Los productos sin referencia interna (sin SKU) no se sincronizan: se saltan y se reportan una vez por ejecución, para que alguien los arregle en el ERP en vez de inventar un emparejamiento.

Fallo 4: confiar en que la referencia es única

El emparejamiento entre sistemas suele hacerse por SKU o referencia. Parece sólido hasta que descubres que en PrestaShop dos productos comparten referencia porque alguien duplicó uno “para probar”, o que la base de datos compara sin distinguir mayúsculas y abc encuentra ABC.

Cómo se arregla. Si una referencia devuelve más de un producto en la tienda, ese SKU falla y queda en el registro. No se elige “el primero”. Adivinar es la forma más rápida de poner el stock de un producto en otro, y de no enterarte hasta que un cliente se queja.

Fallo 5: una API que no hace lo que parece

Cada plataforma tiene sus trampas. La API de PrestaShop, por ejemplo, no permite actualizar solo la cantidad de un stock_available: el PUT reemplaza el recurso entero. Si envías solo el campo que quieres cambiar, pierdes el resto. Y si la tienda usa la gestión avanzada de stock, las escrituras de cantidad se ignoran sin dar error.

Cómo se arregla. Leer el recurso completo, cambiar un solo campo y devolverlo entero. Y conocer la plataforma antes de prometer que “la API lo soporta”. Esto no se aprende en la documentación; se aprende rompiendo una tienda de pruebas, que para eso está el docker compose del proyecto con un Odoo y un PrestaShop locales.

Lo que une los cinco: saber qué pasó

Ninguno de estos arreglos sirve si nadie puede ver qué hizo la sincronización. Por eso cada operación produce una línea de registro estructurada con el SKU, la clave de idempotencia, el resultado (updated, skipped-unchanged, not-found-in-store, failed), los intentos y el cambio de cantidad. Sin secretos en los logs, y con los errores de configuración nombrando la variable, no el valor.

Cuando el cliente pregunta “¿por qué este producto marca 0?”, la respuesta está en una línea, no en una tarde de investigación.

Y la arquitectura, para que el ERP de hoy no sea la cárcel de mañana

El proyecto está construido en arquitectura hexagonal: el núcleo (qué es un SKU, qué es un nivel de stock, qué resultados puede tener una sincronización) no sabe nada de Odoo ni de PrestaShop. Los habla a través de puertos, y cada plataforma es un adaptador. Añadir WooCommerce o Shopify es escribir un adaptador nuevo sin tocar la lógica que ya funciona.

Para una agencia esto tiene una traducción directa: la próxima tienda del cliente, o el próximo cliente con otro ERP, no empieza de cero.


Si tienes una sincronización que “a veces falla” y nadie sabe por qué, lo más probable es que sea uno de estos cinco. Se diagnostica en una tarde y se arregla sin rehacer todo. Escríbeme y lo vemos.