Cupón de descuento en el carrito


Permite que tus clientes apliquen un cupón de descuento desde el carrito, y reemplaza el resumen de totales por el componente que ya incluye el descuento del cupón.



Son dos componentes que se integran juntos:

  • coupon-input: el campo para ingresar el código, con los botones de aplicar y quitar.
  • cart-totals: el resumen del carrito (subtotal, promociones, descuento del cupón, costo de envío, total, descuento por medio de pago y cuotas).

Importante: la fila del descuento del cupón la renderiza cart-totals. Si integrás solo coupon-input, el cupón se aplica pero el cliente no ve el descuento reflejado en el resumen. Los dos componentes van juntos.


HTML

1. Agregá el campo de cupón

El resumen del carrito vive en snipplets/cart-totals.tpl y lo usan tanto la página del carrito (templates/cart.tpl) como el carrito de compras rápidas (snipplets/cart-panel.tpl).

Verificá desde qué archivos se incluye:

{# templates/cart.tpl #}
{% include "snipplets/cart-totals.tpl" with {'cart_page': true} %}

{# snipplets/cart-panel.tpl #}
{% include "snipplets/cart-totals.tpl" %}

Al integrar los componentes en ese único archivo, quedan cubiertos los dos contextos.

Dentro del contenedor del resumen, antes de los totales, agregá el componente coupon-input:

{# Coupon input #}

{% if settings.cart_coupon %}
  <div class="js-visible-on-cart-filled" {% if cart.items_count == 0 %}style="display:none;"{% endif %}>
    {{ component('coupon-input', {
      svg_sprites: false,
      label_custom_icon: include('snipplets/svg/tag.tpl', {svg_custom_class: 'icon-inline icon-w-18 icon-lg svg-icon-text mr-2 align-text-bottom'}),
      toggle_inactive_custom_icon: include('snipplets/svg/chevron-down.tpl', {svg_custom_class: 'icon-inline svg-icon-text'}),
      toggle_active_custom_icon: include('snipplets/svg/chevron-up.tpl', {svg_custom_class: 'icon-inline svg-icon-text'}),
      container_classes: {
        container: 'mb-3',
        content: 'pt-2',
        toggle: 'd-flex align-items-center justify-content-between',
        toggle_label: 'd-flex align-items-center',
        applied_row: 'd-flex align-items-center justify-content-between mt-2',
        applied_code: cart_page ? 'mr-4' : 'mr-4 font-weight-bold',
        remove_button: 'btn btn-secondary btn-small float-right py-1 px-2 px-sm-3',
        form: 'form-group mb-0 mt-2',
        input_wrapper: 'd-flex form-group-inline align-items-center',
        input: 'form-control col-6 col-lg-7 pr-0',
        apply_button: 'btn btn-default btn-block',
        error: 'alert alert-danger mb-0 mt-2',
      }
    }) }}

    {# Divider between coupon input and subtotal #}
    <div class="divider"></div>
  </div>
{% endif %}

Consideraciones:

  • El {% if settings.cart_coupon %} se activa desde el Administrador nube, en la sección de Personalizar tu diseño actual dentro de Carrito de compras.

  • El contenedor con js-visible-on-cart-filled hace que el bloque se oculte cuando el carrito queda vacío. El divisor va adentro del contenedor para que se oculte junto con el campo.

  • Los íconos se pasan según el patrón de tu diseño. Antes de crear uno nuevo, revisá si ya existe en tu diseño (buscá en snipplets/svg/): la etiqueta y las flechas suelen estar disponibles.

    • Si tu diseño tiene un archivo por ícono (como Base), pasá svg_sprites: false y los íconos con include(...), como en el ejemplo.

    • Si tu diseño usa un sprite (un único archivo con <symbol>), pasá los IDs en lugar de los includes:

      label_svg_id: 'tag',
      toggle_inactive_svg_id: 'chevron-down',
      toggle_active_svg_id: 'chevron-up',
  • Si querés mostrar un spinner en los botones mientras se aplica el cupón, pasá spinner_svg_id o spinner_custom_icon. Si no los pasás, no se muestra spinner y los botones solo cambian el texto a "Aplicando" / "Quitando".

2. Reemplazamos el resumen de totales

Reemplazá el HTML del subtotal, promociones, costo de envío, total y cuotas por el componente cart-totals:

{# Cart totals: subtotal, promos, coupon discount, shipping cost, total, payment/installments #}

{% set discount_accent = 'text-accent font-weight-bold' %}
{% set free_shipping_accent = cart.free_shipping.cart_has_free_shipping ? discount_accent : 'opacity-40' %}
{% set summary_weight = cart_page ? 'font-weight-normal' %}

{{ component('cart-totals', {
  shipping_enabled: show_cart_fulfillment,
  payment_discount_price_enabled: settings.payment_discount_price,
  installments_enabled: not settings.payment_discount_price,
  totals_divider: true,
  container_classes: {
    subtotals: 'd-grid',
    totals: 'mb-3',
    totals_divider: 'divider',
  },
  text_classes: {
    subtotal: 'h5 justify-content-between d-flex my-1 ' ~ summary_weight,
    subtotals_prices: 'text-right',
    price_without_taxes: 'd-flex justify-content-between mb-2 font-small opacity-60',
    price_without_taxes_price: 'text-right',
    discounts_row: 'd-flex flex-wrap justify-content-between mb-1',
    discounts_price: discount_accent,
    shipping_costs: 'd-flex justify-content-between h5 ' ~ summary_weight,
    shipping_costs_price: free_shipping_accent,
    shipping_costs_calculating: 'opacity-40',
    shipping_costs_empty: 'opacity-40',
    total: 'd-flex justify-content-between h2 text-primary',
    total_price: 'text-right',
    payment_discount_and_installments: 'text-right mt-1',
    payment_discount_price: 'text-accent font-small font-weight-normal mt-1',
    installments: 'text-accent font-small font-weight-normal',
  },
}) }}

Consideraciones:

  • No borres los elementos ocultos que usa el JS de la plataforma para calcular totales, porque el componente ya los incluye:

    <div class="js-subtotal-price subtotal-price hidden" data-priceraw="{{ cart.total }}"></div>
    <div id="store-curr" class="hidden">{{ cart.currency }}</div>
    <div class='total-price hidden'>{{ "Total" | translate }}: {{ cart.total | money }}</div>
  • shipping_enabled controla la fila del costo de envío. En Base se pasa la misma condición que usa el calculador de envío del carrito:

    {% set show_cart_fulfillment = settings.shipping_calculator_cart_page and (store.has_shipping or store.branches) %}

3. Parámetros disponibles

Podés ver todos los parámetros y clases de ambos componentes, con ejemplos, en Componentes privados.


CSS

Requisito: Tener agregados en tu diseño las clases helpers. Podés seguir este este pequeño tutorial para hacerlo (simplemente es copiar y pegar algunas clases, no toma más de 1 minuto).

1. Agregá el helper .d-grid

Agregar display: grid para el contenedor de subtotales.

/* // Display */
.d-grid{display:grid!important}

2. Borrá el CSS viejo de las promociones

Los diseños antiguos estilaban las filas de promociones con porcentajes y floats, pensados para un HTML que ya no se usa. En Base había que borrar esto de static/css/style-async.scss.tpl:

.cart-promotion-detail{
  float: left;
  width: 65%;
  text-align: left;
}
.cart-promotion-number{
  position: absolute;
  right: 0;
  bottom: 0;
  width: 35%;
  float: right;
  text-align: right;
}
.total-promotions-row{
  float: right;
  width: 100%;
  margin-bottom: 10px;
  position: relative;
}
.cart-total{
  clear: both;
  margin: 10px 0;
  font-weight: bold;
}

Si no borrás el width: 65%, la fila de la promoción queda angosta y el monto aparece en el medio del contenedor en lugar de a la derecha.

3. Estilá la fila de promociones que renderiza el JS

Cuando el cliente cambia cantidades o agrega productos, la plataforma vuelve a dibujar las filas de promociones por JavaScript, con clases fijas que no se pueden pasar por parámetros. Para que esa versión se vea igual que la que se renderiza al recargar la página, agregá en static/css/style-async.scss.tpl:

.total-promotions-row{
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  width: 100%;
  margin: 0 0 5px 0;
}
.cart-promotion-detail{
  text-align: left;
}
.cart-promotion-number{
  margin-left: auto;
  text-align: right;
  font-weight: bold;
}
.total-promotions-row .cart-promotion-number {
  color: $accent-color;
}

JS

El cupón no necesita JavaScript propio: se inicializa con el JS de la plataforma. Lo único a agregar es la actualización del costo de envío, porque cart-totals suma esa fila al resumen. Sin esto, la fila queda siempre en "Calculalo para verlo".

⚠️ Si tu diseño tiene store.js.tpl y store-v2.js.tpl, hacé el cambio solo en store-v2.js.tpl.

1. En store.js.tpl (o donde tengas tus funciones de JS), agregá:

{% set shipping_calculator_enabled = settings.shipping_calculator_cart_page %}

{% if shipping_calculator_enabled %}

    var $selectedShipping = jQueryNuvem('.js-selected-shipping-method');
    if ($selectedShipping.length) {
        LS.ShippingDiscountRow.apply($selectedShipping[0], { containerSelector: '#cart-shipping-container' });
        jQueryNuvem("#shipping-cost").removeClass('opacity-40');
    }

{% endif %}

2. Dentro de la función que maneja la selección de envío, agregá:

selectShippingOption = function(elem, save_option) {
    jQueryNuvem(".js-shipping-method, .js-branch-method").removeClass('js-selected-shipping-method');
    jQueryNuvem(elem).addClass('js-selected-shipping-method');

    {% if shipping_calculator_enabled %}

        LS.ShippingDiscountRow.apply(elem, { containerSelector: '#cart-shipping-container' });
        jQueryNuvem("#shipping-cost").removeClass('opacity-40');

    {% endif %}

    if (save_option) {
        LS.saveCalculatedShipping(true);
    }
    ...
};

Traducciones

Lo único que necesita traducción es el texto de la nueva opción del panel. Agregá en config/translations.txt:

es "Cupones de descuento"
pt "Cupons de desconto"
en "Discount coupons"
es_mx "Cupones de descuento"

es "Permitir que tus clientes apliquen un cupón de descuento en el carrito"
pt "Permitir que seus clientes apliquem um cupom de desconto no carrinho"
en "Allow your customers to apply a discount coupon in the cart"
es_mx "Permitir que tus clientes apliquen un cupón de descuento en el carrito"

es "<a target='_blank' href='https://ayuda.tiendanube.com/es_AR/123465-cupones-y-promociones/que-son-los-cupones-de-descuento' class='js-checkbox-help-link'>Más sobre cupones de descuento</a>"
pt "<a target='_blank' href='https://atendimento.nuvemshop.com.br/cupons/como-criar-cupons-de-desconto' class='js-checkbox-help-link'>Mais sobre cupons de desconto</a>"
en "<a target='_blank' href='https://ayuda.tiendanube.com/es_AR/123465-cupones-y-promociones/que-son-los-cupones-de-descuento' class='js-checkbox-help-link'>More about discount coupons</a>"
es_mx "<a target='_blank' href='https://ayuda.tiendanube.com/es_AR/123465-cupones-y-promociones/que-son-los-cupones-de-descuento' class='js-checkbox-help-link'>Más sobre cupones de descuento</a>"

Activación

1. Agregá la opción al panel de diseño

En config/settings.txt, al final de la sección Carrito de compras, agregá el checkbox:

    title
        title = Cupones de descuento
    checkbox
        name = cart_coupon
        description = Permitir que tus clientes apliquen un cupón de descuento en el carrito
    subtitle
        subtitle = <a target='_blank' href='https://ayuda.tiendanube.com/es_AR/123465-cupones-y-promociones/que-son-los-cupones-de-descuento' class='js-checkbox-help-link'>Más sobre cupones de descuento</a>

2. Activá la opción en la tienda

En el panel de administración, andá a Mi Tienda Nube → Diseño → Configurar diseño actual → Carrito de compras y activá "Permitir que tus clientes apliquen un cupón de descuento en el carrito".