Created
May 18, 2020 20:21
-
-
Save dduugg/765f0d3006cd46bdb853afc613c6396d to your computer and use it in GitHub Desktop.
Programming challenge: Supermarket billing
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
-module(billing). | |
% use print_bill/1 for the defualt items/1 list, or supply your | |
% own using print_bill/2 and the remove_item/1 and | |
% upate_item/1 APIs | |
-export([items/0, print_bill/1, print_bill/2, | |
remove_item/2, test/0, update_item/2]). | |
items() -> | |
[{4719, "Fish Fingers", 121}, {5643, "Nappies", 1010}, | |
{3814, "Orange Jelly", 56}, {1111, "Hula Hoops", 21}, | |
{1112, "Hula Hoops (Giant)", 133}, | |
{1234, "Dry Sherry, 1lt", 540}]. | |
% helper function used to calculate bulk discounts | |
item_count([], _) -> 0; | |
item_count([Barcode | Barcodes], Item) -> | |
case Barcode of | |
Item -> 1 + item_count(Barcodes, Item); | |
_ -> item_count(Barcodes, Item) | |
end. | |
test_item_count() -> | |
2 = item_count([1234, 4719, 1234], 1234). | |
% removes an item from a list of items, if present | |
remove_item([], _) -> []; | |
remove_item([{Barcode, _, _} | Items], Barcode) -> | |
Items; | |
remove_item([Item | Items], Barcode) -> | |
[Item] ++ remove_item(Items, Barcode). | |
test_remove_item() -> | |
[{4719, "Fish Fingers", 121}] = remove_item([{4719, | |
"Fish Fingers", 121}, | |
{5643, "Nappies", 1010}], | |
5643), | |
[{4719, "Fish Fingers", 121}, {5643, "Nappies", 1010}] = | |
remove_item([{4719, "Fish Fingers", 121}, | |
{5643, "Nappies", 1010}], | |
1), | |
ok. | |
% adds or updates an item matching Barcode in a list of items | |
update_item(Items, {Barcode, Name, Cost}) -> | |
remove_item(Items, Barcode) ++ [{Barcode, Name, Cost}]. | |
test_update_item() -> | |
[{5643, "Nappies", 1010}, | |
{4719, "Deluxe Fish Fingers", 250}] = | |
update_item([{4719, "Fish Fingers", 121}, | |
{5643, "Nappies", 1010}], | |
{4719, "Deluxe Fish Fingers", 250}), | |
ok. | |
% prints a bill to the console, given a list of barcodes | |
print_bill(Barcodes) -> print_bill(Barcodes, items()). | |
print_bill(Barcodes, Inventory) -> | |
Discount = -100 * item_count(Barcodes, 1234) div 2, | |
io:format("~s", | |
[string:join(print_bill(Barcodes, [], 0, 30, Discount, | |
Inventory), | |
"\n") | |
++ "\n"]). | |
print_bill([], Lines, Total, Width, Discount, _) -> | |
DiscountLines = case Discount of | |
0 -> []; | |
_ -> ["", format_line_item("Discount", Discount, Width)] | |
end, | |
[" Erlang Stores", ""] ++ | |
Lines ++ | |
DiscountLines ++ | |
["", | |
format_line_item("Total", Total + Discount, Width)]; | |
print_bill([Barcode | Barcodes], Lines, Total, Width, | |
Discount, Inventory) -> | |
{Name, Cost} = lookup_barcode(Barcode, Inventory), | |
case lookup_barcode(Barcode, Inventory) of | |
{Name, Cost} -> | |
Line = format_line_item(Name, Cost, Width), | |
print_bill(Barcodes, Lines ++ [Line], Total + Cost, | |
Width, Discount, Inventory); | |
_ -> | |
print_bill(Barcodes, Lines, Total, Width, Discount, | |
Inventory) | |
end. | |
test_print_bill() -> | |
[" Erlang Stores", "", "", | |
"Total.....................0.00"] = | |
print_bill([], [], 0, 30, 0, items()), | |
[" Erlang Stores", "", | |
"Dry Sherry, 1lt...........5.40", | |
"Fish Fingers..............1.21", "", | |
"Total.....................6.61"] = | |
print_bill([1234, 4719], [], 0, 30, 0, items()), | |
[" Erlang Stores", "", | |
"Dry Sherry, 1lt...........5.40", | |
"Fish Fingers..............1.21", | |
"Dry Sherry, 1lt...........5.40", "", | |
"Discount.................-1.00", "", | |
"Total....................11.01"] = | |
print_bill([1234, 4719, 1234], [], 0, 30, -100, | |
items()), | |
ok. | |
% Formats Name and Cost as a string of legth Width | |
format_line_item(Name, Cost, Width) -> | |
Right = format_cost(Cost), | |
Left = string:left(Name, Width - length(Right), $.), | |
Left ++ Right. | |
test_format_line_item() -> | |
"Fish Fingers..............1.21" = | |
format_line_item("Fish Fingers", 121, 30), | |
ok. | |
% format an int representing cents as a string representing dollars | |
format_cost(Digits) -> | |
format_cost(integer_to_list(Digits), ""). | |
format_cost([Digit], "") -> "0.0" ++ [Digit]; | |
format_cost([Dimes, Cents], "") -> | |
"0." ++ [Dimes, Cents]; | |
format_cost([Dimes, Cents], Acc) -> | |
Acc ++ "." ++ [Dimes, Cents]; | |
format_cost([Digit | Digits], Acc) -> | |
format_cost(Digits, Acc ++ [Digit]). | |
test_format_cost() -> | |
"0.00" = format_cost(0), | |
"0.56" = format_cost(56), | |
"5.40" = format_cost(540), | |
"13.90" = format_cost(1390), | |
ok. | |
% returns the item name and cost for a barcode | |
lookup_barcode(Barcode) -> | |
lookup_barcode(Barcode, items()). | |
lookup_barcode(_, []) -> {}; % or {"Unknown Item", 0}; | |
lookup_barcode(Barcode, [{Code, Name, Cost} | Items]) -> | |
case Code of | |
Barcode -> {Name, Cost}; | |
_ -> lookup_barcode(Barcode, Items) | |
end. | |
test_lookup_barcode() -> | |
{"Hula Hoops", 21} = lookup_barcode(1111), ok. | |
test() -> | |
test_item_count(), | |
test_remove_item(), | |
test_update_item(), | |
test_format_cost(), | |
test_format_line_item(), | |
test_lookup_barcode(), | |
test_print_bill(), | |
ok. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment