Created
February 21, 2015 23:29
-
-
Save ptdecker/a1241d777904038a4f5d to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/fuzomo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>JS Bin</title> | |
</head> | |
<body> | |
<script id="jsbin-javascript"> | |
// Configuration values that are global to the store. These would need | |
// some sort of a Magento dialog to allow the business team to maintain | |
// them. Values are stored in cents to avoid JavaScript floating point | |
// issues | |
// | |
// standardShippingRate | |
// The amount of shipping that should be charged on a per item | |
// basis unless the individual SKU has a special shipping charge | |
// freeShippingThreshold | |
// The amount of the sub-total of the cart of the items that do | |
// not have special shipping charges that, once exceeded, will | |
// result in a zero charge for shipping of the items that do not | |
// have the special shipping charges | |
var globalSettings = { | |
standardShippingRate: 500, | |
freeShippingThreshold: 12000 | |
}; | |
// Sample product catalog. Of course, in a real implementation, these | |
// items would come from the product catalog database. And, the logic | |
// around the price I'm sure has additional considerations. But, the | |
// important new piece here is 'specialShippingCharge'. The product | |
// inventory maintenance pages in the back-end would need to have a place | |
// where the business team can set this 'specialShippingCharge' for | |
// each item. | |
// | |
// sku | |
// Unique identifier for the product catalog item | |
// price | |
// The integer price in cents (to avoid floating point problems in | |
// JavaScipt) for one unit of the item | |
// specialShippingCharge | |
// If this amount is defined (or is not zero in strong typed | |
// languages), then this amount defines the amount of shipping that | |
// is always charged for this item. | |
var productCatalog = { | |
items: [ | |
{ | |
sku: "12345", | |
price: 1000 | |
},{ | |
sku: "67890", | |
price: 1500 | |
},{ | |
sku: "23456", | |
price: 10500, | |
specialShippingCharge: 7500 | |
},{ | |
sku: "78901", | |
price: 12500 | |
},{ | |
sku: "34567", | |
price: 750, | |
specialShippingCharge: 500 | |
} | |
] | |
}; | |
// Various sample chopping carts | |
// Empty cart | |
var sampleCartA = { | |
description: "Empty cart", | |
items: [] | |
}; | |
// Cart containing no special shipping items | |
var sampleCartB = { | |
description: "Cart containing no special shipping items", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 3 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing no special shipping items but where the subtotal of | |
// the items exceeds the free shipping threshold. | |
var sampleCartC = { | |
description: "Cart containing no special shipping items but where the subtotal of the items exceeds the free shipping threshold", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 30 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing special shipping items | |
var sampleCartD = { | |
description: "Cart containing special shipping items", | |
items: [ | |
{ | |
sku:"23456", | |
quantity: 1 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing a mix of regular and special shipping items | |
var sampleCartE = { | |
description: "Cart containing a mix of regular and special shipping items", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 3 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing a mix of regular and special shipping items where the | |
// subtotal of the regular items exceeds the free shipping theshold. | |
var sampleCartF = { | |
description: "Cart containing a mix of regular and special shipping items where the subtotal of the regular items exceeds the free shipping theshold", | |
items: [ | |
{ | |
sku:"12345", | |
quantity:30 | |
},{ | |
sku:"67890", | |
quantity:2 | |
},{ | |
sku:"23456", | |
quantity: 2 | |
} | |
] | |
}; | |
// Helper function to left pad a string with a character to a width | |
// Credit for this goes to: http://stackoverflow.com/a/9744576/959570 | |
function paddy(n, p, c) { | |
var pad_char = typeof c !== 'undefined' ? c : '0'; | |
var pad = new Array(1 + p).join(pad_char); | |
return (pad + n).slice(-pad.length); | |
} | |
// Helper function to add commas using U.S. format pattern (9,999,999) | |
// Credit for this goes to: http://stackoverflow.com/a/2901298/3893444 | |
function addCommas(value) { | |
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); | |
} | |
// A type-safe helper function to nicely format a string to a width. | |
// Strings that are wider than the width are displayed as a width-wide | |
// string of 'x'. If passed a non-string value, the value is returned | |
// unaltered. | |
function formatString(value, width) { | |
if (typeof value !== 'string') { | |
return value; | |
} | |
if (value.length > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return paddy(value, width, ' '); | |
} | |
} | |
// Helper function to nicely format currency based upon an integer | |
// currency value where the least significant two digits represent cents | |
// using U.S. format pattern ($ 9,999.99). Values that overflow the width | |
// are displayed as a width-wide string of 'x'. | |
function formatCurrency(value, width) { | |
var dollars = Math.floor(value / 100); | |
var cents = value % 100; | |
var formatted = addCommas(dollars) + "." + paddy(cents, 2, "0"); | |
if (formatted.length + 1 > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return '$' + paddy(formatted, width - 1, ' '); | |
} | |
} | |
// Helper function to nicely format integers. Values that overflow the | |
// width are displayed as a width-wide string of 'x'. | |
function formatInteger(value, width) { | |
if (value.length > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return paddy(value, width, ' '); | |
} | |
} | |
// Helper function to look up a SKU from the product catalog | |
// Notes: This is a really stupid O(n) approach, but for this demo it | |
// works fine | |
function getSKU(sku, catalog) { | |
var result = {}, | |
skuTemp, | |
index, | |
size; | |
for (index = 0, size = catalog.items.length; index < size; index += 1) { | |
skuTemp = catalog.items[index].sku; | |
if (skuTemp !== undefined && skuTemp === sku) { | |
return catalog.items[index]; | |
} | |
} | |
return undefined; | |
} | |
// Add unit prices to the items in the cart | |
function addUnitPrices(cart, catalog) { | |
var newItems = cart.items.map(function(item){ | |
var newItem = item, | |
itemDetail = getSKU(item.sku, catalog), | |
unitPrice; | |
if (itemDetail === undefined || itemDetail.price === undefined) { | |
newItem.unitPrice = 0; | |
} else { | |
newItem.unitPrice = itemDetail.price; | |
} | |
return newItem; | |
}); | |
return newItems; | |
} | |
// Calculate extended prices | |
function extendPrices(cart) { | |
var newItems = cart.items.map(function(item){ | |
var newItem = item; | |
item.extendedPrice = item.unitPrice * item.quantity; | |
return newItem; | |
}); | |
return newItems; | |
} | |
// Calculate cart sub-total | |
function calcSubtotal(cart) { | |
cart.subtotal = 0; | |
cart.items.forEach(function(item) { | |
cart.subtotal += item.extendedPrice; | |
}); | |
} | |
// Add shipping costs to the cart | |
function addShipping(cart, globals, catalog) { | |
var regularShippingTotal = 0, // Accumulated regular shipping expenses | |
specialShippingTotal = 0; // Accumulated special shipping expense | |
// Spin through the items in the shopping cart evaluating the shipping | |
// charge situation for each. | |
cart.items.forEach(function(item) { | |
// Look up the special shipping amount for the current cart item | |
var specialShipping = getSKU(item.sku, catalog).specialShippingCharge; | |
// If there is 'special shipping' amount for the item then add the | |
// accumualted special shipping charges. Otherwise, add the global | |
// regular shipping fee to the accumulated regular shipping charges. | |
// Of course, both the above taking into account quanity. | |
if (specialShipping !== undefined && specialShipping !== 0) { | |
specialShippingTotal += specialShipping * item.quantity; | |
} else { | |
regularShippingTotal += globals.standardShippingRate * item.quantity; | |
} | |
}); | |
// Now that all items have been evaluated, if accumulated regular | |
// shipping is over the global free shipping threshold then give | |
// the customer free shipping. | |
if (cart.subtotal > globals.freeShippingThreshold) { | |
regularShippingTotal = 0; | |
} | |
// Final shipping amount equals regular plus special shipping | |
cart.shipping = regularShippingTotal + specialShippingTotal; | |
} | |
// Calculate the cart total | |
function calcTotal(cart) { | |
cart.total = cart.subtotal + cart.shipping; | |
} | |
// Calculate the cart | |
function calculateCart(cart, global, catalog) { | |
addUnitPrices(cart, catalog); | |
extendPrices(cart); | |
calcSubtotal(cart); | |
addShipping(cart, global, catalog); | |
calcTotal(cart); | |
} | |
// Display the contents of a cart on the console | |
function showCartOnConsole(cart) { | |
console.log(cart.description); | |
if (cart.items.length === 0) { | |
console.log("The cart is empty"); | |
} else { | |
cart.items.forEach(function(item) { | |
console.log( | |
formatString(item.sku, 6) + " " + | |
formatCurrency(item.unitPrice, 10) + " " + | |
formatInteger(item.quantity, 6) + " " + | |
formatCurrency(item.extendedPrice, 10) | |
); | |
}); | |
console.log( | |
formatString("Subtotal", 10) + " " + | |
formatCurrency(cart.subtotal, 10) | |
); | |
console.log( | |
formatString("Shipping", 10) + " " + | |
formatCurrency(cart.shipping, 10) | |
); | |
console.log( | |
formatString("Total", 10) + " " + | |
formatCurrency(cart.total, 10) | |
); | |
} | |
console.log(""); | |
} | |
// Calculate test carts and show the results. | |
calculateCart(sampleCartA, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartA); | |
calculateCart(sampleCartB, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartB); | |
calculateCart(sampleCartC, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartC); | |
calculateCart(sampleCartD, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartD); | |
calculateCart(sampleCartE, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartE); | |
calculateCart(sampleCartF, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartF); | |
</script> | |
<script id="jsbin-source-javascript" type="text/javascript">// Configuration values that are global to the store. These would need | |
// some sort of a Magento dialog to allow the business team to maintain | |
// them. Values are stored in cents to avoid JavaScript floating point | |
// issues | |
// | |
// standardShippingRate | |
// The amount of shipping that should be charged on a per item | |
// basis unless the individual SKU has a special shipping charge | |
// freeShippingThreshold | |
// The amount of the sub-total of the cart of the items that do | |
// not have special shipping charges that, once exceeded, will | |
// result in a zero charge for shipping of the items that do not | |
// have the special shipping charges | |
var globalSettings = { | |
standardShippingRate: 500, | |
freeShippingThreshold: 12000 | |
}; | |
// Sample product catalog. Of course, in a real implementation, these | |
// items would come from the product catalog database. And, the logic | |
// around the price I'm sure has additional considerations. But, the | |
// important new piece here is 'specialShippingCharge'. The product | |
// inventory maintenance pages in the back-end would need to have a place | |
// where the business team can set this 'specialShippingCharge' for | |
// each item. | |
// | |
// sku | |
// Unique identifier for the product catalog item | |
// price | |
// The integer price in cents (to avoid floating point problems in | |
// JavaScipt) for one unit of the item | |
// specialShippingCharge | |
// If this amount is defined (or is not zero in strong typed | |
// languages), then this amount defines the amount of shipping that | |
// is always charged for this item. | |
var productCatalog = { | |
items: [ | |
{ | |
sku: "12345", | |
price: 1000 | |
},{ | |
sku: "67890", | |
price: 1500 | |
},{ | |
sku: "23456", | |
price: 10500, | |
specialShippingCharge: 7500 | |
},{ | |
sku: "78901", | |
price: 12500 | |
},{ | |
sku: "34567", | |
price: 750, | |
specialShippingCharge: 500 | |
} | |
] | |
}; | |
// Various sample chopping carts | |
// Empty cart | |
var sampleCartA = { | |
description: "Empty cart", | |
items: [] | |
}; | |
// Cart containing no special shipping items | |
var sampleCartB = { | |
description: "Cart containing no special shipping items", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 3 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing no special shipping items but where the subtotal of | |
// the items exceeds the free shipping threshold. | |
var sampleCartC = { | |
description: "Cart containing no special shipping items but where the subtotal of the items exceeds the free shipping threshold", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 30 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing special shipping items | |
var sampleCartD = { | |
description: "Cart containing special shipping items", | |
items: [ | |
{ | |
sku:"23456", | |
quantity: 1 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing a mix of regular and special shipping items | |
var sampleCartE = { | |
description: "Cart containing a mix of regular and special shipping items", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 3 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing a mix of regular and special shipping items where the | |
// subtotal of the regular items exceeds the free shipping theshold. | |
var sampleCartF = { | |
description: "Cart containing a mix of regular and special shipping items where the subtotal of the regular items exceeds the free shipping theshold", | |
items: [ | |
{ | |
sku:"12345", | |
quantity:30 | |
},{ | |
sku:"67890", | |
quantity:2 | |
},{ | |
sku:"23456", | |
quantity: 2 | |
} | |
] | |
}; | |
// Helper function to left pad a string with a character to a width | |
// Credit for this goes to: http://stackoverflow.com/a/9744576/959570 | |
function paddy(n, p, c) { | |
var pad_char = typeof c !== 'undefined' ? c : '0'; | |
var pad = new Array(1 + p).join(pad_char); | |
return (pad + n).slice(-pad.length); | |
} | |
// Helper function to add commas using U.S. format pattern (9,999,999) | |
// Credit for this goes to: http://stackoverflow.com/a/2901298/3893444 | |
function addCommas(value) { | |
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); | |
} | |
// A type-safe helper function to nicely format a string to a width. | |
// Strings that are wider than the width are displayed as a width-wide | |
// string of 'x'. If passed a non-string value, the value is returned | |
// unaltered. | |
function formatString(value, width) { | |
if (typeof value !== 'string') { | |
return value; | |
} | |
if (value.length > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return paddy(value, width, ' '); | |
} | |
} | |
// Helper function to nicely format currency based upon an integer | |
// currency value where the least significant two digits represent cents | |
// using U.S. format pattern ($ 9,999.99). Values that overflow the width | |
// are displayed as a width-wide string of 'x'. | |
function formatCurrency(value, width) { | |
var dollars = Math.floor(value / 100); | |
var cents = value % 100; | |
var formatted = addCommas(dollars) + "." + paddy(cents, 2, "0"); | |
if (formatted.length + 1 > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return '$' + paddy(formatted, width - 1, ' '); | |
} | |
} | |
// Helper function to nicely format integers. Values that overflow the | |
// width are displayed as a width-wide string of 'x'. | |
function formatInteger(value, width) { | |
if (value.length > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return paddy(value, width, ' '); | |
} | |
} | |
// Helper function to look up a SKU from the product catalog | |
// Notes: This is a really stupid O(n) approach, but for this demo it | |
// works fine | |
function getSKU(sku, catalog) { | |
var result = {}, | |
skuTemp, | |
index, | |
size; | |
for (index = 0, size = catalog.items.length; index < size; index += 1) { | |
skuTemp = catalog.items[index].sku; | |
if (skuTemp !== undefined && skuTemp === sku) { | |
return catalog.items[index]; | |
} | |
} | |
return undefined; | |
} | |
// Add unit prices to the items in the cart | |
function addUnitPrices(cart, catalog) { | |
var newItems = cart.items.map(function(item){ | |
var newItem = item, | |
itemDetail = getSKU(item.sku, catalog), | |
unitPrice; | |
if (itemDetail === undefined || itemDetail.price === undefined) { | |
newItem.unitPrice = 0; | |
} else { | |
newItem.unitPrice = itemDetail.price; | |
} | |
return newItem; | |
}); | |
return newItems; | |
} | |
// Calculate extended prices | |
function extendPrices(cart) { | |
var newItems = cart.items.map(function(item){ | |
var newItem = item; | |
item.extendedPrice = item.unitPrice * item.quantity; | |
return newItem; | |
}); | |
return newItems; | |
} | |
// Calculate cart sub-total | |
function calcSubtotal(cart) { | |
cart.subtotal = 0; | |
cart.items.forEach(function(item) { | |
cart.subtotal += item.extendedPrice; | |
}); | |
} | |
// Add shipping costs to the cart | |
function addShipping(cart, globals, catalog) { | |
var regularShippingTotal = 0, // Accumulated regular shipping expenses | |
specialShippingTotal = 0; // Accumulated special shipping expense | |
// Spin through the items in the shopping cart evaluating the shipping | |
// charge situation for each. | |
cart.items.forEach(function(item) { | |
// Look up the special shipping amount for the current cart item | |
var specialShipping = getSKU(item.sku, catalog).specialShippingCharge; | |
// If there is 'special shipping' amount for the item then add the | |
// accumualted special shipping charges. Otherwise, add the global | |
// regular shipping fee to the accumulated regular shipping charges. | |
// Of course, both the above taking into account quanity. | |
if (specialShipping !== undefined && specialShipping !== 0) { | |
specialShippingTotal += specialShipping * item.quantity; | |
} else { | |
regularShippingTotal += globals.standardShippingRate * item.quantity; | |
} | |
}); | |
// Now that all items have been evaluated, if accumulated regular | |
// shipping is over the global free shipping threshold then give | |
// the customer free shipping. | |
if (cart.subtotal > globals.freeShippingThreshold) { | |
regularShippingTotal = 0; | |
} | |
// Final shipping amount equals regular plus special shipping | |
cart.shipping = regularShippingTotal + specialShippingTotal; | |
} | |
// Calculate the cart total | |
function calcTotal(cart) { | |
cart.total = cart.subtotal + cart.shipping; | |
} | |
// Calculate the cart | |
function calculateCart(cart, global, catalog) { | |
addUnitPrices(cart, catalog); | |
extendPrices(cart); | |
calcSubtotal(cart); | |
addShipping(cart, global, catalog); | |
calcTotal(cart); | |
} | |
// Display the contents of a cart on the console | |
function showCartOnConsole(cart) { | |
console.log(cart.description); | |
if (cart.items.length === 0) { | |
console.log("The cart is empty"); | |
} else { | |
cart.items.forEach(function(item) { | |
console.log( | |
formatString(item.sku, 6) + " " + | |
formatCurrency(item.unitPrice, 10) + " " + | |
formatInteger(item.quantity, 6) + " " + | |
formatCurrency(item.extendedPrice, 10) | |
); | |
}); | |
console.log( | |
formatString("Subtotal", 10) + " " + | |
formatCurrency(cart.subtotal, 10) | |
); | |
console.log( | |
formatString("Shipping", 10) + " " + | |
formatCurrency(cart.shipping, 10) | |
); | |
console.log( | |
formatString("Total", 10) + " " + | |
formatCurrency(cart.total, 10) | |
); | |
} | |
console.log(""); | |
} | |
// Calculate test carts and show the results. | |
calculateCart(sampleCartA, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartA); | |
calculateCart(sampleCartB, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartB); | |
calculateCart(sampleCartC, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartC); | |
calculateCart(sampleCartD, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartD); | |
calculateCart(sampleCartE, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartE); | |
calculateCart(sampleCartF, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartF);</script></body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Configuration values that are global to the store. These would need | |
// some sort of a Magento dialog to allow the business team to maintain | |
// them. Values are stored in cents to avoid JavaScript floating point | |
// issues | |
// | |
// standardShippingRate | |
// The amount of shipping that should be charged on a per item | |
// basis unless the individual SKU has a special shipping charge | |
// freeShippingThreshold | |
// The amount of the sub-total of the cart of the items that do | |
// not have special shipping charges that, once exceeded, will | |
// result in a zero charge for shipping of the items that do not | |
// have the special shipping charges | |
var globalSettings = { | |
standardShippingRate: 500, | |
freeShippingThreshold: 12000 | |
}; | |
// Sample product catalog. Of course, in a real implementation, these | |
// items would come from the product catalog database. And, the logic | |
// around the price I'm sure has additional considerations. But, the | |
// important new piece here is 'specialShippingCharge'. The product | |
// inventory maintenance pages in the back-end would need to have a place | |
// where the business team can set this 'specialShippingCharge' for | |
// each item. | |
// | |
// sku | |
// Unique identifier for the product catalog item | |
// price | |
// The integer price in cents (to avoid floating point problems in | |
// JavaScipt) for one unit of the item | |
// specialShippingCharge | |
// If this amount is defined (or is not zero in strong typed | |
// languages), then this amount defines the amount of shipping that | |
// is always charged for this item. | |
var productCatalog = { | |
items: [ | |
{ | |
sku: "12345", | |
price: 1000 | |
},{ | |
sku: "67890", | |
price: 1500 | |
},{ | |
sku: "23456", | |
price: 10500, | |
specialShippingCharge: 7500 | |
},{ | |
sku: "78901", | |
price: 12500 | |
},{ | |
sku: "34567", | |
price: 750, | |
specialShippingCharge: 500 | |
} | |
] | |
}; | |
// Various sample chopping carts | |
// Empty cart | |
var sampleCartA = { | |
description: "Empty cart", | |
items: [] | |
}; | |
// Cart containing no special shipping items | |
var sampleCartB = { | |
description: "Cart containing no special shipping items", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 3 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing no special shipping items but where the subtotal of | |
// the items exceeds the free shipping threshold. | |
var sampleCartC = { | |
description: "Cart containing no special shipping items but where the subtotal of the items exceeds the free shipping threshold", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 30 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing special shipping items | |
var sampleCartD = { | |
description: "Cart containing special shipping items", | |
items: [ | |
{ | |
sku:"23456", | |
quantity: 1 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing a mix of regular and special shipping items | |
var sampleCartE = { | |
description: "Cart containing a mix of regular and special shipping items", | |
items: [ | |
{ | |
sku:"12345", | |
quantity: 3 | |
},{ | |
sku:"67890", | |
quantity: 2 | |
},{ | |
sku:"34567", | |
quantity: 2 | |
} | |
] | |
}; | |
// Cart containing a mix of regular and special shipping items where the | |
// subtotal of the regular items exceeds the free shipping theshold. | |
var sampleCartF = { | |
description: "Cart containing a mix of regular and special shipping items where the subtotal of the regular items exceeds the free shipping theshold", | |
items: [ | |
{ | |
sku:"12345", | |
quantity:30 | |
},{ | |
sku:"67890", | |
quantity:2 | |
},{ | |
sku:"23456", | |
quantity: 2 | |
} | |
] | |
}; | |
// Helper function to left pad a string with a character to a width | |
// Credit for this goes to: http://stackoverflow.com/a/9744576/959570 | |
function paddy(n, p, c) { | |
var pad_char = typeof c !== 'undefined' ? c : '0'; | |
var pad = new Array(1 + p).join(pad_char); | |
return (pad + n).slice(-pad.length); | |
} | |
// Helper function to add commas using U.S. format pattern (9,999,999) | |
// Credit for this goes to: http://stackoverflow.com/a/2901298/3893444 | |
function addCommas(value) { | |
return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); | |
} | |
// A type-safe helper function to nicely format a string to a width. | |
// Strings that are wider than the width are displayed as a width-wide | |
// string of 'x'. If passed a non-string value, the value is returned | |
// unaltered. | |
function formatString(value, width) { | |
if (typeof value !== 'string') { | |
return value; | |
} | |
if (value.length > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return paddy(value, width, ' '); | |
} | |
} | |
// Helper function to nicely format currency based upon an integer | |
// currency value where the least significant two digits represent cents | |
// using U.S. format pattern ($ 9,999.99). Values that overflow the width | |
// are displayed as a width-wide string of 'x'. | |
function formatCurrency(value, width) { | |
var dollars = Math.floor(value / 100); | |
var cents = value % 100; | |
var formatted = addCommas(dollars) + "." + paddy(cents, 2, "0"); | |
if (formatted.length + 1 > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return '$' + paddy(formatted, width - 1, ' '); | |
} | |
} | |
// Helper function to nicely format integers. Values that overflow the | |
// width are displayed as a width-wide string of 'x'. | |
function formatInteger(value, width) { | |
if (value.length > width) { | |
return paddy('', width, 'x'); | |
} else { | |
return paddy(value, width, ' '); | |
} | |
} | |
// Helper function to look up a SKU from the product catalog | |
// Notes: This is a really stupid O(n) approach, but for this demo it | |
// works fine | |
function getSKU(sku, catalog) { | |
var result = {}, | |
skuTemp, | |
index, | |
size; | |
for (index = 0, size = catalog.items.length; index < size; index += 1) { | |
skuTemp = catalog.items[index].sku; | |
if (skuTemp !== undefined && skuTemp === sku) { | |
return catalog.items[index]; | |
} | |
} | |
return undefined; | |
} | |
// Add unit prices to the items in the cart | |
function addUnitPrices(cart, catalog) { | |
var newItems = cart.items.map(function(item){ | |
var newItem = item, | |
itemDetail = getSKU(item.sku, catalog), | |
unitPrice; | |
if (itemDetail === undefined || itemDetail.price === undefined) { | |
newItem.unitPrice = 0; | |
} else { | |
newItem.unitPrice = itemDetail.price; | |
} | |
return newItem; | |
}); | |
return newItems; | |
} | |
// Calculate extended prices | |
function extendPrices(cart) { | |
var newItems = cart.items.map(function(item){ | |
var newItem = item; | |
item.extendedPrice = item.unitPrice * item.quantity; | |
return newItem; | |
}); | |
return newItems; | |
} | |
// Calculate cart sub-total | |
function calcSubtotal(cart) { | |
cart.subtotal = 0; | |
cart.items.forEach(function(item) { | |
cart.subtotal += item.extendedPrice; | |
}); | |
} | |
// Add shipping costs to the cart | |
function addShipping(cart, globals, catalog) { | |
var regularShippingTotal = 0, // Accumulated regular shipping expenses | |
specialShippingTotal = 0; // Accumulated special shipping expense | |
// Spin through the items in the shopping cart evaluating the shipping | |
// charge situation for each. | |
cart.items.forEach(function(item) { | |
// Look up the special shipping amount for the current cart item | |
var specialShipping = getSKU(item.sku, catalog).specialShippingCharge; | |
// If there is 'special shipping' amount for the item then add the | |
// accumualted special shipping charges. Otherwise, add the global | |
// regular shipping fee to the accumulated regular shipping charges. | |
// Of course, both the above taking into account quanity. | |
if (specialShipping !== undefined && specialShipping !== 0) { | |
specialShippingTotal += specialShipping * item.quantity; | |
} else { | |
regularShippingTotal += globals.standardShippingRate * item.quantity; | |
} | |
}); | |
// Now that all items have been evaluated, if accumulated regular | |
// shipping is over the global free shipping threshold then give | |
// the customer free shipping. | |
if (cart.subtotal > globals.freeShippingThreshold) { | |
regularShippingTotal = 0; | |
} | |
// Final shipping amount equals regular plus special shipping | |
cart.shipping = regularShippingTotal + specialShippingTotal; | |
} | |
// Calculate the cart total | |
function calcTotal(cart) { | |
cart.total = cart.subtotal + cart.shipping; | |
} | |
// Calculate the cart | |
function calculateCart(cart, global, catalog) { | |
addUnitPrices(cart, catalog); | |
extendPrices(cart); | |
calcSubtotal(cart); | |
addShipping(cart, global, catalog); | |
calcTotal(cart); | |
} | |
// Display the contents of a cart on the console | |
function showCartOnConsole(cart) { | |
console.log(cart.description); | |
if (cart.items.length === 0) { | |
console.log("The cart is empty"); | |
} else { | |
cart.items.forEach(function(item) { | |
console.log( | |
formatString(item.sku, 6) + " " + | |
formatCurrency(item.unitPrice, 10) + " " + | |
formatInteger(item.quantity, 6) + " " + | |
formatCurrency(item.extendedPrice, 10) | |
); | |
}); | |
console.log( | |
formatString("Subtotal", 10) + " " + | |
formatCurrency(cart.subtotal, 10) | |
); | |
console.log( | |
formatString("Shipping", 10) + " " + | |
formatCurrency(cart.shipping, 10) | |
); | |
console.log( | |
formatString("Total", 10) + " " + | |
formatCurrency(cart.total, 10) | |
); | |
} | |
console.log(""); | |
} | |
// Calculate test carts and show the results. | |
calculateCart(sampleCartA, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartA); | |
calculateCart(sampleCartB, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartB); | |
calculateCart(sampleCartC, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartC); | |
calculateCart(sampleCartD, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartD); | |
calculateCart(sampleCartE, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartE); | |
calculateCart(sampleCartF, globalSettings, productCatalog); | |
showCartOnConsole(sampleCartF); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment