Created
May 15, 2016 17:52
-
-
Save stariqmi/9726563242a47b361d8c149c42ddd3a0 to your computer and use it in GitHub Desktop.
Shopify Coding Challenge
This file contains 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
/* | |
Author: Salman Tariq Mirza | |
node/JavaScript solution to the Shopify Internship Coding Challenge | |
Assumptions: | |
- No duplicates, a flat list of the variants of all the products maintains uniqueness. | |
- For each computer there should be a keyboard. | |
- However if all computers/keyboards are purchased and there is still money left, | |
then spares need to be purchased of the remaining type. | |
Difficulties: | |
- Tried to use the product_type filter for Computer/Keyboard. Did not work, | |
returned products that were not Computers and Keyboards | |
Notes: | |
- hackathon.hardware.basic represents the pair of Computer/Keyboard pairs that need to be purchased | |
- Once shopicruit runs out of either computers or keyboards, we need to purchase spares of the remaining | |
type within the budget. This is represented by hackathon.hardware.spares | |
*/ | |
// npm modules | |
var request = require('sync-request'); | |
var _ = require('lodash'); | |
// Initial state | |
var hackathon = { | |
shopicruit: { | |
url: 'http://shopicruit.myshopify.com/products.json', | |
keyboards: [], | |
computers: [] | |
}, | |
weights: { | |
regular: 0, | |
spare: 0 | |
}, | |
hardware: { // Purchase list | |
basic: [], // Pairs of computers/keyboards | |
spares: { // Spare parts | |
keyboards: [], | |
computers: [], | |
category: '' | |
}, | |
}, | |
budget: 1000.00 | |
}; | |
/** | |
* Function to purchase a pair of computer and keyboard. Stack like behavior. | |
* @param object hackathon reference object that stores the state of the hackathon | |
* @return boolean indicates wether Alice was able to purchase a pair or not | |
*/ | |
function purchaseHardware(hackathon) { | |
var store = hackathon.shopicruit; | |
var hardware = hackathon.hardware; | |
var weights = hackathon.weights; | |
// Check that both have something left | |
if (store.computers.length > 0 && store.keyboards.length > 0) { | |
var c = store.computers.shift(); | |
var k = store.keyboards.shift(); | |
// Check if we still have money left | |
hackathon.budget -= (parseFloat(c.price) + parseFloat(k.price)); | |
// If we don't, we stop buying | |
if (hackathon.budget < 0) return false; | |
hardware.basic.push({computer: c, keyboard: k}); | |
weights.regular += (c.grams + k.grams); | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Function to purchase spare parts | |
* @param object hackathon reference object that stores the state of the hackathon | |
*/ | |
function purchaseSpares(hackathon) { | |
var spareCategory = (hackathon.shopicruit.keyboards.length === 0) ? 'computers' : 'keyboards'; | |
hackathon.hardware.spares.category = spareCategory; | |
while(hackathon.budget > 0) { | |
var c = hackathon.shopicruit[spareCategory].shift(); | |
hackathon.budget -= parseFloat(c.price); | |
if (hackathon.budget < 0) hackathon.budget = 0; | |
else { | |
hackathon.hardware.spares[spareCategory].push(c); | |
hackathon.weights.spare += c.grams; | |
} | |
} | |
} | |
/** | |
* Function to fetch products of type from shopicruit | |
* @param object hackathon reference object that stores the state of the hackathon | |
* @param integer page page number to search | |
*/ | |
function getProducts(hackathon, page) { | |
var hasProducts = true; | |
var store = hackathon.shopicruit; | |
var reqUrl = hackathon.shopicruit.url + '?page=' + page + '&limit=' + 250; | |
var res = request('GET', reqUrl); | |
// Shopify is not happy! | |
if (res.statusCode !== 200) throw(new Error('Request failed with status code ' + res.statusCode + '.\nResponse: ' + res.getBody())); | |
var products = JSON.parse(res.getBody()).products; | |
// No more products | |
if (products.length === 0) hasProducts = false; | |
_.each(products, function(product) { | |
var variants = _.filter(product.variants, function(v) { | |
return v.available; | |
}); | |
switch (product.product_type) { | |
case 'Computer': | |
store.computers.push.apply(store.computers, variants); | |
break; | |
case 'Keyboard': | |
store.keyboards.push.apply(store.keyboards, variants); | |
break; | |
default: | |
// Alice needs to learn that hackers need more than just Computers and Keyboards | |
} | |
}); | |
return hasProducts; | |
} | |
try { | |
// hackathon.hardware identifies the entire purchase list | |
// Get all products from the store | |
var page = 1; | |
while (getProducts(hackathon, page)){ | |
page++; | |
} | |
var store = hackathon.shopicruit; | |
// Sort them by price - ascending | |
store.keyboards = _.sortBy(store.keyboards, function(keyboard) { | |
return parseFloat(keyboard.price); | |
}); | |
store.computers = _.sortBy(store.computers, function(computer) { | |
return parseFloat(computer.price); | |
}); | |
// Make purchase list | |
while(purchaseHardware(hackathon)) { | |
// We just wait till Alice adds to her list | |
} | |
purchaseSpares(hackathon); | |
// console.log(hackathon); | |
console.log('Total Computer/Keyboard pairs: ' + hackathon.hardware.basic.length); | |
console.log('Their weight: ' + hackathon.weights.regular + ' g'); | |
console.log('Spare ' + hackathon.hardware.spares.category + ': ' + hackathon.hardware.spares[hackathon.hardware.spares.category].length); | |
console.log('Their weight: ' + hackathon.weights.spare + ' g'); | |
console.log('Total weight: ' + (hackathon.weights.regular + hackathon.weights.spare) + ' g'); | |
} | |
catch(err) { | |
console.log(err); | |
console.log('Oops, something wen\'t wrong. Please contact Shopify support'); | |
} |
This file contains 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
{ | |
"name": "shopify_challenge", | |
"version": "1.0.0", | |
"description": "Solution for Shopify challenge", | |
"main": "index.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"keywords": [ | |
"shopify", | |
"challenge" | |
], | |
"author": "Salman Tariq Mirza", | |
"license": "MIT", | |
"dependencies": { | |
"lodash": "^4.12.0", | |
"sync-request": "^3.0.1" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment