Los fallos en la lógica de cupones pueden romper los totales de checkout. Aprende reglas de acumulación, exclusiones y patrones testables para evitar doble descuento y totales negativos.

Las promos parecen sencillas hasta que las pones en un checkout real. Un carrito cambia todo el tiempo, pero los descuentos a menudo se escriben como reglas puntuales. Ese hueco es donde aparecen la mayoría de los fallos en la lógica de cupones.
Lo difícil es que una sola regla nueva puede cambiar los totales en todos lados. Añade "10% de descuento, pero no en artículos en oferta" y tienes que decidir qué significa "oferta", cuándo se comprueba y sobre qué cantidad se aplica ese 10%. Si otra promo también afecta los mismos artículos, el orden importa, y el orden cambia el precio.
Muchos equipos también mezclan matemáticas con reglas de negocio. Un arreglo rápido como "limitar el descuento al subtotal" se copia en tres sitios, y pronto obtienes respuestas distintas según dónde se calcule el total (página del carrito, checkout, factura, correo).
Los momentos de alto riesgo son cuando tu sistema recomputa precios:
Un pequeño ejemplo: un comprador añade un paquete, luego aplica un código "$20 off $100", y después quita un artículo. Si tu código todavía "recuerda" el subtotal antiguo, puedes acabar dando $20 de descuento a un carrito de $85, o incluso dejar una línea de artículo en negativo.
Al final de este artículo deberías poder prevenir los fallos de promo más comunes: doble descuento, totales distintos entre pantallas, totales negativos, descuentos aplicados a artículos excluidos y reembolsos que no concuerdan con lo que el cliente pagó originalmente.
La mayoría de los fallos en la lógica de cupones comienzan por una frase que falta: qué descuentos pueden aplicarse juntos y en qué orden. Si no puedes explicar las reglas de acumulación en lenguaje sencillo, tu carrito acabará haciendo algo sorprendente.
Define la acumulación con afirmaciones simples de sí o no. Por ejemplo: "Un cupón manual por pedido. Las promos automáticas pueden seguir aplicándose a menos que el cupón diga que las bloquea." Esa línea evita combinaciones aleatorias que conducen a doble descuento.
Separa pronto los descuentos a nivel de artículo de los descuentos a nivel de pedido. Las reglas a nivel de artículo cambian el precio de productos específicos (por ejemplo, 20% en zapatos). Las reglas a nivel de pedido cambian el total (por ejemplo, $10 de descuento al carrito). Mezclarlas sin estructura hace que los totales diverjan entre la página de producto, el carrito y el checkout.
Decide qué significa "mejor oferta" antes de programar. Muchos equipos eligen "máximo ahorro", pero eso puede romper los pisos de precio. También podrías necesitar reglas como "nunca descontar por debajo del coste" o "nunca dejar el envío en negativo". Elige una regla ganadora clara para que el motor no adivine.
Un orden de prioridad simple mantiene los conflictos predecibles:
Ejemplo: un carrito tiene un 10% automático en todos los artículos y además un cupón escrito de $15 off en pedidos superiores a $100. Si tu prioridad dice que lo automático va primero, puedes responder claramente: ¿el umbral de $100 usa el subtotal antes del descuento o el subtotal después del descuento? Escríbelo y mantenlo coherente en todas partes.
Una vez escritas estas decisiones, tus reglas de acumulación de cupones se convierten en reglas comprobables, no en comportamientos ocultos. Esa es la forma más rápida de evitar fallos más adelante.
Muchos fallos comienzan cuando los descuentos viven como comprobaciones if-else dispersas por el código de checkout. Un enfoque más seguro es tratar cada promo como datos con un tipo, alcance y límites claros. Entonces las matemáticas del carrito se reducen a un evaluador pequeño y predecible.
Empieza nombrando el tipo de descuento, no la idea de marketing. La mayoría de las promos encajan en pocas formas: porcentaje, cantidad fija, artículo gratis (o compra X lleva Y) y envío gratis. Si puedes expresar una promo usando uno de estos tipos, evitas casos especiales difíciles de testear.
Después, haz el alcance explícito. Un mismo porcentaje se comporta muy distinto según a qué se dirija. Define si se aplica al pedido entero, a una categoría, a un producto, a una línea de artículo o al envío. Si el alcance es ambiguo, acabarás descontando del subtotal equivocado o descontando dos veces.
Captura las restricciones como campos, no como comentarios en el código. Las comunes son gasto mínimo, solo primer pedido y rango de fechas. También registra cómo debe comportarse con precios en oferta: acumula encima, aplicar al precio original o excluir artículos rebajados.
Un esquema compacto de regla podría incluir:
Finalmente, añade pisos de precio que el motor siempre debe respetar: totales nunca por debajo de cero, y si tu negocio lo exige, artículos nunca por debajo del coste (o por debajo de un precio mínimo definido). Si construyes esto, previenes totales negativos y casos extremos donde "pagamos al cliente".
Si prototipas un motor de descuentos en Koder.ai, mantén estos campos visibles en tu modo de planificación para que el evaluador siga simple y testeable a medida que añades más promos.
La mayoría de los fallos aparecen cuando las comprobaciones de elegibilidad y las matemáticas se mezclan. Un patrón más seguro es en dos fases: primero decide qué puede aplicarse, luego calcula los montos. Esa separación mantiene las reglas legibles y hace más fácil prevenir estados malos (como totales negativos).
Usa el mismo orden siempre, incluso si las promos llegan en distinto orden desde la UI o la API. La determinación importa porque convierte "¿por qué cambió este carrito?" en una pregunta que puedes responder.
Un flujo simple que funciona bien:
Cuando aplicas promos, no guardes solo un "total de descuento". Conserva un desglose por línea y por pedido para poder conciliar totales y explicarlos.
Como mínimo, registra:
Ejemplo: un carrito tiene dos artículos, uno ya en oferta. La Fase 1 marca el código elegible solo para el artículo a precio completo. La Fase 2 aplica 10% a esa línea, deja la línea en oferta sin cambios y luego recalcula los totales del pedido desde el desglose de líneas para no descontar doble por accidente.
La mayoría de los fallos empiezan cuando las exclusiones están escondidas dentro de ramas de casos especiales como "si el código es X, saltar Y." Funciona para una promo, luego falla cuando llega la siguiente.
Un patrón más seguro es: mantén un único flujo de evaluación y convierte las exclusiones en un conjunto de comprobaciones que pueden rechazar una combinación de promos antes de calcular dinero. Así los descuentos nunca se aplican a medias.
En vez de codificar comportamientos, da a cada promo un pequeño "perfil de compatibilidad" explícito. Por ejemplo: tipo de promo (cupón vs venta automática), alcance (artículos, envío, pedido) y reglas de combinación.
Soporta ambos:
La clave es que tu motor haga las mismas preguntas para cada promo y luego decida si el conjunto es válido.
Las ventas automáticas suelen aplicarse primero, y luego llega un cupón que las anula silenciosamente. Decide desde el inicio qué debe ocurrir:
Elige una por promo y codifícala como una comprobación, no como una ruta de cálculo alternativa.
Una forma práctica de evitar sorpresas es validar la simetría. Si "WELCOME10 no puede combinarse con FREESHIP" debe ser mutuo, codifícalo para que bloquee en ambas direcciones. Si no es mutuo, que sea intencional y visible en los datos.
Ejemplo: hay una venta automática del 15% en todo el sitio. Un cliente introduce un cupón del 20% pensado solo para artículos a precio completo. Tus comprobaciones deberían rechazar los artículos en oferta para el cupón antes de calcular totales, en lugar de descontarlos y luego intentar arreglar las cifras.
Si construyes tus reglas en una plataforma como Koder.ai, mantén estas comprobaciones como una capa separable y testeable para cambiar reglas sin reescribir las matemáticas.
La mayoría de las disputas sobre promos no se deben al descuento principal. Ocurren cuando el mismo carrito se calcula de dos formas ligeramente diferentes, y el cliente ve un número en el carrito y otro en el checkout.
Empieza por bloquear tu orden de operaciones. Decide y documenta si los descuentos a nivel de artículo ocurren antes de los descuentos a nivel de pedido, y dónde encaja el envío. Una regla común es: descuentos de artículo primero, luego descuento de pedido sobre el subtotal restante, luego descuentos de envío al final. Sea lo que elijas, usa la misma secuencia exacta donde sea que muestres un total.
Los impuestos son la siguiente trampa. Si tus precios incluyen impuestos, un descuento reduce también la porción de impuesto. Si los precios excluyen impuestos, el impuesto se calcula después de los descuentos. Mezclar estos modelos en distintas partes del flujo es uno de los fallos clásicos porque dos cálculos correctos pueden discrepar si asumen bases de impuesto diferentes.
Los problemas de redondeo parecen pequeños pero generan muchos tickets de soporte. Decide si redondeas por línea (cada SKU después del descuento) o solo a nivel de pedido, y mantente con la precisión de la moneda. Con cupones porcentuales, el redondeo por línea puede desviarse por unos centavos frente al redondeo por pedido, sobre todo con muchos artículos de bajo precio.
Estos casos límite valen la pena tratarlos explícitamente:
Un ejemplo concreto: un cupón de 10% al pedido más envío gratis en pedidos superiores a $50. Si el cupón se aplica antes de comprobar el umbral, el subtotal descontado puede quedar por debajo de $50 y el envío deja de ser gratis. Elige una interpretación, codifícala y mantenla consistente en carrito, checkout y reembolsos.
La mayoría de los fallos aparecen cuando el carrito se evalúa por más de una vía. Una promo puede aplicarse a nivel de línea en un lugar y de nuevo a nivel de pedido en otro, y ambas pueden parecer "correctas" por separado.
Aquí están los bugs que aparecen con más frecuencia y la causa habitual detrás de cada uno:
Un ejemplo concreto: un carrito tiene dos artículos, uno elegible y otro excluido. Si el motor calcula correctamente el "subtotal elegible" para la promo porcentual, pero después resta un descuento fijo del total del pedido completo, el artículo excluido acaba siendo descontado igualmente.
El patrón más seguro es calcular cada promo contra una "cantidad elegible" explícita y devolver un ajuste acotado (nunca por debajo de cero), además de una traza clara de qué tocó. Si generas tu motor de descuentos en una herramienta como Koder.ai, haz que emita la traza como datos para que tus pruebas puedan afirmar exactamente qué líneas fueron elegibles y qué subtotal se usó.
La mayoría de los fallos aparecen porque las pruebas solo verifican el total final. Una buena suite comprueba tanto la elegibilidad (¿debería aplicarse esta promo?) como las matemáticas (¿cuánto debería descontar?), con un desglose legible que puedas comparar con el tiempo.
Comienza con tests unitarios que aislen una regla a la vez. Mantén la entrada pequeña y luego amplía a escenarios completos.
Después de tener cobertura, añade algunas comprobaciones "siempre verdaderas". Estas detectan los casos raros que no pensaste escribir a mano.
Imagina un carrito con 2 artículos: una camiseta a $40 (elegible) y una tarjeta regalo a $30 (excluida). Envío $7. Una promo es "20% en ropa, máximo $15", y otra es "$10 off en pedidos > $50" que no puede acumularse con descuentos porcentuales.
Tu test de escenario debe afirmar qué promo gana (por prioridad), confirmar que la tarjeta regalo está excluida y verificar la asignación exacta: 20% de $40 es $8, envío sin cambios, total final correcto. Guarda ese desglose como un snapshot dorado para que futuros refactors no cambien silenciosamente qué promo se aplica o que empiecen a descontar líneas excluidas.
Antes de activar una nueva promo, haz una pasada final con una checklist que atrape las fallas que los clientes notan al instante: totales raros, mensajes confusos y reembolsos que no cuadran. Estas comprobaciones también ayudan a evitar los fallos más comunes porque obligan a que las reglas se comporten igual en cada carrito.
Corre estas comprobaciones contra un pequeño conjunto de "carritos complicados conocidos" (un artículo, muchos artículos, tasas de impuesto mixtas, envío y una línea de alta cantidad). Guarda los carritos para volver a ejecutarlos cada vez que cambies código de precios.
Si construyes tus reglas de descuento en un generador como Koder.ai, añade estos casos como tests automatizados junto a las definiciones de reglas. El objetivo es simple: cualquier promo futura debe fallar rápido en tests en lugar de fallar en el carrito de un cliente.
Aquí tienes un carrito pequeño que expone la mayoría de los fallos sin complicarlo demasiado.
Asume estas reglas (escríbelas exactamente así en tu sistema):
Carrito:
| Linea | Precio | Notas |
|---|---|---|
| Artículo A | $60 | precio completo, elegible |
| Artículo B | $40 | precio completo, elegible |
| Artículo C | $30 | artículo en oferta, excluido |
| Envío | $8 | tarifa |
Promos:
Comprueba el mínimo del cupón: la mercancía elegible antes de descuentos es $60 + $40 = $100, así que el cupón puede aplicarse.
Aplica Promo 1 (10% en artículos elegibles): $100 x 10% = $10 de descuento. El subtotal elegible pasa a $90.
Aplica Promo 2 ($15 off): el tope es $90, así que aplica el $15 completo. Nuevo subtotal elegible: $75.
Totales:
Ahora cambia una cosa: el cliente quita el Artículo B ($40). La mercancía elegible pasa a $60, así que el cupón falla la comprobación de gasto mínimo. Solo queda la promo automática del 10%: el Artículo A queda $54, la mercancía es $54 + $30 = $84, y el total final pasa a $99.36. Este es el tipo de "pequeña edición" que suele romper carritos si la elegibilidad y el orden no son explícitos.
La forma más rápida de evitar fallos es tratar las promos como reglas de producto, no como "un poco de matemática en el checkout." Antes de lanzar, escribe una especificación corta que cualquiera en el equipo pueda leer y aceptar.
Incluye cuatro cosas, en lenguaje claro:
Tras el lanzamiento, vigila los totales como vigilas los errores. Un bug de descuento a menudo parece un pedido válido hasta que finanzas lo revisa.
Configura monitorización que marque pedidos con patrones inusuales, como totales cercanos a cero, totales negativos, descuentos mayores que el subtotal o picos repentinos en carritos "100% off." Dirige las alertas al mismo sitio donde van los errores de checkout y mantén un pequeño playbook sobre cómo desactivar una promo de forma segura.
Para añadir nuevas promos sin regresiones, usa un flujo repetible: actualiza la especificación primero, codifica la regla como datos (no como ramas), añade tests para algunos carritos "normales" más uno o dos casos límite, y luego ejecuta la suite completa de tests de descuento antes de hacer merge.
Si quieres implementar e iterar más rápido, puedes prototipar flujos del motor de promos en Koder.ai usando el modo de planificación, luego usar snapshots y rollback mientras afinas tus tests. Te ayuda a probar cambios de reglas rápidamente sin perder una versión conocida y estable.