Documentation You are here: start » v » 2.0 » shipping » custom_code

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
v:2.0:shipping:custom_code [2019/12/03 23:40] – [Free shipping based on a coupon] adamv:2.0:shipping:custom_code [2024/01/29 14:42] (current) – [Getting shipping rates from Third Party Providers] adam
Line 1: Line 1:
 ====== Custom Shipping Code ====== ====== Custom Shipping Code ======
  
-The Custom Shipping Code option supports adding javascript code to your store's shipping section that is able to add new rates, or modifiy or remove existing rates that have been returned from other configured shipping rates for your store.+The Custom Shipping Code option supports adding javascript code to your store's shipping section that is able to add new rates, or modify or remove existing rates that have been returned from other configured shipping rates for your store.
  
 The Custom Shipping Code is processed after any other carriers that have been configured have run, including the Custom Shipping Endpoint. This means that those rates can also be modified as part of your custom code. The Custom Shipping Code is processed after any other carriers that have been configured have run, including the Custom Shipping Endpoint. This means that those rates can also be modified as part of your custom code.
Line 7: Line 7:
 <wrap tip>**This custom code runs serverside,** not client-side.</wrap> Yes, it's javascript, but this javascript doesn't output to the browser. Instead, it's run serverside in Node.js (in a separate environment per store), so you can put private logic (such as coupon codes) in the code. <wrap tip>**This custom code runs serverside,** not client-side.</wrap> Yes, it's javascript, but this javascript doesn't output to the browser. Instead, it's run serverside in Node.js (in a separate environment per store), so you can put private logic (such as coupon codes) in the code.
  
 +===== Example Payload =====
 +The custom shipping code receives the same payload as the custom shipping endpoint. See a [[./payload|sample payload]].
 +
 +===== Category Settings =====
 +You'll need to set each [[https://admin.foxycart.com/admin.php?ThisAction=ManageProductCategories|Category]] where you want the Custom Shipping Code to apply to //Shipped using live shipping rates//. You can do this after applying the custom shipping code to your shipping settings if you're not using live shipping rates already.
 ===== Enabling Custom Shipping Code ===== ===== Enabling Custom Shipping Code =====
 +
 +==== Enable custom code ====
  
 To enable Custom Shipping Code for your store, login to your store's Foxy administration and head to the "shipping" section. You'll find the option to "use custom code" as the last option on the page. To enable Custom Shipping Code for your store, login to your store's Foxy administration and head to the "shipping" section. You'll find the option to "use custom code" as the last option on the page.
 +
 +Enabling the "use custom code" option will reveal a code editor where you can enter your custom JavaScript shipping code.
  
 <WRAP center round info  60%> <WRAP center round info  60%>
Line 15: Line 24:
 </WRAP> </WRAP>
  
-Enabling the "use custom code" option will reveal a code editor where you can enter your custom JavaScript shipping code. Within this code editor, you'll also have access to a couple of objects:+==== Write your custom shipping code ====
  
-  * ''rates'': The rates object for the cart, which will be prepopulated with any rates returned from other options enabled for the store+We have a [[v:2.0:shipping:custom_code:api|Shipping API]] that helps you interact with the rates, adding custom rates, or filtering, modifying or removing existing rates (either from our native live rate carriers, or custom rates you add). You can review the example code further down this page for examples of using the Shipping API to modify rates. 
 + 
 +Within the shipping code editor, you will also have access to a couple of objects: 
 + 
 +  * ''rates'': The rates object for the cart, which will be prepopulated with any rates returned from other options enabled for the store. This object also provides access to the [[v:2.0:shipping:custom_code:api|Shipping API]].
   * ''cart'': An object containing all of the information about the customers cart. For an overview of what this object looks like, [[v:2.0:shipping:payload|see this page]].   * ''cart'': An object containing all of the information about the customers cart. For an overview of what this object looks like, [[v:2.0:shipping:payload|see this page]].
  
-Within the code editor, you can enter and javascript logic you require for calculating your custom shipping ratesAs you enter your shipping code, the code editor will provide in-context feedback for any issues it may detect. Hover over any icons or highlighted code for additional details.+The code is processed within a Node.js v14 instanceUTC timezone, with access to the following Node modules:
  
-We also have helper functions available for your custom code for working with custom ratesYou can review the documentation on the [[v:2.0:shipping:custom_code:api|Shipping API functions you can use in your logic here]]We also have some examples further down this page.+  * [[https://github.com/node-fetch/node-fetch|node-fetch]] (available as ''fetch''
 +  * [[https://sdk.foxy.dev/|Foxy SDK]] (available as ''FoxySDK''
 +  * [[https://github.com/goshippo/shippo-node-client|Shippo]] (available as ''shippo''
 +  * [[https://www.npmjs.com/package/xml2js|xml2js]] (available as ''xml2js''
 + 
 +Within the code editor, you can enter any javascript logic you require for calculating your custom shipping ratesAs you enter your shipping code, the code editor will provide in-context feedback for any issues it may detectHover over any icons or highlighted code for additional details (note that there is a known issue with the code validations relating to lines of code containing ''await'' - you can ignore errors for this)
  
 <WRAP center round tip 90%> <WRAP center round tip 90%>
 We recommend enabling the "enable shipping rate signing" option on the shipping page settings as well. If you have any javascript snippets in your store's configuration outside of the custom code entered on the shipping page that affects the returned shipping rates, or the weight used to calculate the shipping rate, you will want to leave this unchecked however.  We recommend enabling the "enable shipping rate signing" option on the shipping page settings as well. If you have any javascript snippets in your store's configuration outside of the custom code entered on the shipping page that affects the returned shipping rates, or the weight used to calculate the shipping rate, you will want to leave this unchecked however. 
 </WRAP> </WRAP>
 +
 +==== Deploy your shipping code ====
  
 Once you have your shipping code entered as desired, click the green "Update" button at the bottom of the page. You will see a message that the shipping code is being deployed, and to refresh the page to get an updated status. Wait for 15-20 seconds and refresh the page - if you see your shipping code displayed again, then your code was successfully deployed! Once you have your shipping code entered as desired, click the green "Update" button at the bottom of the page. You will see a message that the shipping code is being deployed, and to refresh the page to get an updated status. Wait for 15-20 seconds and refresh the page - if you see your shipping code displayed again, then your code was successfully deployed!
Line 41: Line 61:
 The following are a selection of examples of shipping code to give you an idea of how it can be utilised for your store. For details on the functions available within the custom code, you can [[v:2.0:shipping:custom_code:api|review the Shipping API here]]. The following are a selection of examples of shipping code to give you an idea of how it can be utilised for your store. For details on the functions available within the custom code, you can [[v:2.0:shipping:custom_code:api|review the Shipping API here]].
  
 +<note important>Note that HTML is not currently supported in the rate //carrier// or //service// parameters. We do have plans to support it in the future.</note>
 ==== Adding a fallback shipping rate ==== ==== Adding a fallback shipping rate ====
  
Line 60: Line 81:
 if (cart['_embedded']['fx:shipment']['total_item_price'] >= 40) { if (cart['_embedded']['fx:shipment']['total_item_price'] >= 40) {
  rates.filter(10001).price(0).service('Free Shipping');  rates.filter(10001).price(0).service('Free Shipping');
 +}
 +</code>
 +
 +
 +==== Flat rates based on order total ====
 +
 +Different flat rates based on the product subtotal, with a "pick up" option if a threshold isn't met.
 +
 +<code javascript>
 +const total_item_price = cart['_embedded']['fx:shipment']['total_item_price'];
 +
 +rates.add(10001, 75, 'FoxyPost', 'Standard');
 +if (total_item_price <= 200) {
 +  // Orders $200 and under can only be picked up.
 +  rates.filter(10001).price(0).service('Customer Pickup');
 +} else if (total_item_price <= 500) {
 +  // Orders from $200.01 to $500 ship for $75
 +  rates.filter(10001).price(75);
 +} else if (total_item_price <= 1000) {
 +  rates.filter(10001).price(150);
 +} else {
 +  // Orders over $1000, from the last if statement
 +  rates.filter(10001).price(300);
 } }
 </code> </code>
Line 71: Line 115:
 </code> </code>
  
 +==== Adding extra text to shipping rate labels ===
 +
 +If you want to modify a returned shipping rate label to have a different service, you can do that using the API like this:
 +
 +<code javascript>
 +rates.filter('FedEx Home Delivery').service('Ground');
 +</code>
 +
 +That would change the rate ''FedEx Home Delivery'' to instead be ''FedEx Ground''.
 +
 +You can also append to the existing service text though, so it will still use whatever the shipping provider returns. For example, the following would use FedEx Home Delivery again, but would append " (Signature Required)" to the end of it:
 +
 +<code javascript>
 +let home_delivery = rates.filter('FedEx Home Delivery');
 +if (home_delivery.exists()) {
 +    home_delivery.service(home_delivery.service() + ' (Signature Required)');
 +}
 +</code>
 +
 +If you wanted to make a similar adjustment to a lot of different rates, for example adding " (Signature Required)" to all FedEx rates, you can do that like this:
 +
 +<code javascript>
 +rates.filter('fedex').each(function() {
 +    this.service(this.service() + ' (Signature Required)');
 +});
 +</code>
 ==== Providing flat rates based on the shipping country ==== ==== Providing flat rates based on the shipping country ====
  
Line 92: Line 162:
 </code> </code>
  
 +==== Returning a flat rate for international orders ====
 +
 +This example is a simple approach for only showing a flat rate option for international orders.
 +
 +<code javascript>
 +const country = cart['_embedded']['fx:shipment']['country'];
 +
 +if (country != "US") {
 +  // The customer is shipping outside the US
 +  rates.hide();
 +  rates.add(10001, 25, 'FoxyPost', 'Standard');
 +}
 +</code>
 +==== Restricting shipping to only a specific set of postcodes ====
 +
 +This example can be used to prevent customers from being able to complete the checkout if they don't have a shipping address within a specific set of postcodes. The ''allowed_postcodes'' array can be updated to include as many postcodes as needed. If a customer has a shipping address that doesn't have a matching postcode, they will instead see an error.
 +
 +<code javascript>
 +const allowed_postcodes = [55115, 55116];
 +const postal_code = Number(cart['_embedded']['fx:shipment']['postal_code']);
 +
 +if (allowed_postcodes.includes(postal_code)) {
 +    rates.add(10001, 10, '', 'Standard Shipping');
 +} else {
 +    rates.error('Sorry, we are not currently able to ship to your location');
 +}
 +</code>
 +
 +===Example using non-numerical postcodes===
 +
 +Since some countries may use postcodes that include alphabetic characters, the example needs to be a little different in that case. Here is an example for postcodes in UK.
 +
 +<code javascript>
 +const allowed_postcodes = ['SE100AA', 'SE100AB'];
 +const postal_code = (cart['_embedded']['fx:shipment']['postal_code']).replace(/\s+/g, '').toUpperCase();
 +
 +if (allowed_postcodes.includes(postal_code)) {
 +    rates.add(10001, 10, '', 'Standard Shipping');
 +} else {
 +    rates.error('Sorry, we are not currently able to ship to your location');
 +}
 +</code>
  
 ==== Hiding specific shipping rates depending on the shipping state ==== ==== Hiding specific shipping rates depending on the shipping state ====
Line 132: Line 244:
  
 This example would allow free shipping if a coupon with a code of ''freeshipping'' was present, or one that had a suffix of ''-fs'', like ''mycode-fs'' or ''h3Sif4yg-fs'' This example would allow free shipping if a coupon with a code of ''freeshipping'' was present, or one that had a suffix of ''-fs'', like ''mycode-fs'' or ''h3Sif4yg-fs''
 +
 +If you don't want to give a discount for the products and only free shipping, your coupon can be set to all the default settings with a ''coupon details'' string of ''0-0''.
  
 <code javascript> <code javascript>
Line 143: Line 257:
     rates.add(11000, 0, '', 'Free Shipping');     rates.add(11000, 0, '', 'Free Shipping');
   }   }
 +}
 +</code>
 +
 +
 +==== Free shipping over a certain amount ====
 +This example provides free shipping if the subtotal for the order (total item price less any coupons) is greater than $50.
 +
 +<code javascript>
 +const total_item_price = cart['_embedded']['fx:shipment']['total_item_price'];
 +
 +let discounts = 0;
 +for (let d in cart['_embedded']['fx:discounts']) {
 +    discounts += cart['_embedded']['fx:discounts'][d]['amount'];
 +}
 +
 +rates.add(10001, 8, '', 'Standard Shipping');
 +
 +if (total_item_price + discounts > 50) {
 +    rates.hide();
 +    rates.add(10002, 0, '', 'Free Shipping');
 +}
 +</code>
 +
 +
 +==== Modifying Rates by Customer Attributes ====
 +If you use ''attributes'' on your customers, such as a ''Loyalty_Level'' or ''Wholesaler_Status'', you can key off that to trigger custom rates. The below code is just a partial bit to show how to access customer attributes, which you could combine with other examples on this page.
 +
 +<code javascript>
 +let loyaltyLevel = false;
 +
 +if (
 +  cart._embedded["fx:customer"] &&
 +  cart._embedded["fx:customer"].id &&
 +  cart._embedded["fx:customer"].id != 0 &&
 +  cart._embedded["fx:customer"]._embedded &&
 +  cart._embedded["fx:customer"]._embedded["fx:attributes"]
 +) {
 +  for (
 +    let i = 0;
 +    i < cart._embedded["fx:customer"]._embedded["fx:attributes"].length;
 +    i++
 +  ) {
 +    const attr = cart._embedded["fx:customer"]._embedded["fx:attributes"][i];
 +    if (attr.name === "Loyalty_Level") {
 +      loyaltyLevel = attr.value;
 +    }
 +  }
 +}
 +
 +if (loyaltyLevel && loyaltyLevel.match(/silver/i)) {
 +  rates.hide().add(10003, 0, "", "Free Shipping for Silver Level");
 } }
 </code> </code>
Line 166: Line 331:
   // If 3 or more food items, update priority overnight to be free   // If 3 or more food items, update priority overnight to be free
   if (food >= 3) rates.filter('priority overnight').price(0);   if (food >= 3) rates.filter('priority overnight').price(0);
 +}
 +</code>
 +
 +
 +==== Restricting available rates based on custom fields ====
 +This example is similar to the above, but checks the value of a custom field from the session/checkout instead of the category. Review the [[..:shipping#passing_custom_fields_to_the_custom_shipping_endpoint|"Passing custom fields to the custom shipping endpoint" section on the shipping page]] for details on how to pass custom values from the cart/checkout to your shipping code.
 +
 +<code javascript>
 +let my_field = '';
 +for (let c in cart['_embedded']['fx:custom_fields']) {
 +    let custom_field = cart['_embedded']['fx:custom_fields'][c];
 +    if (custom_field.name == 'my_field') {
 +        my_field = custom_field.value.toLowerCase();
 +    }
 +}
 +
 +rates.add(10001, 8.99, '', 'Standard Shipping');
 +rates.add(10002, 15.50, '', 'Express Shipping');
 +
 +if (my_field == 'my_value') {
 +    rates.hide();
 +    rates.filter(10002).price("+3.25").show();
 } }
 </code> </code>
Line 182: Line 369:
  
 If there are shipping rates already present (from the native live carrier integrations or the custom shipping endpoint), then the product level shipping fees are added onto the existing rates, otherwise it creates a new rate with a label of "Standard Shipping". If there are shipping rates already present (from the native live carrier integrations or the custom shipping endpoint), then the product level shipping fees are added onto the existing rates, otherwise it creates a new rate with a label of "Standard Shipping".
 +
 +If you want to hide the custom product option on the cart, you can do that from the "configuration" page of the Foxy administration, look for the option labelled "Customize Cart Display" and add the product option name you used (''shipping'' in this example).
  
 <code javascript> <code javascript>
Line 212: Line 401:
 </code> </code>
  
 +==== Increase rates by an amount ====
 +
 +This example filters rates on UPS and adds 4 units of the appropriate currency to all UPS prices.
 +
 +<code javascript>
 +rates.filter('UPS').price('+4');
 +</code>
 +
 +==== Getting shipping rates from Third Party Providers ====
 +
 +If you're needing to get rates from other providers that Foxy doesn't currently support, then using a third-party service like [[https://goshippo.com/|GoShippo]] or [[https://www.easypost.com|EasyPost]] can be a great option. We support fetching their rates through the custom shipping code feature, and you can see details on setting that up on the following pages:
 +
 +  * [[v:2.0:shipping:custom_code:goshippo|Fetching shipping rates from GoShippo]]
 +  * [[v:2.0:shipping:custom_code:easypost|Fetching shipping rates from EasyPost]]
 +  * [[v:2.0:shipping:custom_code:xps|Fetching shipping rates from XPS]]
 +  * [[v:2.0:shipping:custom_code:postmen|Fetching shipping rates from Postmen]]
 +==== Calculate flat rate shipping based on distance ====
 +
 +For stores that want to calculate a flat rate shipping cost based on the distance, rather than using a live rate provider like USPS, FedEx or UPS, this approach can use the Google Maps API to calculate the distance between the store address and the customers.
 +
 +[[v:2.0:shipping:custom_code:google_maps_distance|Calculating flat rate shipping by distance]]
 +
 +==== Restricting shipping to a specific map area ====
 +
 +If you have a specific geographical area that you allow shipping to, you can use Google Maps with the custom shipping code to only show certain options if the customers shipping address is within that area.
 +
 +[[v:2.0:snippets:restrict_shipping_to_specific_map_area|Restrict shipping to a specific map area]]

Site Tools