import re from datetime import datetime # constants MAX_PIZZAS = 5 DELIVERY_FEE = 3.00 # pizza and extras menus pizza_menu = [ ["Margherita", 8.50], ["Pepperoni", 9.00], ["BBQ Chicken", 10.00], ["Veggie Delight", 9.00], ["Meatlovers", 11.50], ["Hawaiian", 9.50], ["Cheeseburger", 10.00], ["Chicken Cranberry", 11.00], ["Beef & Onion", 9.50], ["Garlic & Cheese", 8.00] ] extras_menu = [ ["Drink", 2.50], ["Fries", 3.00], ["Extra Cheese", 1.50], ["Garlic Sauce", 1.00], ["Dipping Box", 3.50] ] # --- helper functions --- def display_menu(): print("\n--- Pizza Menu ---") for i, item in enumerate(pizza_menu, 1): print(f"{i}. {item[0]} - ${item[1]:.2f}") def display_extras(): print("\n--- Optional Extras ---") for i, item in enumerate(extras_menu, 1): print(f"{i}. {item[0]} - ${item[1]:.2f}") def not_blank(prompt): while True: s = input(prompt).strip() if s: return s print("This can't be blank. Try again.") def string_check(prompt, valid_list, min_letters=1): valid_list = [v.lower() for v in valid_list] while True: ans = input(prompt).strip().lower() if not ans: print(f"Choose from {valid_list}") continue for v in valid_list: if ans == v or ans == v[:min_letters]: return v print(f"Choose from {valid_list}") def normalize_phone(phone_raw): digits = re.sub(r"\D", "", phone_raw) if digits.startswith("64"): digits = "0" + digits[2:] return digits def get_valid_phone(): allowed_prefixes = ("02", "03", "04", "06", "07", "09") while True: raw = input("Enter your phone number (NZ): ").strip() phone = normalize_phone(raw) if phone.isdigit() and 9 <= len(phone) <= 11 and phone.startswith(allowed_prefixes): return phone print("Invalid phone. Must be NZ format (e.g. 0211234567).") def get_valid_address(): while True: address = input("Enter your address: ").strip() if len(address) < 3: print("Address is too short.") continue if not re.search(r"[A-Za-z]", address): print("Address needs a street name (letters).") continue if not re.search(r"\d", address): print("Address needs a house number (digit).") continue return address def get_customer_details(): name = not_blank("Enter your name: ").strip().capitalize() + "." phone = get_valid_phone() delivery = string_check("Pickup or delivery? ", ["pickup", "delivery"], 1) address = "" if delivery == "delivery": address = get_valid_address() return {"name": name, "phone": phone, "delivery": delivery, "address": address} def get_order(): order = {} while True: try: n = int(input(f"How many pizzas? (1-{MAX_PIZZAS}): ")) except ValueError: print("Enter a number.") continue if 1 <= n <= MAX_PIZZAS: break print(f"Enter a number between 1 and {MAX_PIZZAS}.") display_menu() for i in range(n): while True: try: choice = int(input(f"Select pizza #{i+1} (1-{len(pizza_menu)}): ")) except ValueError: print("Enter a number.") continue if 1 <= choice <= len(pizza_menu): name, price = pizza_menu[choice-1] if name in order: order[name]["qty"] += 1 else: order[name] = {"price": price, "qty": 1} print(f"Added: {name} x{order[name]['qty']}") break else: print("That number is not on the menu.") return order def get_extras(): extras = [] want = string_check("Do you want extras? (yes/no): ", ["yes", "no"], 1) if want == "yes": display_extras() while True: choice = input("Extra number or 'x' to stop: ").strip().lower() if choice == "x": break try: idx = int(choice) except ValueError: print("Enter a number or x.") continue if 1 <= idx <= len(extras_menu): e = extras_menu[idx-1] extras.append(e) print(f"Added extra: {e[0]}") else: print("Invalid number.") return extras def calculate_total(order_dict, extras_list, delivery_bool): subtotal = 0.0 for name, info in order_dict.items(): subtotal += info["price"] * info["qty"] for e in extras_list: subtotal += e[1] delivery_fee = DELIVERY_FEE if delivery_bool else 0.0 total = subtotal + delivery_fee return subtotal, delivery_fee, total def build_summary(customer, order_dict, extras, delivery_fee, subtotal, total): lines = [] lines.append("PIZZA ORDER") lines.append(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") lines.append(f"Customer: {customer['name']}") lines.append(f"Phone: {customer['phone']}") lines.append(f"Order Type: {customer['delivery'].capitalize()}") if customer["delivery"] == "delivery": lines.append(f"Address: {customer['address']}") lines.append("") lines.append("Items:") for name, info in order_dict.items(): lines.append(f"- {name} x{info['qty']}: ${info['price']:.2f} each") if extras: lines.append("") lines.append("Extras:") for e in extras: lines.append(f"- {e[0]}: ${e[1]:.2f}") if delivery_fee > 0: lines.append(f"\nDelivery fee: ${delivery_fee:.2f}") lines.append(f"\nSubtotal: ${subtotal:.2f}") lines.append(f"Total: ${total:.2f}") return lines def write_order_file(lines, filename="order_log.txt"): try: with open(filename, "a", encoding="utf-8") as f: f.write("\n".join(lines)) f.write("\n" + "-"*30 + "\n") return True except Exception as e: print("Failed to write order file:", e) return False # --- main loop --- def main(): while True: print("\nWelcome. Start pizza order.") show = string_check("Do you want to see the menu? (yes/no): ", ["yes", "no"], 1) if show == "yes": display_menu() show_extras_menu = string_check("Would you like to see the extras menu? (yes/no): ", ["yes", "no"], 1) if show_extras_menu == "yes": display_extras() customer = get_customer_details() order = get_order() extras = get_extras() subtotal, delivery_fee, total = calculate_total(order, extras, customer["delivery"]=="delivery") summary = build_summary(customer, order, extras, delivery_fee, subtotal, total) confirm = string_check("Confirm order? (yes/no): ", ["yes", "no"], 1) if confirm == "yes": for line in summary: print(line) written = write_order_file(summary) if written: print("Order saved.") else: print("Order cancelled.") again = string_check("\nDo you want to place another order? (yes/no): ", ["yes", "no"], 1) if again == "no": print("Thanks for using the Pizza Ordering System!") break if __name__ == "__main__": main()