I need to create a function that creates a session that accepts a "clerk's" input data about a customer's orders until the "clerk" enters the string "/". Each line of input consists of two elements: the product code and the quantity. Lines of input are formatted as follows: "{product_code},{quantity}". The function should write a file called receipt.txt that prints a summarized report of the session.
The receipt should provide a summary of all the orders made during the session and the product must only appear once if it has been ordered at least once during the session, even if it has been ordered multiple times. In other words, if a product is ordered multiple times, then it should only have one entry in the receipt that describes the sum of all of the orders made for that product. The products must appear in alphabetical order.
Here is my code right now and it prints a receipt but I don't know how to make the order appear only once and make it alphabetical order. Please help.
EDIT: Added get_property function.
def get_property(code,property):
return products[code][property]
def main():
products = {
"americano":{"name":"Americano","price":150.00},
"brewedcoffee":{"name":"Brewed Coffee","price":110.00},
"cappuccino":{"name":"Cappuccino","price":170.00},
"dalgona":{"name":"Dalgona","price":170.00},
"espresso":{"name":"Espresso","price":140.00},
"frappuccino":{"name":"Frappuccino","price":170.00},
}
orders_list = []
total = 0
while(True):
customer_order = input("Welcome to the CoffeePython POS Terminal.\nPlease enter the Product Code and the Quantity in this format - {Product Code},{Quantity}.\nEnter '/' to quit.\n")
if customer_order == "/":
break
else:
code_quantity_list = customer_order.split(",")
code = code_quantity_list[0]
quantity = code_quantity_list[1]
quantity_int = int(quantity)
if code in products:
subtotal = get_property(code,"price")*quantity_int
total += subtotal
ordered_item = dict([
('code', code),
('qty', quantity_int),
('subtotal', subtotal)
])
orders_list.append(ordered_item)
else:
print("The Product Code that you entered is invalid. Please try again.")
print("==")
print("CODE\t\t\tNAME\t\t\tQUANTITY\t\t\tSUBTOTAL")
for order in orders_list:
order_code = order['code']
order_name = products[order_code]["name"]
order_qty = order['qty']
order_subtotal = order['subtotal']
print(f"{order_code}\t\t{order_name}\t\t{order_qty}\t\t\t\t{order_subtotal}\t\t")
print(f"\nTotal:\t\t\t\t\t\t\t\t\t\t{total}")
print("==")
print("Thank you for ordering. Goodbye.")
main()
Output
==
CODE NAME QUANTITY SUBTOTAL
americano Americano 2 300.0
americano Americano 2 300.0
Total: 600.0
==
To store the orders, I would suggest you to use a dictionary with code as a key, and the price as value.
orders_list = {}
while ...:
orders_list[code] = orders_list.setdefault(code, 0) + subtotal
for product in sorted(orders_list):
subtotal = orders_list[product]
print(f"{product:<10} {subtotal}")
You need to check the saved list in orders_list and then evaluate the existing key. For sort list in the order_list by key in a dict, you can use this reference
How do I sort a list of dictionaries by a value of the dictionary?
I am adding a new method to perform check.
Also, I am not sure about your get_property() method, I changed it a bit.
def check_code(orders_list, code):
codes = []
for i in orders_list:
codes.append(i["code"])
if(code in codes):
return True, codes.index(code)
else:
return False, 0
def main():
products = {
"americano":{"name":"Americano","price":150.00},
"brewedcoffee":{"name":"Brewed Coffee","price":110.00},
"cappuccino":{"name":"Cappuccino","price":170.00},
"dalgona":{"name":"Dalgona","price":170.00},
"espresso":{"name":"Espresso","price":140.00},
"frappuccino":{"name":"Frappuccino","price":170.00},
}
orders_list = []
total = 0
while(True):
customer_order = input("Welcome to the CoffeePython POS Terminal.\nPlease enter the Product Code and the Quantity in this format - {Product Code},{Quantity}.\nEnter '/' to quit.\n")
if customer_order == "/":
break
else:
code_quantity_list = customer_order.split(",")
code = code_quantity_list[0]
quantity = code_quantity_list[1]
quantity_int = int(quantity)
if code in products:
# subtotal = get_property(code,"price")*quantity_int
subtotal = products[code]["price"] *quantity_int
check = check_code(orders_list, code)
if check[0]:
orders_list[check[1]]["subtotal"] += subtotal
orders_list[check[1]]["qty"] += quantity_int
else:
ordered_item = dict([
('code', code),
('qty', quantity_int),
('subtotal', subtotal)
])
orders_list.append(ordered_item)
total += subtotal
else:
print("The Product Code that you entered is invalid. Please try again.")
print("==")
print("CODE\t\t\tNAME\t\t\tQUANTITY\t\t\tSUBTOTAL")
orders_list = sorted(orders_list, key=lambda k: k['code'])
for order in orders_list:
order_code = order['code']
order_name = products[order_code]["name"]
order_qty = order['qty']
order_subtotal = order['subtotal']
print(f"{order_code}\t\t{order_name}\t\t{order_qty}\t\t\t\t{order_subtotal}\t\t")
print(f"\nTotal:\t\t\t\t\t\t\t\t\t\t{total}")
print("==")
print("Thank you for ordering. Goodbye.")
main()
When i test the code the item prints once and i did following:
frappuccino, 1
americano, 2
dalgona, 1
So i cannot reproduce the issue but i dont have the get_properties method either so maybe thats the issue.
As for printing the list in alphabetical order you should look to sort the list before looping and printing the reciept. You will find how you can achieve sort on a list containing dictionaries
here
Related
I am coding a program that simulates someone making a purchase in a grocery store. I am displaying all the products and the price and I am prompting the user to input all the products they went to buy separated by commas. I want the program to check if the input is in the dictionary of product and add it to the cart with the use of a loop. Before adding it to cart the program needs to check if the input is valid, meaning if the item is in the list of products to buy. When the user selects an item to buy, I want the program to ask the user for the quantity of that item, so how many of the item they want to buy. At the samThen the program will calculate the total of all the products, then calculate the tax value, 24% of the total, and then return a subtotal that includes tax. Here is what I have so far:
def calculatetotal(slist, produce):
# for each item on the shoping list look up the cost & calculate total price
item_price = 0
subtotal = 0
VAT = 0
final_total = 0
basket = {}
for item in slist:
item_price = produce.get(item)
basket[item] = item_price
subtotal = subtotal + item_price
basket["Subtotal"] = subtotal
#calculating VAT
VAT = subtotal * 0.24
basket["VAT"] = VAT
#calculating price with tax
final_total = subtotal + VAT
basket["Total"] = final_total
# print off results
return basket
def main():
# set up grocery list with prices
produce={"Rice":5.00, "Bread":2.00, "Sugar":1.5, "Apple":0.75, "Cereal":3.75, "Gum": 1.00, "Water": 1.75, "Soda": 2.00}
# process input from the user - get a shopping list
item = input("Please enter the items that you want to buy: ")
slist = []
while(item != 'stop'):
if not (item in slist):
slist.append(item)
item = input("Please enter the items that you want to buy: ")
result = calculatetotal(slist, produce)
print(result)
main()
I've gotten most of it, but the small changes that I mentioned above, I can't figure out what to do. I forgot to mention that asking for the quantity of the item and checking if the user input has to be done with a loop. Any input is very much appreciated. Please show the change of code. Thank you in advance.
In this case I would simply go for a while loop
while True:
item = input("Please enter the items that you want to buy: ")
if item == 'Stop':
break
elif item not in produce or item in slist:
# error message or whatever
else:
num = int(input("Enter Quantity"))
# other operations
The code is a follows:
n=str(input("Enter the name of the item:"))
p=int(input("Enter the price of the item:"))
r=int(input("Enter the quantity of the item:"))
tot=p*r
GST=tot+(5/100)*tot
print("Bill:")
print("Item", "\t\t\tPrice", "\tQuantity", "\tGST", "\tTotal cost")
print(n,"\t\t", p, "\t", r, "\t\t5%","\t", GST)
The number of items n must be given as user input
Try converting 'v 'variable' to list so u can access it using indexes and even user can enter many items to it
why don't you make a loop like:
stopped = False
items = []
prices = []
quantities = []
while not stopped:
items.append(str(input("Enter the name of the item:")))
prices.append(int(input("Enter the price of the item:")))
quantities.append(int(input("Enter the quantity of the item:")))
c = ""
while c not in ["yes", "no"]:
c = input("continue ? type yes or no")
if c == "no":
stopped = True
# then make your processing of these lists.
I am a new learner in python trying to understand the logic and the solution of this problem.Exercise says to create an order app for a coffee shop .
import uuid # GET A RANDOM ID FOR THE CUSTOMER
from datetime import date # GET CURRENT DATE
from csv import DictWriter
inlist = -1
length = 0
Total_Amount = 0.0
CustomerList = []
AddressList = []
Today_Key = date.toordinal(date.today())
Today_Date = date.today()
Print_Today = Today_Date
Customers = {}
Dates = {}
FirstEmployeeAccountUsername = "coffee1"
FirstEmployeeAccountPassword = "coffeeshop1"
SecondEmployeeAccountUsername = "coffee2"
SecondEmployeeAccountPassword = "coffeeshop2"
ThirdEmployeeAccountUsername = "coffee3"
ThirdEmployeeAccountPassword = "coffeeshop3"
print("Welcome to our coffee shop!")
print("Login")
# EMPLOYEE LOGIN PROCESS STARTS
LoginEnter = True
while LoginEnter:
username = input("Username: ")
password = input("Password: ")
if username == FirstEmployeeAccountUsername and password == FirstEmployeeAccountPassword or username == SecondEmployeeAccountUsername and password == SecondEmployeeAccountPassword or username == ThirdEmployeeAccountUsername and password == ThirdEmployeeAccountPassword:
print("Login Successful")
LoginEnter = False
else:
print("Invalid Login. Try again")
# EMPLOYEE LOGIN PROCESS ENDS
# PROCESS AFTER ORDER PLACEMENT STARTS
process1 = True
process2 = True
while process1:
while process2:
Customer_Name = input("Customer's Name:")
CustomerList.append(Customer_Name)
Customers_Address = input("Customer's Address:")
AddressList.append(Customers_Address)
if Today_Key not in Dates:
Dates[Today_Key] = {}
if Customer_Name not in Dates[Today_Key]:
Dates[Today_Key][Customer_Name] = 1
else:
Dates[Today_Key][Customer_Name] += 1
if Customer_Name in Customers:
Customers[Customer_Name]['Orders'] += 1
Customers[Customer_Name]['TotalAmount'] = Total_Amount
else:
Customers[Customer_Name] = {}
Customers[Customer_Name]['Address'] = Customers_Address
Customers[Customer_Name]['ID'] = uuid.uuid1()
Customers[Customer_Name]['Orders'] = 1
Customers[Customer_Name]['TotalAmount'] = 0
print(Customer_Name, "has ordered {} time(s)".format(Customers[Customer_Name]['Orders']))
if Customers[Customer_Name]['TotalAmount'] == 0:
print("This is the first time", Customer_Name, "orders")
else:
print(Customer_Name, "has spent", Customers[Customer_Name]['TotalAmount'], "in total")
print("Current Date is: {}".format(Today_Date))
Order_Price = float(input("Total amount of order:"))
Total_Amount = Order_Price + Total_Amount
if Print_Today != Today_Date:
print("Total amount of orders today is: ", float(Total_Amount))
answer1 = input("Send another order? (Y/N)").lower()
if answer1 == "y":
process2 = True
else:
process2 = False
LengthCustomersList = len(CustomerList)
length += 1
inlist += 1
file = open('CustomerNames.txt', 'w')
file.write(str(CustomerList[0:]) + '\n') # TAKE CARE FOR DUPLICATE NAMES FROM SAME ADDRESS
file.close()
file1 = open('Orders_Per_Users.txt', 'a')
file1.write(Customer_Name + " has ordered " + str(
Customers[Customer_Name]['Orders']) + " times in total\n") # FIX DUPLICATES SAME NAME SAME ADDRESS
file1.close()
with open('data_entered.csv', 'a') as f:
csv_writer = DictWriter(f, fieldnames=['Customer Name', 'Customer Address', 'Customer ID', 'Total Orders',
'Total Amount'])
csv_writer.writeheader()
csv_writer.writerows([{'Customer Name': CustomerList[inlist], 'Customer Address': AddressList[inlist],
'Customer ID': Customers[Customer_Name]['ID'],
'Total Orders': Customers[Customer_Name]['Orders'],
'Total Amount': Customers[Customer_Name]['TotalAmount']}])
if int(length) == int(LengthCustomersList):
process1 = False
My idea is to do something like an if statement so when the same Customer ID and the same CustomerName show up in the .csv file , one of them gets deleted, so the file does not contain any duplicates like those in the screenshot above.
I am not sure we are going to eventually solve your question but I wanted to give you some inputs that you can use to fix your code.
Use of variable Today_Date and Print_Today in your code
Today_Date = date.today()
Print_Today = Today_Date
if Print_Today != Today_Date:
These two lines are set to the same value. Later on in the code, you are checking if the are not equal. I checked Print_Today and Today_Date for reassignment. None occurs. So how do you expect these two variables to have different values?
If this program runs for infinite number of days, it will still NOT change the value of these two variables. The reason is they were defined at the beginning of the program and never changed. You may want to look into it.
The use of Today_Key in Dates dictionary in your code.
Today_Key = date.toordinal(date.today())
Dates = {}
You are using Today_Key to count the number of times a customer name was entered. I don't see a point in having Today_Key as the key unless you plan to have more than one key in the dictionary. This was set at the beginning of the program and never changed. So what do you intend to do with this key? I don't think you should have that as key. Instead you should just keep track of the customer names. Also, you are not printing or writing this information into a file. Are you intending to use this later in the program? I dont see the value and it may just be using up memory space and processing time.
Use of multiple names for Username & Password.
You have created 6 variables to store username & password. In other places, you are using dictionary. So why are you not taking advantage of the dictionary here?
FirstEmployeeAccountUsername = "coffee1"
FirstEmployeeAccountPassword = "coffeeshop1"
SecondEmployeeAccountUsername = "coffee2"
SecondEmployeeAccountPassword = "coffeeshop2"
ThirdEmployeeAccountUsername = "coffee3"
ThirdEmployeeAccountPassword = "coffeeshop3"
Instead of these, can't you just define a dict variable and check for the value as shown below?
UserLogin = {"coffee1":"coffeeshop1", "coffee2": "coffeeshop2", "coffee3": "coffeeshop3"}
username = password = ''
while True:
username = input("Username: ")
password = input("Password: ")
if (username in UserLogin) and (UserLogin[username] == password):
print("Login Successful")
break
else:
print("Invalid Login. Try again")
For your customer name counter portion, try this. I dont think you are actually doing anything with the counter. If you are, this code is much simpler.
CustomerCounts = defaultdict(int)
while True:
Customer_Name = input("Customer's Name:")
CustomerList.append(Customer_Name)
Customers_Address = input("Customer's Address:")
AddressList.append(Customers_Address)
CustomerCounts[Customer_Name] += 1
similarly, try using defaultdict and reduce a lot of code you have written. In the end, there is lot of code optimization and logic corrections you can do. However, it does not solve the infinite loop situation.
I'm just starting to learn python and have written a script with three functions. After the Q input is passed through I receive a Traceback error.
This is just a learning exercise so I can develop my Python skills. The learning module source code and my code appear to be exactly the same, but for some reason my output returns an error.
File "C:\Users\Desktop\DearWorld\new.py", line 36, in <module>
main()
File "C:\Users\Desktop\DearWorld\new.py", line 33, in main
total = bill_total(orders, menu)
File "C:\Users\Desktop\DearWorld\new.py", line 24, in bill_total
for order in orders:
TypeError: 'NoneType' object is not iterable
menu = {'Angel Dust Blunt': 6.66, 'The OG Blunt': 4.20, 'Caviar Blunt': 7.10, 'The Chronic Blunt' : 4.20}
def print_menu(menu):
for name, price in menu.items():
print(name, ': $', format(price, '.2f'), sep = '')
def get_order(menu):
orders = []
order = input("What would you like to order (Q to quit)")
while (order.upper() != 'Q'):
#Find the order and add it to the list if it exists
found = menu.get(order)
if found:
orders.append(order)
else:
print("Menu item doesn't exist")
order = input("Anything else? (Q to Quit)")
def bill_total(orders, menu):
total = 0
for order in orders:
total += menu[order]
return total
def main():
menu = {'Angel Dust Blunt': 6.66, 'The OG Blunt': 4.20, 'Caviar Blunt': 7.10, 'The Chronic Blunt' : 4.20}
print_menu(menu)
orders = get_order(menu)
total = bill_total(orders, menu)
print("You ordered:" ,order, "Your total is: $", format(total, '.2f'), sep='')
main()
The script is supposed to return the bill_total and the items ordered as the output. What is returned instead when the user enters 'Q' is a 'TypeError'
Late answer, but you can use:
menu = {
"1": {"name":"Angel Dust Blunt", "price":6.66},
"2": {"name":"The OG Blunt", "price":6.66},
"3": {"name":"Caviar Blunt", "price":7.10},
"4": {"name":"The Chronic Blunt", "price":4.20}
}
orders = []
def print_menu():
for k, v in menu.items():
print(f"[{k}] - ", v['name'], ': $', format(v['price'], '.2f'), sep = '')
def bill_total():
total = 0
for id in orders:
total += menu[id]['price']
return total
def get_order():
while 1:
order = input(f"What would you like to order (Q to quit)\n")
if order.strip().upper() == 'Q':
return
else:
found = menu.get(order)
if found:
# avoid dup orders, can be improved to increase the count of product items.
if order in orders:
print("Product already in cart")
continue
orders.append(order)
print(f"Item {found['name']} added to cart")
else:
print("Menu item doesn't exist")
print_menu(), get_order(), print("You ordered:\n")
for id in orders:
print(menu[id]['name'], f"${menu[id]['price']}")
print(f"\nYour total is: ${bill_total()}" )
Python Demo
Asciinema (just for fun)
Your get_order function isn't returning anything, so the value of orders in the line:
orders = get_order(menu)
will be None. Then you're trying to iterate over the variable, and it will fail.
You need to add this line at the end of the get_order function:
return orders
So the function should look like this:
def get_order(menu):
orders = []
order = input("What would you like to order (Q to quit)")
while (order.upper() != 'Q'):
#Find the order and add it to the list if it exists
found = menu.get(order)
if found:
orders.append(order)
else:
print("Menu item doesn't exist")
order = input("Anything else? (Q to Quit)")
return orders # Added this line
The reason is that orders is None, and it is because the function get_order returns nothing.
look at this line:
orders = get_order(menu)
you should add:
return orders
at the end of get_order function. like this:
def get_order(menu):
orders = []
order = input("What would you like to order (Q to quit)")
while (order.upper() != 'Q'):
#Find the order and add it to the list if it exists
found = menu.get(order)
if found:
orders.append(order)
else:
print("Menu item doesn't exist")
order = input("Anything else? (Q to Quit)")
return orders
Your get_order() function has no return statement. As a result, it will always return None. Therefore, in main():
orders = get_order(menu)
total = bill_total(orders, menu)
orders will get a value of None, which is then passed to bill_total(). When you try to iterate over that in the for loop, the result is the exception you're seeing
I am trying to print the total of the shopping list but every time i call on the string it prints 0 instead of what it should be.
cash_due = 0
import pickle
picklee = open('Store_stuff.pickle', 'rb')
contents = pickle.load(picklee)
picklee.close()
shopping_list = ['Name price quantity total']
store_contents ='''Store Contents
Name Price GTIN-8 Code
Butter £1.20 70925647
Chocolate £1.00 11826975
Bread £1.00 59217367
Cheese £2.80 98512508
Bacon £2.40 92647640
Lamb £4.80 49811230
Ham £2.59 53261496
Potatoes £2.00 11356288
Chicken £3.40 89847268
Eggs £1.29 21271243'''
def item(barcode, quantity, cash_due, shopping_list):
shopping_list.append(contents[barcode]['name']+' £'+(str((int(contents[barcode]['price']))/100))+' '+str(quantity)+' £'+str((int(quantity)*int(contents[barcode]['price']))/100))
print(cash_due)
print(contents[barcode]['price'])
print(quantity)
cash_due += ((int(contents[barcode]['price'])*(int(quantity)))/100)
print(cash_due)
def shopkeeper_ui():
print('Welcome to Stanmore\'s Food Emporium! Feel free to browse.')
print(store_contents)
user_input = ''
while user_input != 'finish':
user_input = input('''Welcome to the checkout.
instructions -
if you are entering text make sure your \'CAP\'s Lock\' is turned off
if you are entering a barcode number, please enter it carefully
if you want to print your current recipt, enter \'recipt\'
if you want to see your current total, enter \'total\'
and if you are finished, enter \'finish\'
You can see the stores contents below
Thanks for shopping: ''')
if len(user_input) == 8:
quantity = int(input('Enter the quantity that you want: '))
item(user_input, quantity, cash_due, shopping_list)
elif user_input == 'recipt':
count8 = 0
for i in shopping_list:
print(shopping_list[count8])
count8 += 1
elif user_input == 'finish':
print('Your shopping list is',shopping_list,' \nand your total was', total,'\n Thank you for shopping with Stanmore\'s Food Emporium')
elif user_input == 'total':
print('your total is, £',cash_due)
else:
print('User_input not valid. Try again...')
shopkeeper_ui()
If i enter the code and my first entry is 21271243 (the barcode for eggs). then i enter 4 for the quantity. i can get the shopping_list list to understand the total and if I print the string cash_due from inside the item function it understands it but as soon as i try to call cash_due from the shopkeeper_ui function it prints 0 instead of what should be 5.12?
cash_due is not mutable. Changes in item function are lost when leaving the function.
Generally, the way out of this is to let the function (item) return the value.
In this case, I would just keep cash_due out of item function and let item only return the cost for that item. Something like this:
def item(barcode, quantity, shopping_list):
shopping_list.append(contents[barcode]['name']+' £'+(str((int(contents[barcode]['price']))/100))+' '+str(quantity)+' £'+str((int(quantity)*int(contents[barcode]['price']))/100))
print(contents[barcode]['price'])
print(quantity)
cost = ((int(contents[barcode]['price'])*(int(quantity)))/100)
print(cost)
return cost
[...]
if len(user_input) == 8:
quantity = int(input('Enter the quantity that you want: '))
cash_due += item(user_input, quantity, shopping_list)
You don't have the same issue with shopping_list because it is a mutable: it is changed in place. Read about mutables to understand the concept.
However, it could be better design to not let item modify the list. It could just return both the list element and the cost, and the caller would modify the list.
def item(barcode, quantity):
stuff = (contents[barcode]['name']+' £'+(str((int(contents[barcode]['price']))/100))+' '+str(quantity)+' £'+str((int(quantity)*int(contents[barcode]['price']))/100))
cost = ((int(contents[barcode]['price'])*(int(quantity)))/100)
return stuff, cost
[...]
if len(user_input) == 8:
quantity = int(input('Enter the quantity that you want: '))
stuff, cost = item(user_input, quantity, shopping_list)
shopping_list.append(stuff)
cash_due += cost