Calculador de envíos

En el siguiente tutorial, explicamos cómo agregar el calculador de envíos y los locales físicos en tu diseño:

El código en este tutorial incluye:

  • El calculador de envíos, tanto en el detalle del producto como en el carrito
  • El filtro entre opciones de envio similares. Este destaca la mejor opción de envío y oculta el resto en un link de “Ver más opciones”. No aplica a medios de envío personalizados.
  • Fechas de envío exactas en lugar de tiempo estimado en días
  • Selector de locales físicos (solo para tiendas que no son de Brasil)
  • Mensaje sobre el envío gratis (solo aplica a tiendas de argentina que usan el medio de envío OCA)

Debajo del subtotal se puede ver un ejemplo del calculador y los locales.

A la izquierda las opciones de envío desplegadas y a la derecha las opciones menos relevantes, visibles al hacer click en “Ver más opciones”.

HTML

Lo primero que vamos a hacer es crear los tpls necesarios para la funcionalidad.

1. Agregamos la carpeta con el nombre shipping dentro de la carpeta snipplets 

2. Dentro de esta carpeta creamos los siguientes archivos, cada uno con su respectivo código. Es importante mantener los IDs y las clases “js-...” para garantizar su funcionamiento cuando agreguemos el JavaScript.

branches.tpl

Este archivo representa el selector de locales físicos que sólo están visibles para tiendas que no son de Brasil. El código es el siguiente:

<div class="js-toggle-branches w-100">
    <span class="form-row">
        <div class="col-auto">
            {% include "snipplets/svg/store.tpl" with {svg_custom_class: "icon-inline icon-lg link-module-icon svg-icon-text"} %}
        </div>
        <div class="col-6">
            <div class="mb-1"> 
                {% if store.branches|length > 1 %}
                    {{ 'Retirá gratis en nuestros locales' | translate }}
                {% else %}
                    {{ 'Retirá gratis en nuestro local' | translate }}
                {% endif %}
            </div>
            <div class="btn-link float-left">
                {% if product_detail %}
                    <span class="js-see-branches">
                        {% if store.branches|length > 1 %}
                            {{ 'Ver locales' | translate }}
                        {% else %}
                            {{ 'Ver local' | translate }}
                        {% endif %}
                    </span>
                {% else %}
                    <span>
                        {{ 'Elegir local' | translate }}
                    </span>
                {% endif %}
                {% include "snipplets/svg/chevron-down.tpl" with {svg_custom_class: "js-see-branches icon-inline ml-1"} %}


                <span class="js-hide-branches" style="display: none;">
                    {% if product_detail %}
                        {% if store.branches|length > 1 %}
                            {{ 'Ocultar locales' | translate }}
                        {% else %}
                            {{ 'Ocultar local' | translate }}
                        {% endif %}
                    {% endif %}
                    {% include "snipplets/svg/chevron-up.tpl" with {svg_custom_class: "icon-inline ml-1"} %}
                </span>
            </div>
        </div>
    </span>
</div>


{# Store branches #}


{% if not product_detail %}
    
    <ul class="js-store-branches-container list-unstyled radio-button-container mt-3" style="display: none;">


        {# Selectable branches #}


        {% for branch in store.branches %}
            <li class="radio-button-item">
                <label class="js-shipping-radio js-branch-radio radio-button" data-loop="branch-radio-{{loop.index}}">
                <input 
                    class="js-branch-method {% if cart.shipping_data.code == branch.code %} js-selected-shipping-method {% endif %} shipping-method" 
                    data-price="0" 
                    {% if cart.shipping_data.code == branch.code %}checked{% endif %} type="radio" 
                    value="{{branch.code}}" 
                    data-name="{{ branch.name }} - {{ branch.extra }}"
                    data-code="{{branch.code}}" 
                    data-cost="{{ 'Gratis' | translate }}"
                    name="option" 
                    style="display:none">
                    <span class="shipping-option row-fluid radio-button-content">
                       <span class="radio-button-icons">
                            <span class="radio-button-icon unchecked"></span>
                            <span class="radio-button-icon checked"></span>
                            <span class="radio-button-icon checked checked-invert"></span>
                        </span>
                        <span class="radio-button-label">
                            <h6 class="text-primary mb-1 d-inline-block">{{ 'Gratis' | translate }}</h6>
                            <span class="radio-button-text">
                                {{ branch.name }} - {{ branch.extra }}
                            </span>
                        </span>
                    </span>
                </label>
            </li>
        {% endfor %}
    </ul>
{% else %}
    <ul class="js-store-branches-container list-unstyled list mt-3" style="display: none;">
        {% for branch in store.branches %}
            <li class="list-item">
                <span class="list-item-content">
                    <h6 class="text-primary mb-1">{{ 'Gratis' | translate }}</h6>
                    <div>{{ branch.name }} - {{ branch.extra }}</div>
                </span>
            </li>
        {% endfor %}
    </ul>
{% endif %}

shipping-calculator.tpl

Es el componente para el calculador de envíos. Incluye un input, un botón, el mensaje de error y un mensaje que muestra el monto mínimo para lograr envío gratis, así como un mensaje notificando que el envío gratis fue alcanzado al superar este monto (esto solo aplica a tiendas que usen OCA).  

{% if shipping_calculator_show %}
    <div class="{% if product_detail %}product-shipping-calculator{% endif %} {% if store.branches and store.country != 'BR' %}mb-4{% else %}mb-2{% endif %}">
        <div class="js-shipping-calculator-form">


            {# Shipping calcualtor input #}
            
            {% embed "snipplets/forms/form-input.tpl" with{type_tel: true, input_value: cart.shipping_zipcode, input_name: 'zipcode', input_custom_class: 'js-shipping-input', input_placeholder: "Código postal" | translate, input_label: false, input_append_content: true, input_group_custom_class: 'form-row align-items-center mb-3', form_control_container_custom_class: 'col-5'} %}
                {% block input_prepend_content %}
                    <div class="col-12 mb-2">


                        {% include "snipplets/svg/truck.tpl" with {svg_custom_class: "icon-inline icon-w-18 icon-lg svg-icon-text mr-2"} %}


                        {# Free shipping achieved label #}


                        <span class="js-free-shipping-message" {% if not free_shipping.cart_has_free_shipping %}style="display: none;"{% endif %}>
                            {{ "¡Genial! <strong class='text-primary'>Tenés envío gratis</strong> en esta compra" | translate }}
                        </span>


                        {# Free shipping with min price label #}


                        <span class="js-shipping-calculator-label" {% if free_shipping.cart_has_free_shipping or not free_shipping.min_price_free_shipping.min_price %}style="display: none;"{% endif %}>
                            {{ "<strong class='text-primary'>Envío gratis</strong> superando los" | translate }} <span>{{ free_shipping.min_price_free_shipping.min_price }}</span>
                        </span>


                        {# Shipping default label #}


                        <span class="js-shipping-calculator-label-default" {% if free_shipping.cart_has_free_shipping or free_shipping.min_price_free_shipping.min_price %}style="display: none;"{% endif %}>


                            {# Regular shipping calculator label #}
                            
                            {{ 'Costos de envío' | translate }}
                        </span>
                    </div>
                {% endblock input_prepend_content %}
                {% block input_form_alert %}
                <div class="col-12">
                    <div class="js-ship-calculator-error invalid-zipcode alert alert-danger" style="display: none;">{{ "No encontramos este código postal. ¿Está bien escrito?" | translate }}</div>
                    <div class="js-ship-calculator-error js-ship-calculator-common-error alert alert-danger" style="display: none;">{{ "Ocurrió un error al calcular el envío. Por favor intentá de nuevo en unos segundos." | translate }}</div>
                    <div class="js-ship-calculator-error js-ship-calculator-external-error alert alert-danger" style="display: none;">{{ "El calculo falló por un problema con el medio de envío. Por favor intentá de nuevo en unos segundos." | translate }}</div>
                </div>
                {% endblock input_form_alert %}
                {% block input_append_content %}
                <span class="col-6">
                    <button class="js-calculate-shipping btn btn-default btn-block">    
                        <span class="js-calculate-shipping-wording">{{ "Calcular" | translate }}</span>
                        <span class="js-calculating-shipping-wording" style="display: none;">{{ "Calculando" | translate }}</span>
                        <span class="loading" style="display: none;">
                            {% include "snipplets/svg/sync-alt.tpl" with {svg_custom_class: "icon-inline svg-icon-text icon-spin"} %}
                        </span>
                    </button>
                    {% if shipping_calculator_variant %}
                        <input type="hidden" name="variant_id" id="shipping-variant-id" value="{{ shipping_calculator_variant.id }}">
                    {% endif %}
                </span>
                {% endblock input_append_content %}
            {% endembed %}
        </div>
        <div class="js-shipping-calculator-response mb-3 float-left w-100 {% if product_detail %}list{% endif %}" style="display: none;"></div>
    </div>
{% endif %}

shipping-calculator-item.tpl

Este es el item dentro del listado de opciones de envío. Dentro de este se puede mostrar:

VariableDescripción
option.short_nameNombre del medio de envío
option.costPrecio. Si option.cost == 0 se muestra la palabra grátis.
option.old_costPrecio viejo cuando es una opción de OCA con envío gratis
option.time Tiempo con formato en días, por ejemplo “5 días hábiles”
option.timeTiempo con formato en fechas, por ejemplo “Llega entre el martes 07/08 y el miércoles 09/08”. Recomendamos usar está opción ya que es más fácil de entender para el usuario.
option.payment_rulesUn mensaje si el medio de envío está disponible solo para un determinado medio de pago

Además si el medio de envío tiene subopciones incluimos el tpl de la carpeta shipping_suboptions (que vamos a agregar luego). Aplica solo a tiendas de argentina con el medio de envío OCA por ahora.

Y también hay un mensaje de alerta en caso que necesitemos mostrar alguna condición extra en el medio de envío. Esto es definido desde el PHP de Tiendanube.

También el condicional  featured_option sobre el input radio. Este sirve para diferenciar las opciones de envío destacadas de las menos prioritarias a la hora de incluirlo en el tpl shipping_options.tpl (que incluiremos luego). Recordemos que este filtrado no incluye locales ni medios de envío personalizados.

El código es el siguiente:

<li class="js-shipping-list-item radio-button-item">
    <label class="js-shipping-radio radio-button list-item" data-loop="shipping-radio-{{loop.index}}">
        <input 
        id="{% if featured_option %}featured-{% endif %}shipping-{{loop.index}}" 
        class="js-shipping-method {% if not featured_option %}js-shipping-method-hidden{% endif %} shipping-method" 
        data-price="{{option.cost.value}}" 
        data-code="{{option.code}}" 
        data-name="{{option.name}}" 
        data-cost="{% if option.show_price %} {% if option.cost.value == 0  %}{{ 'Gratis' | translate }}{% else %}{{option.cost}}{% endif %}{% else %} {{ 'A convenir' | translate }} {% endif %}" 
        type="radio" 
        value="{{option.code}}" 
        {% if featured_option and loop.first %}checked="checked"{% endif %} name="option" 
        style="display:none" />
        <span class="radio-button-content">
            <span class="radio-button-icons">
                <span class="radio-button-icon unchecked"></span>
                <span class="radio-button-icon checked"></span>
            </span>
            <span class="radio-button-label">


                {# Improved shipping option with no carrier img and ordered shipping info #}
                
                <div class="radio-button-text"> 
                    {% if option.show_price %} 
                        <div class="mb-1 d-inline-block">
                            <span class="text-primary h6">
                                {% if option.cost.value == 0  %}
                                    {{ 'Gratis' | translate }}
                                {% else %}
                                    {{option.cost}}
                                {% endif %}
                            </span>
                            {% if option.cost.value == 0 and option.old_cost.value %}
                                <span class="price-compare text-foreground font-small ml-1">{{option.old_cost}}</span>
                            {% endif %}
                        </div>
                    {% endif %}
                    {% if option.time %}
                        <div>
                            <strong>
                            {% if store.has_smart_dates %}
                                {{option.dates}}
                            {% else %}
                                {{option.time}}
                            {% endif %}
                            </strong>
                        </div>
                    {% endif %}
                </div>
                <div class="radio-button-text">
                    {{option.short_name}} {{ option.method == 'branch'  ? option.extra.extra  :  '' }}
                </div>
                {% if option.payment_rules %}
                    <div>
                        {% include "snipplets/svg/info-circle.tpl" with {svg_custom_class: "icon-inline svg-icon-text"} %}
                        <i>{{option.payment_rules}}</i>
                    </div>
                {% endif %}


                {% if option.suboptions is not empty %}
                    {% include "snipplets/shipping_suboptions/#{option.suboptions.type}.tpl" with {'suboptions': option.suboptions} %}
                {% endif %}


                {% if option.warning['enable'] %}
                    <div class="alert alert-warning">
                      <p>{{ option.warning['message'] }}</p>
                    </div>
                {% endif %}
            </span>
        </span>
    </label>
</li>

3. Creamos el archivo shipping_options.tpl dentro de la carpeta snipplets. No debe cambiar su nombre ni ubicación ya que lo usamos desde el PHP de Tiendanube para mostrarlo dentro del div con la clase js-shipping-calculator-response en el tpl shipping-calculator.tpl

Dentro de este snipplet se construyen ambos listados de opciones de envío, la priorizadas y la que se ocultan en el link de “Ver más opciones”.

{% if options %}
    {% if store.has_smart_dates and show_time %}
        <div class="radio-group-label mb-3">{{"El tiempo de entrega no considera feriados." | translate}}</div>
    {% endif %}
    <ul class="list-unstyled">


        {# Smart shipping hides similar shipping options on a toggle div and also shows an improved shipping item #}


        {# Check if smart shipping is needed #}


        {% set has_options_to_hide = false %}


        {% for option in options_to_hide %}
            {% if options_to_hide|length >= 1 %}
                {% set has_options_to_hide = true %}
            {% endif %}
        {% endfor %}


        {% for option in options_to_show if store.country == 'BR' or option.img_code != "branch" %}
            {% include "snipplets/shipping/shipping-calculator-item.tpl" with {'featured_option': true} %}
        {% endfor %}


        {% if has_options_to_hide %}
            <div class="js-show-more-shipping-options d-inline-block w-100 mt-3 text-center">
                <a href="#" class="btn-link">
                    <span class="js-shipping-see-more">
                        {{ 'Ver más opciones' | translate }}
                        {% include "snipplets/svg/chevron-down.tpl" with {svg_custom_class: "icon-inline ml-1"} %}
                    </span>
                    <span class="js-shipping-see-less" style="display: none;">{{ 'Ver menos opciones' | translate }}
                        {% include "snipplets/svg/chevron-up.tpl" with {svg_custom_class: "icon-inline ml-1"} %}
                    </span>
                </a>
            </div>
            <div class="js-other-shipping-option w-100 mt-3" style="display: none;">
                {% for option in options_to_hide if store.country == 'BR' or option.img_code != "branch" %}
                    {% include "snipplets/shipping/shipping-calculator-item.tpl" %}
                {% endfor %}
                </div>
        {% endif %}
    </ul>


    <div class="js-product-shipping-label font-small mt-3 pull-left" style="display: none;">
        <span class="js-shipping-filled-cart js-visible-on-cart-filled" {% if cart.items_count == 0 %}style="display:none;"{% endif%}>
            {% include "snipplets/svg/info-circle.tpl" with {svg_custom_class: "icon-inline svg-icon-text"} %}
            <span>{{ 'El precio de envío incluye este producto y todos los que agregaste al carrito.' | translate }}</span>
        </span>
    </div>
{% else %}
<span>{{"No hay costos de envío para el código postal dado." | translate}}</span>
{% endif %}


{# Don't remove this #}
<input type="hidden" name="after_calculation" value="1"/>
<input type="hidden" name="zipcode" value="{{zipcode}}"/>

4. Agregamos la carpeta shipping_suboptions dentro de la carpeta snipplet y por último creamos un tpl llamado select.tpl.

Este muestra subopciones en forma de un select para los medios de envío que necesiten mostrarlas, por ahora solo aplica a las sucursales de OCA.

{% set selected_option = loop.first or cart.shipping_option == option.name %}
<div class="js-shipping-suboption {{suboptions.name}}">
    {% if suboptions.options %}


        <p class="js-shipping-suboption-product mb-1" style="display: none;">{{ 'Podrás elegir alguna de las siguientes opciones antes de finalizar la compra:' | translate }}</p>


        {# Read only suboptions #}
        <ul class="js-shipping-suboption-list" name="{{suboptions.name}}" style="display: none;">
            {% for option in suboptions.options %}
                <li class="text-capitalize">{{ option.name | lower }}</li>
            {% endfor %}
        </ul>


        {# Select suboptions for cart page #}


        <div class="js-shipping-suboption-select" style="display:none;">
        {% embed "snipplets/forms/form-select.tpl" with{ select_name: suboptions.name, select_group_custom_class: 'm-0'} %}
            {% block select_options %}
               <option {% if not suboptions.selected %}selected{% endif %} disabled>{{ suboptions.default_option | translate }}</option>
                {% for option in suboptions.options %}
                    <option value="{{option.value}}">{{ option.name | lower }}</option>
                {% endfor %}
            {% endblock select_options%}
        {% endembed %}
        </div>


    {% else %}
        <input type="hidden" name="{{suboptions.name}}"/>
        <div>{{ suboptions.no_options_message | translate }}</div>
    {% endif %}
</div>

5. Ahora necesitamos llamar al calculador de envíos y los locales tanto en el carrito como en el detalle del producto.

Para el detalle del producto agregamos lo siguiente en product-form.tpl o el archivo donde tengas el formulario de producto, dentro del mismo:

{% if settings.shipping_calculator_product_page and not product.free_shipping %}

        {# Shipping calculator and branch link #}


        <div id="product-shipping-container" class="product-shipping-calculator list" {% if not product.display_price or not product.has_stock %}style="display:none;"{% endif %}>


            {# Shipping Calculator #}
            
            {% if store.has_shipping %}
                {% include "snipplets/shipping/shipping-calculator.tpl" with {'shipping_calculator_show': settings.shipping_calculator_cart_page and not product.free_shipping, 'shipping_calculator_variant' : product.selected_or_first_available_variant} %}
            {% endif %}


            {% if store.branches and store.country != 'BR' %}
                
                {# Link for branches #}
                {% include "snipplets/shipping/branches.tpl" with {'product_detail': true} %}
            {% endif %}
        </div>
{% endif %} 

Luego tenemos que agregar el calculador en el carrito, en el theme Base se encuentra en el snipplet cart-totals.tpl pero en tu diseño puede que esté en cart.tpl o cart-panel-ajax.tpl 

{% if settings.shipping_calculator_cart_page %}
  <div class="js-visible-on-cart-filled divider" {% if cart.items_count == 0 %}style="display:none;"{% endif %}></div>


  <div class="js-visible-on-cart-filled js-has-new-shipping js-shipping-calculator-container container-fluid">


    {# Saved shipping not available #}


    <div class="js-shipping-method-unavailable alert alert-warning row" style="display: none;">
      <div>
        <strong>{{ 'El medio de envío que habías elegido ya no se encuentra disponible ' | translate }}</strong>{{ 'porque el total de los items del carrito superan el peso máximo.' | translate }}
      </div>
      <div>
        {{ '¡No te preocupes! Podés elegir otro medio de envío.' | translate}}
      </div>
    </div>


    {# Shipping calculator and branch link #}


    <div id="cart-shipping-container" class="row" {% if cart.items_count == 0 %} style="display: none;"{% endif %} data-shipping-url="{{ store.shipping_calculator_url }}">


      {# Used to save shipping #}


      <span id="cart-selected-shipping-method" data-code="{{ cart.shipping_data.code }}" class="hidden">{{ cart.shipping_data.name }}</span>


      {# Shipping Calculator #}


      {% if store.has_shipping %}
        {% include "snipplets/shipping/shipping-calculator.tpl" with {'shipping_calculator_show': settings.shipping_calculator_cart_page, 'product_detail': false} %}
      {% endif %}


      {# Store branches #}


      {% if store.branches and store.country != 'BR' %}


        {# Link for branches #}


        {% include "snipplets/shipping/branches.tpl" with {'product_detail': false} %}
      {% endif %}
    </div>
  </div>


  <div class="js-visible-on-cart-filled divider {% if not store.branches or store.country == 'BR' %} mt-0{% endif %}" {% if cart.items_count == 0 %}style="display:none;"{% endif %}></div>


{% endif %}

6. Necesitamos agregar dentro del template product.tpl en el div padre de todo el detalle de producto el ID “single-product” y las clases js-has-new-shipping js-product-detail js-product-container, js-shipping-calculator-container. Quedando de la siguiente forma:

<div id="single-product" class="js-has-new-shipping js-product-detail js-product-container js-shipping-calculator-container" data-variants="{{product.variants_object | json_encode }}" itemscope itemtype="http://schema.org/Product">
HTML del detalle de producto
</div>

7. Creamos la carpeta forms dentro de la carpeta snipplets. Acá necesitamos sumar un archivo nuevo con el nombre form-input.tpl que vamos a usar para el input del calculador.

{# /*============================================================================
  #Form input
==============================================================================*/


#Properties


#Group
    //input_group_custom_class for custom CSS classes
#Label 
    // input_label_id for ID
    // input_for for label for
    // input_label_custom_class for custom CSS classes
    // input_label_text for label text
#Prepend
    // input_prepend_content to add content before input
#Container (Only if has prepend or append)
    // form_control_container_custom_class for container custom class. E.g: col
#Input 
    // Can be text_area or input
    // input_type to define type (text, tel, number or passowrd)
    // input_id for id
    // input_name for name
    // input_value for val
    // input_placeholder for placeholder
    // input_custom_class for custom CSS classes 
    // input_rows for textarea rows
    // input_data_attr for data attributes
    // input_data_val for input_data_attr value
#Append
    // input_append_content to add content after input
#Alerts 
    // input_form_alert to insert alerts


#}


<div class="form-group {{ input_group_custom_class }}">
    {% if input_label_text %}
        <label {% if input_label_id %}id="{{ input_label_id }}"{% endif %} class="form-label {{ input_label_custom_class }}" {% if input_for %}for="{{ input_name }}"{% endif %}>{{ input_label_text }}</label>
    {% endif %}
    {% block input_prepend_content %}
    {% endblock input_prepend_content %}
    {% if input_append_content or input_prepend_content %}
    <div class="form-control-container {{ form_control_container_custom_class }}">
    {% endif %}
    {% if text_area %}
        <textarea
            {% if input_id %}id="{{ input_id }}"{% endif %}
            class="form-control form-control-area {{ input_custom_class }} {% if input_append_content %}form-control-inline{% endif %}" 
            autocorrect="off" 
            autocapitalize="off" 
            {% if input_name %}name="{{ input_name }}"{% endif %}
            {% if input_value %}value="{{ input_value }}"{% endif %}
            {% if input_rows %}rows="{{ input_rows }}"{% endif %}
            {% if input_placeholder %}placeholder="{{ input_placeholder }}"{% endif %}
            {% if input_data_attr %}data-{{ input_data_attr }}="{{ input_data_val }}"{% endif %}></textarea>
    {% else %}
        <input 
            type="{% if type_text %}text{% elseif type_number %}number{% elseif type_tel %}tel{% elseif type_password %}password{% elseif type_hidden %}hidden{% endif %}"
            {% if input_id %}id="{{ input_id }}"{% endif %}
            class="form-control {{ input_custom_class }} {% if input_append_content %}form-control-inline{% endif %}" 
            autocorrect="off" 
            autocapitalize="off" 
            {% if type_password %}autocomplete="off"{% endif %}
            {% if input_name %}name="{{ input_name }}"{% endif %}
            {% if input_value %}value="{{ input_value }}"{% endif %}
            {% if input_min %}min="{{ input_min }}"{% endif %}
            {% if input_placeholder %}placeholder="{{ input_placeholder }}"{% endif %}
            {% if input_data_attr %}data-{{ input_data_attr }}="{{ input_data_val }}"{% endif %}/>
    {% endif %}
    {% if input_append_content or input_prepend_content %}
    </div>
    {% endif %}
    {% block input_append_content %}
    {% endblock input_append_content %}
    {% if input_help %}
    <div class="mt-4 text-center">
        <a href="{{ input_help_link }}" class="btn-link {{ input_link_class }}">{% block input_help_text %}{% endblock input_help_text %}</a>
    </div>
    {% endif %}
    {% block input_form_alert %}
    {% endblock input_form_alert %}
</div>

8. Por último para la parte de HTML, necesitamos agregar una carpeta SVG dentro de la carpeta snipplets. Acá vamos sumar los SVGs que usamos para los iconos en el calculador.

store.tpl

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 616 512"><path d="M602 118.6L537.1 15C531.3 5.7 521 0 510 0H106C95 0 84.7 5.7 78.9 15L14 118.6c-29.6 47.2-10 110.6 38 130.8v227.4c0 19.4 14.3 35.2 32 35.2h448c17.7 0 32-15.8 32-35.2V249.4c48-20.2 67.6-83.6 38-130.8zM516 464H100v-96h416zm-.2-144.2H100v-64.7c24-3.3 45.1-15.2 60.3-32.2 18 20.1 44.3 33.1 73.8 33.1 29.6 0 55.8-13 73.8-33.1 18 20.1 44.3 33.1 73.8 33.1 29.6 0 55.8-13 73.8-33.1 15.3 17 36.3 28.9 60.3 32.2zm47.9-133c-3.2 6.8-10.9 18.6-27 20.8-2.4.3-4.8.5-7.2.5-14.7 0-28.2-6.1-38.1-17.2L455.7 151 420 190.8c-9.9 11.1-23.5 17.2-38.1 17.2s-28.2-6.1-38.1-17.2L308 151l-35.7 39.8c-9.9 11.1-23.5 17.2-38.1 17.2-14.7 0-28.2-6.1-38.1-17.2L160.3 151l-35.7 39.8c-9.9 11.1-23.5 17.2-38.1 17.2-2.5 0-4.9-.2-7.2-.5-16-2.2-23.8-13.9-27-20.8-5-10.8-7.1-27.6 2.3-42.6L114.8 48h386.3l60.2 96.1c9.5 15.1 7.5 31.9 2.4 42.7z"/></svg>

chevron-down.tpl

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M441.9 167.3l-19.8-19.8c-4.7-4.7-12.3-4.7-17 0L224 328.2 42.9 147.5c-4.7-4.7-12.3-4.7-17 0L6.1 167.3c-4.7 4.7-4.7 12.3 0 17l209.4 209.4c4.7 4.7 12.3 4.7 17 0l209.4-209.4c4.7-4.7 4.7-12.3 0-17z"/></svg>

chevron-up.tpl

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M6.101 359.293L25.9 379.092c4.686 4.686 12.284 4.686 16.971 0L224 198.393l181.13 180.698c4.686 4.686 12.284 4.686 16.971 0l19.799-19.799c4.686-4.686 4.686-12.284 0-16.971L232.485 132.908c-4.686-4.686-12.284-4.686-16.971 0L6.101 342.322c-4.687 4.687-4.687 12.285 0 16.971z"/></svg>

info-circle.tpl

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 448c-110.532 0-200-89.431-200-200 0-110.495 89.472-200 200-200 110.491 0 200 89.471 200 200 0 110.53-89.431 200-200 200zm0-338c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"/></svg>

truck.tpl

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><path d="M624 368h-16V251.9c0-19-7.7-37.5-21.1-50.9L503 117.1C489.6 103.7 471 96 452.1 96H416V56c0-30.9-25.1-56-56-56H56C25.1 0 0 25.1 0 56v304c0 30.9 25.1 56 56 56h8c0 53 43 96 96 96s96-43 96-96h128c0 53 43 96 96 96s96-43 96-96h48c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16zm-464 96c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm208-96H242.7c-16.6-28.6-47.2-48-82.7-48s-66.1 19.4-82.7 48H56c-4.4 0-8-3.6-8-8V56c0-4.4 3.6-8 8-8h304c4.4 0 8 3.6 8 8v312zm48-224h36.1c6.3 0 12.5 2.6 17 7l73 73H416v-80zm64 320c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48zm80-100.9c-17.2-25.9-46.6-43.1-80-43.1-24.7 0-47 9.6-64 24.9V272h144v91.1z"/></svg>

sync-alt.tpl 

<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M483.515 28.485L431.35 80.65C386.475 35.767 324.485 8 256 8 123.228 8 14.824 112.338 8.31 243.493 7.971 250.311 13.475 256 20.301 256h28.045c6.353 0 11.613-4.952 11.973-11.294C66.161 141.649 151.453 60 256 60c54.163 0 103.157 21.923 138.614 57.386l-54.128 54.129c-7.56 7.56-2.206 20.485 8.485 20.485H492c6.627 0 12-5.373 12-12V36.971c0-10.691-12.926-16.045-20.485-8.486zM491.699 256h-28.045c-6.353 0-11.613 4.952-11.973 11.294C445.839 370.351 360.547 452 256 452c-54.163 0-103.157-21.923-138.614-57.386l54.128-54.129c7.56-7.56 2.206-20.485-8.485-20.485H20c-6.627 0-12 5.373-12 12v143.029c0 10.691 12.926 16.045 20.485 8.485L80.65 431.35C125.525 476.233 187.516 504 256 504c132.773 0 241.176-104.338 247.69-235.493.339-6.818-5.165-12.507-11.991-12.507z"/></svg>

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. Agregamos el siguiente SASS de colores en style-colors.scss.tpl (o la hoja de tu diseño que tenga los colores y tipografías de la tienda). Recordá que las variables de colores y tipografías pueden variar respecto a tu diseño:

{# This mixin adds browser prefixes to a CSS property #}


@mixin prefix($property, $value, $prefixes: ()) {
  @each $prefix in $prefixes {
      #{'-' + $prefix + '-' + $property}: $value;
  }
    #{$property}: $value;
}


{# /* // Buttons */ #}


.btn{
  text-decoration: none;
  text-align: center;
  border: 0;
  cursor: pointer;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  text-transform: uppercase;
  background: none;
  @include prefix(transition, all 0.4s ease, webkit ms moz o);
  &:hover,
  &:focus{
    outline: 0;
    opacity: 0.8;
  }
  &[disabled],
  &[disabled]:hover{
    opacity: 0.5;
    cursor: not-allowed;
    outline: 0;
  }
  &-default{
    padding: 10px 15px; 
    background-color: rgba($main-foreground, .2);
    color: $main-foreground;
    fill: $main-foreground;
    font-weight: bold;
  }
  &-primary{
    padding: 15px;
    background-color: $primary-color;
    color: $main-background;
    fill: $main-background;
    letter-spacing: 4px;
    @extend %body-font;
    &:hover{
      color: $main-background;
      fill: $main-background;
    }
  }
  &-secondary{
    padding: 10px 15px; 
    background-color: $main-background;
    color: $main-foreground;
    fill: $main-foreground;
    border: 1px solid $main-foreground;
  }
  &-block{
    float: left;
    width: 100%;
  }
}


{# /* // Links */ #}


.btn-link{
  color: $primary-color;
  fill: $primary-color;
  text-transform: uppercase;
  border-bottom: 1px solid;
  font-weight: bold;
  cursor: pointer;
  &:hover,
  &:focus{
    color: rgba($primary-color, .5);
    fill: rgba($primary-color, .5);
  }
}


{# /* // Forms */ #}


input,
textarea {
  font-family: $body-font;
}


.form-control {
  display: block;
  padding: 10px 8px;
  width: 100%;
  border: 0;
  border-bottom: 1px solid rgba($main-foreground, .5);
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  color: $main-foreground;
  background-color: $main-background;
  &:focus{
    outline: 0;
  }
  &-inline{
    display: inline;
  }
}


.form-control::-webkit-input-placeholder { 
  color: $main-foreground;
}
.form-control:-moz-placeholder {
  color: $main-foreground;
}
.form-control::-moz-placeholder {
  color: $main-foreground;
}
.form-control:-ms-input-placeholder {
  color: $main-foreground;
}


.radio-button {
  input[type="radio"]{
    & +  .radio-button-content .unchecked{
      border:2px solid $main-foreground;
    }
    & +  .radio-button-content .checked{
      background-color: $main-foreground;
    }
  }
}

2. Agregar los estilos dentro del archivo static/style-critical.tpl 

Si en tu diseño usas una hoja de estilos para el CSS crítico, vamos a necesitar agregar el siguiente código debajo dentro de la misma, pero si no es el caso podés unificar el CSS de los pasos 2 y 3 en un solo archivo.

{# /* // Forms */ #}


.form-group {
  position: relative;
  width: 100%;
}
.form-group .form-select-icon{
  position: absolute;
  bottom: 12px;
  right: 0;
  pointer-events: none;
}
.form-row {
  width: auto;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  margin-right: -5px;
  margin-left: -5px;
  clear: both;
}


.form-row > .col,
.form-row > [class*=col-]{
  padding-right: 5px;
  padding-left: 5px;
}


.form-label {
  display: block;
  font-size: 10px;
  text-transform: uppercase;
}

3. Agregar los estilos dentro del archivo static/style-async.tpl 

Si en tu diseño usas una hoja de estilos para CSS asíncrono, vamos a necesitar agregar el siguiente código dentro de la misma, pero si no es el caso podés unificar el CSS de los pasos 2 y 3 en un solo archivo.

{# /* // Margin and Padding */ #}


%section-margin {
  margin-bottom: 70px;
}
%element-margin {
  margin-bottom: 35px;
}
%element-margin-small {
  margin-bottom: 20px;
}


{# /* // Mixins */ #}


{# This mixin adds browser prefixes to a CSS property #}


@mixin prefix($property, $value, $prefixes: ()) {
  @each $prefix in $prefixes {
    #{'-' + $prefix + '-' + $property}: $value;
  }
  #{$property}: $value;
}


{# /* // Forms */ #}


.form-group{
  @extend %element-margin;
  .form-label{
    float: left;
    width: 100%;
    margin-bottom: 10px;
  }
  .alert{
    margin: 10px 0 0 0;
  }
}


.radio-button{
  width: 100%;
  float: left;
  clear: both;
  text-align: left;
  -webkit-tap-highlight-color: rgba(0,0,0,0);
  @extend %element-margin-small;
  cursor: pointer;
  &.disabled{
    opacity: 0.6;
    cursor: not-allowed;
    input[type="radio"] {
      cursor: not-allowed;
    }
  }
  &-icons{
    position: relative;
    float: left;
    display: table;
    width: 20px;
    margin:0 5px 0 0;
  }
  &-icon{
    border-radius: 50%;
    width: 18px;
    height: 18px;
  }
  input[type="radio"]{
    display: none;
    & +  .radio-button-content .unchecked{
      float: left;
    }
    & +  .radio-button-content .checked{
      position: absolute;
      left:9px;
      top:9px;
      width:0;
      height: 0;      
      @include prefix(transform, translate(-50%,-50%), webkit ms moz o);
      @include prefix(transition, all 0.2s , webkit ms moz o);
    }
    &:checked + .radio-button-content .checked{
      width: 6px;
      height: 6px;
    }
  }
  &-label{
    display: table;
    padding-top: 1px;
  }
  &-text{
    display: table;
    margin-bottom: 2px;
  }
}


.radio-button-item:last-of-type .radio-button{
  margin-bottom: 0;
}


.form-select {
  display: block;
  width: 100%;
  &:focus{
    outline:0;
  }
  &::-ms-expand {
    display: none;
  }
}


{# /* Disabled controls */ #}


input,
select,
textarea{
  &[disabled],
  &[disabled]:hover,
  &[readonly],
  &[readonly]:hover{
    background-color: #DDD;
    cursor: not-allowed; 
  }
}

JS

1. El JavaScript necesitamos agregarlo en el archivo store.js.tpl (o donde tengas tus funciones de JS). El código que necesitamos es el siguiente:

/* // Select and save shipping function */ 


    selectAndSaveShippingOption = function(elem){
        $(".js-shipping-method, .js-branch-method").removeClass('js-selected-shipping-method');
        $(elem).addClass('js-selected-shipping-method');
        LS.saveCalculatedShipping(true);
        var $closest_shipping_container = $(elem).closest(".js-shipping-calculator-container");
        if($(elem).hasClass("js-shipping-method-hidden")){
            $closest_shipping_container.find(".js-shipping-see-more").hide();
            $closest_shipping_container.find(".js-shipping-see-less").show();
            $closest_shipping_container.find(".js-other-shipping-options").show();
        }
    };


    /* // Calculate shipping function */ 


    $(".js-calculate-shipping").click(function (e) {
        e.preventDefault();


            {# Take the Zip code to all shipping calculators on screen #}
            let shipping_input_val = $(this).closest(".js-shipping-calculator-form").find(".js-shipping-input").val();
            if (shipping_input_val.length != 0){
                $(".js-shipping-input").val(shipping_input_val);
            }
            
        LS.calculateShippingAjax(
            $(this).closest(".js-shipping-calculator-container").find(".js-shipping-input").val(),
            '{{ store.shipping_calculator_url | escape('js') }}',
            $(this).closest(".js-shipping-calculator-container")
        );
    });


    /* // Calculate shipping by submit */ 


    $(".js-shipping-input").keydown(function (e) {
        var key = e.which ? e.which : e.keyCode;
        var enterKey = 13;
        if (key === enterKey) {
            e.preventDefault();
            $(this).closest(".js-shipping-calculator-form").find(".js-calculate-shipping").click();
            if ($(window).width() < 768) {
                $(this).blur();
            }
        }
    });


     /* // Shipping and branch click */ 


    $(document).on("change", ".js-shipping-method, .js-branch-method", function () {
        selectAndSaveShippingOption(this);
        $(".js-shipping-method-unavailable").hide();
    });


    /* // Select shipping first option on results */


    $('.js-shipping-method:checked').livequery(function () {
        let shippingPrice = $(this).attr("data-price");
        LS.addToTotal(shippingPrice);
        selectAndSaveShippingOption(this);
    });


   /* // Toggle branches link */


    $(document).on("click", ".js-toggle-branches", function (e) {
        e.preventDefault();
        $(this).next().slideToggle("fast");
        $(this).find(".js-see-branches, .js-hide-branches").toggle();
    });


    /* // Toggle more shipping options */


    $(document).on("click", ".js-show-more-shipping-options", function(e) {
        e.preventDefault();
        $(this).next().slideToggle("fast");
        $(this).find(".js-shipping-see-more, .js-shipping-see-less").toggle();
    });


    /* // Calculate shipping on page load */


    {# Only shipping input has value, cart has saved shipping and there is no branch selected #}


    if($("#cart-shipping-container .js-shipping-input").val() && !$(".js-branch-method").hasClass('js-selected-shipping-method') && $(".js-cart-total").hasClass('js-cart-saved-shipping')){
       
        // If user already had calculated shipping: recalculate shipping
       
       setTimeout(function() { 
            LS.calculateShippingAjax(
                $('#cart-shipping-container').find(".js-shipping-input").val(), 
                '{{store.shipping_calculator_url | escape('js')}}',
                $("#cart-shipping-container").closest(".js-shipping-calculator-container") );
        }, 100);
    }else if($(".js-branch-method").hasClass('js-selected-shipping-method')){
        $("#cart-shipping-container .js-toggle-branches").click();


        // Trigger function only for free pickup stores
        LS.saveCalculatedShipping(false);
    }


    /* // Shipping provinces */


    {% if provinces_json %}
        $('select[name="country"]').change(function () {
            var provinces = {{ provinces_json | default('{}') | raw }};
            LS.swapProvinces(provinces[$(this).val()]);
        }).change();
    {% endif %}

2. Luego vamos a necesitar agregar en el archivo external.js.tpl o el archivo donde tengas los plugins de tu diseño, el plugin Livequery

/*! jquery.livequery - v1.3.6 - 2013-08-26
* Copyright (c)
*  (c) 2010, Brandon Aaron (http://brandonaaron.net)
*  (c) 2012 - 2013, Alexander Zaytsev (http://hazzik.ru/en)
* Dual licensed under the MIT (MIT_LICENSE.txt)
* and GPL Version 2 (GPL_LICENSE.txt) licenses. 
*/
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?a(require("jquery")):a(jQuery)}(function(a,b){function c(a,b,c,d){return!(a.selector!=b.selector||a.context!=b.context||c&&c.$lqguid!=b.fn.$lqguid||d&&d.$lqguid!=b.fn2.$lqguid)}a.extend(a.fn,{livequery:function(b,e){var f,g=this;return a.each(d.queries,function(a,d){return c(g,d,b,e)?(f=d)&&!1:void 0}),f=f||new d(g.selector,g.context,b,e),f.stopped=!1,f.run(),g},expire:function(b,e){var f=this;return a.each(d.queries,function(a,g){c(f,g,b,e)&&!f.stopped&&d.stop(g.id)}),f}});var d=a.livequery=function(b,c,e,f){var g=this;return g.selector=b,g.context=c,g.fn=e,g.fn2=f,g.elements=a([]),g.stopped=!1,g.id=d.queries.push(g)-1,e.$lqguid=e.$lqguid||d.guid++,f&&(f.$lqguid=f.$lqguid||d.guid++),g};d.prototype={stop:function(){var b=this;b.stopped||(b.fn2&&b.elements.each(b.fn2),b.elements=a([]),b.stopped=!0)},run:function(){var b=this;if(!b.stopped){var c=b.elements,d=a(b.selector,b.context),e=d.not(c),f=c.not(d);b.elements=d,e.each(b.fn),b.fn2&&f.each(b.fn2)}}},a.extend(d,{guid:0,queries:[],queue:[],running:!1,timeout:null,registered:[],checkQueue:function(){if(d.running&&d.queue.length)for(var a=d.queue.length;a--;)d.queries[d.queue.shift()].run()},pause:function(){d.running=!1},play:function(){d.running=!0,d.run()},registerPlugin:function(){a.each(arguments,function(b,c){if(a.fn[c]&&!(a.inArray(c,d.registered)>0)){var e=a.fn[c];a.fn[c]=function(){var a=e.apply(this,arguments);return d.run(),a},d.registered.push(c)}})},run:function(c){c!==b?a.inArray(c,d.queue)<0&&d.queue.push(c):a.each(d.queries,function(b){a.inArray(b,d.queue)<0&&d.queue.push(b)}),d.timeout&&clearTimeout(d.timeout),d.timeout=setTimeout(d.checkQueue,20)},stop:function(c){c!==b?d.queries[c].stop():a.each(d.queries,d.prototype.stop)}}),d.registerPlugin("append","prepend","after","before","wrap","attr","removeAttr","addClass","removeClass","toggleClass","empty","remove","html","prop","removeProp"),a(function(){d.play()})});

Configuraciones

En el archivo config/settings.txt vamos a agregar el checkbox para poder activar o desactivar el calculador y los locales desde la sección de Personalizar tu diseño actual en el Administrador nube

Dentro de la sección de Detalle de producto agregamos lo siguiente:

    title
        title = Medios de envío
    checkbox_global
        name = shipping_calculator_product_page
        description = Mostrar calculador de costos de envío en la página de producto

Y hacemos lo mismo para la sección de Carrito de compras

    title
        title = Medios de envío
    checkbox_global
        name = shipping_calculator_cart_page
        description = Mostrar calculador de costos de envío en el carrito

Traducciones

En este paso agregamos los textos para las traducciones en el archivo config/translations.txt

--- Shipping ---


es "Formas de envío"
pt "Formas de envio"
en "Shipping methods"
es_mx "Opciones de envío"


es "FORMAS DE ENVÍO"
pt "FORMAS DE ENVIO"
en "SHIPPING METHODS"
es_mx "OPCIONES DE ENVÍO"


es "Ejemplos de formas de envío"
pt "Exemplos de formas de envio"
en "Shipping methods examples"
es_mx "Ejemplos de opciones de envío"


es "Ingrese aquí su código postal para calcular su costo de envío"
pt "Digite aqui o seu CEP para calcular o frete"
en "Enter your zipcode to calculate your shipping cost"
es_mx "Ingresa tu código postal para calcular el costo de envío"


es "Calculá el costo de tu envío"
pt "Cálculo de frete"
en "Enter your zipcode to calculate your shipping cost"
es_mx "Calcula el costo de tu envío"


es "Calcular envío"
pt "Calcular frete"
en "Calculate shipping"
es_mx "Calcular envío"


es "Código postal"
pt "CEP"
en "Zipcode"
es_mx "Código postal"


es "Calcular costo de envío"
pt "Calcular Frete"
en "Calculate shipping"
es_mx "Calcular costo de envío"


es "El código postal es inválido."
pt "O CEP está inválido."
en "The zipcode is not valid."
es_mx "El código postal es inválido."


es " (sin envío)"
pt " (sem frete)"
en " (without shipping cost)"
es_mx " (sin envío)"


es "El código postal es inválido. Por favor intentá de nuevo usando otro."
pt "CEP inválido. Por favor, digite novamente ou informe outro."
en "The zipcode is not valid. Please try again using another."
es_mx "El código postal es inválido. Intenta de nuevo ingresando otro."


es "Ocurrió un error al calcular el envío. Por favor intentá de nuevo en unos segundos."
pt "Erro no cálculo. Por favor, tente novamente em alguns segundos."
en "An error ocurred while calculating the shipping. Please try again in a few seconds."
es_mx "Hubo un error al calcular el envío. Intenta de nuevo en unos segundos."


es "El calculo falló por un problema con el medio de envío. Por favor intentá de nuevo en unos segundos."
pt "Erro no meio de envio. Por favor, tente novamente em alguns segundos."
en "The calculation failed due to a problem with the shipping method. Please try again in a few seconds."
es_mx "El cálculo falló por un problema con el forma de envío. Intenta de nuevo en unos segundos."


es "Vea las opciones de envío para su código postal abajo"
pt "Veja os valores para o seu CEP abaixo"
en "Your shipping options are the following"
es_mx "Conoce las opciones de entrega para tu código postal"


es "No hay costos de envío para el código postal dado."
pt "Não há frete disponível para o CEP informado"
en "Shipping is not available for your zipcode."
es_mx "No hay costos de envío para ese código postal."


es "Retirá gratis en nuestros locales"
pt "Retire grátis em nossas lojas físicas"
en "Free pickup on our stores"
es_mx "Recoge gratis en nuestras tiendas"


es "Retirá gratis en nuestro local"
pt "Retire grátis em nossa loja física"
en "Free pickup on our store"
es_mx "Recoge gratis en nuestra tienda"


es "Ver locales"
pt "Ver lojas físicas"
en "See our stores"
es_mx "Ver tiendas"


es "Ver local"
pt "Ver loja física"
en "See our store"
es_mx "Ver tienda"


es "Elegir local"
pt "Escolher loja física"
en "Select store"
es_mx "Elegir una tienda"


es "Conocé nuestras opciones de envío"
pt "Conheça nossas opções de frete"
en "See our shipping options"
es_mx "Conoce nuestras opciones de entrega"


es "Elegí nuestras opciones de envío"
pt "Escolha a opção de frete"
en "Choose our shipping options"
es_mx "Conoce las opciones de entrega"


es "Calculando"
pt "Calculando"
en "Calculating"
es_mx "Calculando"


es "El medio de envío que habías elegido ya no se encuentra disponible "
pt "O frete escolhido não está mais disponível "
en "The shipping method selected is no longer available "
es_mx "La forma de envío que elegiste ya no está disponible "


es "porque el total de los items del carrito superan el peso máximo."
pt "porque o total de itens no carrinho excede o peso máximo."
en "because the total of the items in the cart surpass the maximum weight."
es_mx "porque el peso total del carrito supera el peso máximo."


es "¡No te preocupes! Podés elegir otro medio de envío."
pt "Mas não se preocupe! Você pode escolher outro meio de envio."
en "Do not worry! You can select another method."
es_mx "¡No te preocupes! Puedes elegir otra forma de envío."


es "Ocultar locales"
pt "Esconder lojas físicas"
en "Hide our stores"
es_mx "Ocultar tiendas"


es "Ocultar local"
pt "Esconder loja física"
en "Hide our store"
es_mx "Ocultar tienda"


es "Seguí acá"
pt "Acompanhe aqui"
en "Track here"
es_mx "Sigue aquí"


es "tu última compra"
pt "seu último pedido"
en "your last order"
es_mx "tu última compra"


es "El precio de envío incluye este producto y todos los que agregaste al carrito."
pt "O custo de frete inclui este produto e outros adicionados ao carrinho."
en "The shipping cost includes this product and all the products added to the cart."
es_mx "El precio de envío incluye este producto y todos los que has agregado al carrito."


es "Podrás elegir alguna de las siguientes opciones antes de finalizar la compra:"
pt "Você pode escolher uma das seguintes opções antes de finalizar a compra"
en "You will be able to choose some of the following options before ending the purchase"
es_mx "Podrás elegir alguna de las siguientes opciones antes de finalizar la compra:"


es "No encontramos este código postal. ¿Está bien escrito?"
pt "Não conseguimos encontrar esse CEP. Está bem escrito?"
en "We couldn&#39;t find this zipcode. Is it written right?"
es_mx "No encontramos este código postal. ¿Está bien escrito?"


es "El tiempo de entrega no considera feriados."
pt "O prazo de entrega não contabiliza feriados."
en "The delivery time does not consider holidays."
es_mx "El tiempo de entrega no considera feriados."


es "Ingresa aquí tu código postal para calcular tu costo de envío"
pt "Digite aqui o seu CEP para calcular o frete"
en "Enter your zipcode to calculate your shipping cost"
es_mx "Ingresa aquí tu código postal para calcular tu costo de envío"


es "Costos de envío"
pt "Custos de frete"
en "Shipping costs"
es_mx "Costos de envío"


es "Calcular"
pt "Calcular"
en "Calculate"
es_mx "Calcular"


es "Envío:"
pt "Frete:"
en "Shipping:"
es_mx "Envío:"


es "Calcular para ver"
pt "Calcule para visualizar"
en "Calculate to view"
es_mx "Calcular para ver"


es "El costo del envío se calculará después."
pt "O frete será calculado depois."
en "Shipping cost will be calculated at checkout"
es_mx "El costo del envío se calculará después."


es "<strong>Tenés envío gratis</strong> en esta compra. ¡Aprovechalo!"
pt "Você ganhou <strong>frete grátis</strong> para esta compra. Aproveite!"
en "You have <strong>free shipping</strong> in this order. Go for it!"
es_mx "<strong>Tienes envío gratis</strong> en esta compra. ¡Aprovéchalo!"


es "¡Genial! <strong class='text-primary'>Tenés envío gratis</strong> en esta compra"
pt "Sucesso! Você <strong class='text-primary'>tem frete grátis</strong> para esta compra."
en "You have <strong class='text-primary'>free shipping</strong> in this order."
es_mx "¡Genial! <strong class='text-primary'>Tienes envío gratis</strong> en esta compra"


es "¡Estas a <strong class='js-cart-free-shipping-amount'></strong> de tener <strong class='text-primary m-quarter-bottom'>envío gratis</strong> en tu compra!"
pt "<strong>Ganhe frete grátis</strong> com mais <strong class='js-cart-free-shipping-amount'></strong> em compras"
en "You need <strong class='js-cart-free-shipping-amount'></strong> to have <strong class='text-primary m-quarter-bottom'>free shipping</strong> on your order"
es_mx "¡Estas a <strong class='js-cart-free-shipping-amount'></strong> de tener <strong class='text-primary m-quarter-bottom'>envío gratis</strong> en tu compra!"


es "Ver más productos"
pt "Escolher mais produtos"
en "See more products"
es_mx "Ver más productos"


es "¡Todos los productos de esta categoría <strong>tienen envío gratis!</strong>"
pt "Todos os produtos desta categoria <strong>tienen envío gratis!</strong>"
en "All the products in this category <strong>have free shipping!</strong>"
es_mx "¡Todos los productos de esta categoría <strong>tienen envío gratis!</strong>"


es "<strong class='text-primary'>Envío gratis</strong> superando los"
pt "<strong class='text-primary'>Frete grátis</strong> para compras acima de"
en "<strong class='text-primary'>Free shipping</strong> buying more than"
es_mx "<strong class='text-primary'>Envío gratis</strong> superando los"


es "<strong class='text-primary'>¡Envío gratis!</strong> con todos los medios de envío"
pt "<strong class='text-primary'>Frete grátis!</strong> com todos os meios de envio"
en "<strong class='text-primary'>Free shipping!</strong> with all shipping options"
es_mx "<strong class='text-primary'>¡Envío gratis!</strong> con todos los medios de envío"




--- --- Shipping and Payments


es "Medios de envío"
pt "Opções de frete"
en "Shipping Methods"
es_mx "Opciones de envío"


es "Mostrar calculador de costos de envío en la página de producto"
pt "Mostrar o Cálculo de Frete na página de produto"
en "Show shipping cost calculator on product page"
es_mx "Mostrar el calculador de costos de envío en la página de producto"


es "Mostrar calculador de costos de envío en el carrito"
pt "Mostrar o Cálculo de Frete no carrinho"
en "Show shipping cost calculator to cart"
es_mx "Mostrar el calculador de costos de envío en el carrito"


es "Mostrar medios de envío en tu tienda"
pt "Mostrar as opções de frete na sua loja"
en "Show Shipping Methods in your store"
es_mx "Mostrar las opciones de envío en tu sitio"


es "Mostrar medios de pago en tu tienda"
pt "Mostrar as opções de pagamento na sua loja"
en "Show payment methods in your store"
es_mx "Mostrar los métodos de pago en tu sitio"

Activación

Por último podés activar el calculador tanto para el detalle del producto como para el carrito desde el Administrador nube, en la sección de Personalizar tu diseño actual dentro de las partes Detalles de producto y Carrito de compras:


Listo, ya tenés en tu diseño la funcionalidad aplicada ¡Excelente!