Event API Example: Automatically Add an Ice Pack to Each Shipment in the Multiple shipping Address Process

Please note: This is an advanced tutorial, and should be completed by a qualified web developer familiar with HTML and Liquid. If you are not working with a developer, and would like us to handle this for you, we can do so for a flat fee of $100 USD. Payment can be made by navigating to the following url: https://shop.gist-apps.com

If you ship products that require an ice pack, and need this to be automatically charged to the customer for each shipment, the following code can be used as a guideline in order to implement this in the multi-address process. It leverages our Javascript Event API, and requires some hard coded parameters, such as the variant ID of the ice pack product, and the product_types that need to have an Ice Pack added.

This tutorial can also be modified to suite other automatic surcharge needs.

For completeness, the provided code will also handle this for single address checkouts if added to your theme.

Create a file in your theme’s assets directly called “warm-weather-ship.js”, and copy the below code in to it, ensuring to modify the MODULE.config parameters to suite your needs.

window.WARMWEATHERMODULE = (function() {
  
  var MODULE = {
	    
    config: {
      requestsBuilt: false,
      productTypesThatNeedIce: ["warm-weather-ship"], // Define applicable product types.
      icePackVariantId: 123456, // CHANGE ME. Define upsell variant ID.
      icePackPrice: 1000, // Define upsell price.
      icePackTitle: "Warm weather handling + $10.00", // Define upsell product title.
      icePackDesc: "<u>Warm weather handling</u> is required for select products and is automatically added at checkout, when applicable during the warm weather season." // Define upsell description.
    },
    
    state: {
      path: null,
      requests: [],
      shipments: null
    },
    
    init: function() {

      this.state.path = this.registerPath();

      if (this.state.path === "multi") {
        this.multi.init();
        return;
      }

      if (this.state.path === "single") {
        this.single.init();
        return;
      }      

    },

    multi: {

      init: function() {

        this.registerEventHandlers();
      
      },
      
      registerEventHandlers: function() {

        // Step 1: Save shipments. These will always be ready first.
        document.addEventListener('giftship.shipping.ready', function() {
          MODULE.state.shipments = window.GSSDK.shipments.get();
          //console.log("MODULE.state.shipments", MODULE.state.shipments);
          MODULE.multi.buildRequests();
        });
        
        document.addEventListener('giftship.shipping.rates-complete', function() {

          MODULE.addNotice();
          MODULE.flushProductRequests();
          
        });
            
      },

      buildRequests: function() {
        
        try {
          
          MODULE.state.shipments.forEach(function(shipment) {
            MODULE.buildRequest(shipment.variants);
          });
            
        } catch (error) {
            
          console.error('Error handling shipping groups:', error);
            
        }
        
        MODULE.state.requestsBuilt = true;
        
      },
      
    },

    single: {

      init: function() {

        MODULE.getCart()
        .then(function(cartData) {
          
          MODULE.buildRequest(cartData.items);
          MODULE.flushProductRequests();
        })
        .catch(function(err) {
          console.warn('An error occurred getting the cart', err)
        })
        ;
        
      }
            
    },

    onlyUnique: function(value, index, array) {
      return array.indexOf(value) === index;
    },
  

    buildRequest: function(items) {

      var needsIcePack = MODULE.needsIcePack(items);
      var firstVariant = items[0];
      var properties   = firstVariant.properties || {};

      console.log('needsIcePack', needsIcePack);

      if (!needsIcePack) {
        return;
      }


      // Add to bundle or create if it exists already.
      
      // properties._gs_bundle_ids = properties._gs_bundle_ids || [];
      // properties._gs_bundle_quanties = properties._gs_bundle_quanties || [];
      // properties._gs_bundle_prices = properties._gs_bundle_prices || [];
      // properties._gs_bundle_contents = properties._gs_bundle_contents || [];
      
      // properties._gs_bundle_ids.push(MODULE.config.icePackVariantId + "");
      // properties._gs_bundle_quanties.push("1");
      // properties._gs_bundle_prices.push(MODULE.config.icePackPrice + "");
      // properties._gs_bundle_contents.push(MODULE.config.icePackTitle);

      // properties._gs_bundle_ids = properties._gs_bundle_ids.filter(MODULE.onlyUnique);
      // properties._gs_bundle_quanties = properties._gs_bundle_quanties.filter(MODULE.onlyUnique);
      // properties._gs_bundle_prices = properties._gs_bundle_prices.filter(MODULE.onlyUnique);
      // properties._gs_bundle_contents = properties._gs_bundle_contents.filter(MODULE.onlyUnique);
      
      // https://shopify.dev/docs/api/ajax/reference/cart#post-locale-cart-change-js
      var props = properties._gs_a ? {
        Address: properties.Address,
        _gs_a: properties._gs_a
      } : {};
      
      MODULE.state.requests.push({
        id: MODULE.config.icePackVariantId,
        properties: props,
        quantity: 1
      });

      console.log("properties", properties);

    },

    registerPath: function () {
      
      let path = window.location.pathname;

      if (path.includes('a/gs/cart/confirm')) {
        return "multi";
      }

      if (path.includes('cart')) {
        return "single";
      }
    
      return null;
    },

    needsIcePack: function(items) {

      MODULE.state.hasIcePack = false;
      
      for (var key in items) {
        if (Object.hasOwnProperty.call(items, key)) {
          var item = items[key];
          var props = item.properties || {};
          
          var hasPack = item.variant_id === MODULE.config.icePackVariantId;
          
          if (hasPack) {
            MODULE.state.hasIcePack = true;
          }
          
        }
      }

      if (MODULE.state.hasIcePack) {
        return false;
      }
      
      for (var key in items) {
          
        if (Object.hasOwnProperty.call(items, key)) {
            
          var item = items[key];
          var props = item.properties || {};
          
          if (MODULE.config.productTypesThatNeedIce.includes(item.product_type)) {
            return true;
          }
        }
      }

      return false;
      
    },

    getCart: function() {

      return fetch('/cart.js')
      .then(function(data) {
        return data.json();
      })
      .then(function(response) {
        return response;
      }) 
      .catch(function(error) {
        return err;
      });
      
    },

    changeCart: function(formData) {

      return fetch(window.Shopify.routes.root + 'cart/change.js', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(formData)
      })
      .then(function(response){
        return response.json();
      })
      .then(function(res) {
        console.log("res", res);
        return res;
      })
      .catch(function(error) {
        console.error('Error:', error);
        return error;
      });
      
    },

    addProducts: function(formData) {

      return fetch(window.Shopify.routes.root + 'cart/add.js', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(formData)
      })
      .then(function(response){
        return response.json();
      })
      .then(function(res) {
        console.log("res", res);
        return res;
      })
      .catch(function(error) {
        console.error('Error:', error);
        return error;
      });
      
    },

    addNotice: function() {

      var multiCheckoutBtn = document.querySelector('#gsMultiCheckout');
      var existingNotice = document.querySelector('#icePackNotice');
      var notice = document.createElement('div');
      
      if (existingNotice || !multiCheckoutBtn || !MODULE.state.requests.length && MODULE.state.hasIcePack === false) {
        return;
      }

      notice.innerHTML = MODULE.config.icePackDesc;
      notice.id = 'icePackNotice';

      multiCheckoutBtn.parentNode.insertBefore(notice, multiCheckoutBtn);

    },
 
    flushProductRequests: function(attempts) {

      //console.log("FLUSHING PRODUCT REQUESTS", attempts, MODULE.state.requests);
      
      if (MODULE.state.requestsBuilt === false && attempts < 10) {
        
        setTimeout(function() {
          attempts = attempts + 1;
          console.log("Ice pack requests not ready");
          MODULE.flushProductRequests(attempts);
        }, 1000);
        return;
        
      }
      
      if (!MODULE.state.requests.length) {
        console.warn("No warm weather packages needed");
        return;
      }
      
      try {
        var functions = MODULE.state.requests.map(function(request) {
            return MODULE.addProducts(request);
          });

        //console.log("functions", functions);
        setTimeout(function() {

          // Allow time for the cart cookie to reset
          Promise.all(functions)
          .then(function(promises) {
            console.log(promises);
          })
          .catch(function(err) {
            console.log(err);
          })
          ;
          
        }, 1000);
        
 
      } catch (error) {
        console.error('Error handling upsell:', error);
          
      }
    }

  };

  // Initialize the MODULE
  
  MODULE.init();

  return MODULE;
  
})();

In Giftship’s multi-address settings, add the below code. Click save.

} catch(e) {
  
}
})();
</script>
{{ 'warm-weather-charge.js' | asset_url | script_tag }}
<script>
(function() {
try {

Can't find the answer in our documentation?
Contact Support