Created
August 11, 2020 10:05
-
-
Save joshhunt/19a1dd58bfe15e7b8e9d605ab63e42cb to your computer and use it in GitHub Desktop.
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
const round = (num) => Math.round((num + Number.EPSILON) * 100) / 100; | |
const DAYS_IN_A_YEAR = 365; | |
const VAT_MULTIPLIER = 1.05; | |
function priceCommand(plans, _annualUsage) { | |
const annualUsage = parseInt(_annualUsage); | |
const results = plans | |
.map((plan) => { | |
const standingCharge = plan.standing_charge || 0; | |
let cost = DAYS_IN_A_YEAR * standingCharge; | |
let remainingKwh = annualUsage; | |
for (const rate of plan.rates) { | |
if (!rate.threshold || rate.threshold > remainingKwh) { | |
cost += rate.price * remainingKwh; | |
break; | |
} | |
cost += rate.threshold * rate.price; | |
remainingKwh -= rate.threshold; | |
} | |
cost = cost * VAT_MULTIPLIER; | |
return { plan, cost }; | |
}) | |
.sort((a, b) => a.cost - b.cost) | |
.map((result) => | |
[result.plan.supplier, result.plan.plan, round(result.cost / 100)].join( | |
"," | |
) | |
); | |
return results; | |
} | |
function usageCommand(plans, supplier, planName, _cost) { | |
const cost = parseInt(_cost); | |
const plan = plans.find( | |
(v) => v.supplier === supplier && v.plan === planName | |
); | |
if (!plan) { | |
throw new Error("Could not find plan"); | |
} | |
const annualSpend = (cost * 12 * 100) / VAT_MULTIPLIER; // in pence, remove VAT | |
const standingCharge = plan.standing_charge || 0; | |
const standingChargeSpend = standingCharge * DAYS_IN_A_YEAR; | |
const energyUsageSpend = annualSpend - standingChargeSpend; | |
let energyUsage = 0; | |
let remainingSpend = energyUsageSpend; | |
for (const rate of plan.rates) { | |
const energyConsumed = remainingSpend / rate.price; | |
if (rate.threshold && energyConsumed > rate.threshold) { | |
energyUsage += rate.threshold; | |
remainingSpend -= rate.price * rate.threshold; | |
} else { | |
energyUsage += energyConsumed; | |
break; | |
} | |
} | |
return [Math.round(energyUsage).toString()]; | |
} | |
function exitCommand() { | |
process.exit(0); | |
} | |
function unknownCommand() { | |
return ["unknown command"]; | |
} | |
module.exports = { | |
priceCommand, | |
usageCommand, | |
exitCommand, | |
unknownCommand, | |
}; |
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
const test = require("ava"); | |
const { priceCommand, usageCommand } = require("./commands"); | |
const plans = require("./plans.json"); | |
test("price 1000", (t) => { | |
const result = priceCommand(plans, "1000"); | |
t.deepEqual(result, [ | |
"eon,variable,108.68", | |
"edf,fixed,111.25", | |
"ovo,standard,120.23", | |
"bg,standing-charge,121.33", | |
]); | |
}); | |
test("price 2000", (t) => { | |
const result = priceCommand(plans, "2000"); | |
t.deepEqual(result, [ | |
"edf,fixed,205.75", | |
"eon,variable,213.68", | |
"bg,standing-charge,215.83", | |
"ovo,standard,235.73", | |
]); | |
}); | |
test("usage edf fixed 350", (t) => { | |
const result = usageCommand(plans, "edf", "fixed", "350"); | |
t.deepEqual(result, ["44267"]); | |
}); | |
test("usage ovo standard 1000", (t) => { | |
const result = usageCommand(plans, "ovo", "standard", "1000"); | |
t.deepEqual(result, ["103855"]); | |
}); | |
test("usage bg standing-charge 120", (t) => { | |
const result = usageCommand(plans, "bg", "standing-charge", "120"); | |
t.deepEqual(result, ["14954"]); | |
}); |
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
const readline = require("readline"); | |
const path = require("path"); | |
const { | |
priceCommand, | |
usageCommand, | |
exitCommand, | |
unknownCommand, | |
} = require("./commands"); | |
const COMMANDS = { | |
price: priceCommand, | |
usage: usageCommand, | |
exit: exitCommand, | |
unknown: unknownCommand, | |
}; | |
const plansPath = process.argv[2]; | |
const plans = require(path.resolve(plansPath)); | |
var rl = readline.createInterface({ | |
input: process.stdin, | |
output: process.stdout, | |
terminal: false, | |
}); | |
rl.on("line", function (line) { | |
const [command, ...args] = line.split(" "); | |
const commandFn = COMMANDS[command] || COMMANDS.unknown; | |
const results = commandFn(plans, ...args) || []; | |
results.forEach((line) => console.log(line)); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment