diff --git a/Pipfile b/Pipfile index dd782fb0e..1a74f8052 100644 --- a/Pipfile +++ b/Pipfile @@ -7,6 +7,7 @@ name = "pypi" ipdb = "*" faker = "*" pytest = "7.1.3" +colorama = "*" [dev-packages] diff --git a/Pipfile.lock b/Pipfile.lock index 65384111f..08e08155e 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5c9ab3d3df05028a37934f5beef7b9fd83f4720c871befa2abcbf7363aa550a4" + "sha256": "1c7ec9806e2940016797a4f7b310634e6463b4604eed9e05edcacf8b1da35f3a" }, "pipfile-spec": 6, "requires": { @@ -38,6 +38,15 @@ ], "version": "==0.2.0" }, + "colorama": { + "hashes": [ + "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", + "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" + ], + "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6'", + "version": "==0.4.6" + }, "decorator": { "hashes": [ "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", diff --git a/README.md b/README.md index 79b19b1bf..cabb6a4c5 100644 --- a/README.md +++ b/README.md @@ -1,172 +1,50 @@ -# Phase 3 CLI+ORM Project Template +# ๐Ÿน๐Ÿบ The Thirsty Python Bar ๐Ÿฅƒ๐Ÿธ -## Learning Goals - -- Discuss the basic directory structure of a CLI. -- Outline the first steps in building a CLI. +Welcome to **The Thirsty Python Bar**! ๐Ÿป This terminal-based drink ordering simulator allows you to simulate your experience at a bar, all through a Command-Line Interface (CLI) powered by Python. Whether it's your birthday or you're just looking to grab a drink, this project offers an interactive way to place drink orders, manage customer tabs, and celebrate special occasions โ€” all while keeping track of orders with an SQL database. --- -## Introduction - -You now have a basic idea of what constitutes a CLI. Fork and clone this lesson -for a project template for your CLI. - -Take a look at the directory structure: +## ๐ŸŽ‰ Features ๐ŸŽ‰ -```console -. -โ”œโ”€โ”€ Pipfile -โ”œโ”€โ”€ Pipfile.lock -โ”œโ”€โ”€ README.md -โ””โ”€โ”€ lib - โ”œโ”€โ”€ models - โ”‚ โ”œโ”€โ”€ __init__.py - โ”‚ โ””โ”€โ”€ model_1.py - โ”œโ”€โ”€ cli.py - โ”œโ”€โ”€ debug.py - โ””โ”€โ”€ helpers.py -``` - -Note: The directory also includes two files named `CONTRIBUTING.md` and -`LICENSE.md` that are specific to Flatiron's curriculum. You can disregard or -delete the files if you want. +- ๐Ÿ™‹ **Customer Creation**: Create a customer profile and verify if they are old enough to enter the bar. +- ๐Ÿฅณ **Birthday Fun**: Celebrate your birthday and automatically update your age when you do. +- ๐Ÿน **Drink Management**: Add, remove, and select drinks from the menu. +- ๐Ÿ’ณ **Tabs**: Track the drinks a customer has ordered. Open a new tab, view previous orders, and switch between tabs. +- ๐Ÿ’ต **Tab Closure**: Once the customer has closed their tab, all their orders are removed from the system, and the customer is logged out. +- ๐Ÿ’พ **SQL Backend**: The system uses an SQL database to store, update, and retrieve customer and drink data. --- -## Generating Your Environment - -You might have noticed in the file structure- there's already a Pipfile! - -Install any additional dependencies you know you'll need for your project by -adding them to the `Pipfile`. Then run the commands: - -```console -pipenv install -pipenv shell -``` - ---- - -## Generating Your CLI - -A CLI is, simply put, an interactive script and prompts the user and performs -operations based on user input. - -The project template has a sample CLI in `lib/cli.py` that looks like this: - -```py -# lib/cli.py - -from helpers import ( - exit_program, - helper_1 -) - - -def main(): - while True: - menu() - choice = input("> ") - if choice == "0": - exit_program() - elif choice == "1": - helper_1() - else: - print("Invalid choice") - +## ๐Ÿ’ป Technologies Used ๐Ÿ’ป -def menu(): - print("Please select an option:") - print("0. Exit the program") - print("1. Some useful function") - - -if __name__ == "__main__": - main() -``` - -The helper functions are located in `lib/helpers.py`: - -```py -# lib/helpers.py - -def helper_1(): - print("Performing useful function#1.") - - -def exit_program(): - print("Goodbye!") - exit() -``` - -You can run the template CLI with `python lib/cli.py`, or include the shebang -and make it executable with `chmod +x`. The template CLI will ask for input, do -some work, and accomplish some sort of task. - -Past that, CLIs can be whatever you'd like, as long as you follow the project -requirements. - -Of course, you will update `lib/cli.py` with prompts that are appropriate for -your application, and you will update `lib/helpers.py` to replace `helper_1()` -with a useful function based on the specific problem domain you decide to -implement, along with adding other helper functions to the module. - -In the `lib/models` folder, you should rename `model_1.py` with the name of a -data model class from your specific problem domain, and add other classes to the -folder as needed. The file `lib/models/__init__.py` has been initialized to -create the necessary database constants. You need to add import statements to -the various data model classes in order to use the database constants. - -You are also welcome to implement a different module and directory structure. -However, your project should be well organized, modular, and follow the design -principal of separation of concerns, which means you should separate code -related to: - -- User interface -- Data persistence -- Problem domain rules and logic +- **Python**: The core programming language for logic and CLI interaction. +- **CLI**: Command Line Interface for interaction with the system. +- **SQL**: Database management to store customer profiles, drink menus, and order data. --- -## Updating README.md +## ๐Ÿ’พ Starting the Program ๐Ÿ’พ -`README.md` is a Markdown file that should describe your project. You will -replace the contents of this `README.md` file with a description of **your** -actual project. +To get started, first clone the repository: -Markdown is not a language that we cover in Flatiron's Software Engineering -curriculum, but it's not a particularly difficult language to learn (if you've -ever left a comment on Reddit, you might already know the basics). Refer to the -cheat sheet in this assignments's resources for a basic guide to Markdown. +- git clone git@github.com:Ketchuso/python-phase3-project.git +- cd python-phase3-project -### What Goes into a README? +Make sure you have Python installed (version 3.7 or above). -This README serves as a template. Replace the contents of this file to describe -the important files in your project and describe what they do. Each Python file -that you edit should get at least a paragraph, and each function should be -described with a sentence or two. +Before starting the application to access Colorama: -Describe your actual CLI script first, and with a good level of detail. The rest -should be ordered by importance to the user. (Probably functions next, then -models.) +- pipenv install colorama -Screenshots and links to resources that you used throughout are also useful to -users and collaborators, but a little more syntactically complicated. Only add -these in if you're feeling comfortable with Markdown. +To start the application, open your terminal and run the following command: ---- - -## Conclusion +- python lib/cli.py -A lot of work goes into a good CLI, but it all relies on concepts that you've -practiced quite a bit by now. Hopefully this template and guide will get you off -to a good start with your Phase 3 Project. +## ๐Ÿ™ Acknowledgments ๐Ÿ™ -Happy coding! - ---- +A huge thank you to the talented developers who contributed to this project: +Jay, Victoria, and Kerissa -## Resources +## ๐Ÿ“œ License ๐Ÿ“œ -- [Markdown Cheat Sheet](https://www.markdownguide.org/cheat-sheet/) +This project is licensed under the MIT License. \ No newline at end of file diff --git a/bar.drawio b/bar.drawio new file mode 100644 index 000000000..8a17f786b --- /dev/null +++ b/bar.drawio @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/cli.py b/lib/cli.py index edd1b62ad..6a25726ff 100644 --- a/lib/cli.py +++ b/lib/cli.py @@ -1,28 +1,323 @@ # lib/cli.py - +from colorama import Fore, Style, init from helpers import ( exit_program, - helper_1 + age_checker, + customer_name, + customer_age ) +from models.Customer import Customer +from models.Drink_Orders import Drink_Orders +from models.Drinks import Drinks +import os +import subprocess + +def run_seed(): + subprocess.run(["python", "lib/models/seed.py"]) +run_seed() +init() +tab_open = False +birthday = False +birthday_toggle = False +drink_count = 0 + +if not os.path.exists("company.db"): + import seed def main(): + customer = None + while True: + enter_bar(customer) + +#verifies valid choice +def get_valid_choice(valid_options): + #keep asking until a valid choice is entered while True: - menu() choice = input("> ") - if choice == "0": - exit_program() - elif choice == "1": - helper_1() + if choice in valid_options: + return choice + print(Style.BRIGHT + Fore.RED + "Invalid choice, please try again" + Style.RESET_ALL) + +#entering the bar +def enter_bar(customer): + print(Style.BRIGHT + Fore.CYAN + "\nPlease select an option:" + Style.RESET_ALL) + print("1. Can I see your ID?") + print(Fore.RED + "2. Leave" + Style.RESET_ALL) + + choice = get_valid_choice(["1", "2"]) + if choice == "1": + customer = customer_name() # Re-assign the customer object returned by customer_name() + customer_age(customer) + age_checker(customer) + option_select(customer) + elif choice == "2": + exit_program(customer) + +#main option select +def option_select(customer): + global drink_count + global birthday + emotion_state() + if drink_count < 6: + print("1. Can I get a drink?") + else: + print("Nope, no more") + + print("2. View Open Tabs") + + if tab_open: + if not birthday: + print("3. It's my birthday!") + print(Fore.RED + "4. Close Your Tab" + Style.RESET_ALL) + else: + print(Fore.RED + "3. Close Your Tab" + Style.RESET_ALL) + print(Fore.CYAN + "\nhint: to leave, close your tab" + Style.RESET_ALL) + else: + if not birthday: + print("3. It's my birthday!") + print(Fore.RED + "4. Leave" + Style.RESET_ALL) + else: + print(Fore.RED + "3. Leave" + Style.RESET_ALL) + + if drink_count < 6: + choice = get_valid_choice(["1", "2", "3", "4"]) + elif birthday: + choice = get_valid_choice(["2", "3", "4"]) + else: + choice = get_valid_choice(["2", "3", "4"]) + + if drink_count < 6: + if choice == "1": + select_drink(customer) + + if choice == "2": + view_tab(customer) + if choice == "3" and not birthday: + update_birthday(customer) + + if choice == "3" and birthday: + if tab_open: + close_tab(customer) + else: + leave(customer) + + elif choice == "4" and not birthday: + if (tab_open): + close_tab(customer) + else: + leave(customer) + +def update_birthday(customer): + global birthday, birthday_toggle + + birthday = True + birthday_toggle = True + + + customer.age += 1 + customer.update() + + option_select(customer) + + +def rainbow_text(text): + colors = [Fore.RED, Fore.YELLOW, Fore.GREEN, Fore.CYAN, Fore.BLUE, Fore.MAGENTA] + return "".join(colors[i % len(colors)] + char for i, char in enumerate(text)) + Style.RESET_ALL + +def emotion_state(): + global birthday_toggle + + if birthday_toggle: + print(Style.BRIGHT + "\n" + rainbow_text("HAPPY BIRTHDAY!!!")) + print(Fore.GREEN + Style.BRIGHT + "(โ˜ž๏พŸใƒฎ๏พŸ)โ˜ž\n" + Style.RESET_ALL) + birthday_toggle = False + else: + states = { + 0: Fore.GREEN + Style.BRIGHT + "\n<" + "(๏ฟฃ๏ธถ๏ฟฃ)>\n" + Style.RESET_ALL, + 1: Fore.GREEN + Style.BRIGHT + "\n(เน‘>แด—<เน‘)\n" + Style.RESET_ALL, + 2: Fore.GREEN + Style.BRIGHT + "\n(๏พ‰> โ—‡ <)๏พ‰\n" + Style.RESET_ALL, + 3: Fore.GREEN + Style.BRIGHT + "\nโ”—(๏ผพ0๏ผพ)โ”“\n" + Style.RESET_ALL, + 4: Fore.GREEN + Style.BRIGHT + "\nโ”€=โ‰กฮฃ((( ใคโ€ขฬ€ฯ‰โ€ขฬ)ใค\n" + Style.RESET_ALL, + 5: Fore.RED + Style.BRIGHT + "\nใƒพ(๏ฟฃโ–ก๏ฟฃ;)๏พ‰\n" + Style.RESET_ALL, + 6: Fore.RED + Style.BRIGHT + "\n(โ•ฏยฐโ–กยฐ๏ผ‰โ•ฏ๏ธต โ”ปโ”โ”ป" + Style.RESET_ALL + } + print(states[drink_count]) + +def select_drink(customer): + global drink_count + + print(Style.BRIGHT + Fore.CYAN + "\nOptions:" + Style.RESET_ALL) + drinks_list = Drinks.get_all() + print(Fore.GREEN + "Please select drink number:" + Style.RESET_ALL) + + ids = [] + for i, drink in enumerate(drinks_list): + print(f"{i + 1}. {drink.name}") + ids.append(str(i + 1)) + + copy_of_ids = ids.copy() + + print(f"{Fore.YELLOW}{len(drinks_list) + 1}. Specialty Drink {Style.RESET_ALL}") + ids.append(str(len(drinks_list) + 1)) + + print(f"{Fore.RED}{len(drinks_list) + 2}. Delete Drink {Style.RESET_ALL}") + ids.append(str(len(drinks_list) + 2)) + + print(f"{Fore.RED}{len(drinks_list) + 3}. Go Back {Style.RESET_ALL}") + ids.append(str(len(drinks_list) + 3)) + + + choice = get_valid_choice(ids) + choice = int(choice) + + if choice == (len(drinks_list) + 3): + option_select(customer) + elif choice == (len(drinks_list) + 2): + delete_drink(customer, copy_of_ids) + elif choice == (len(drinks_list) + 1): + create_specialty_drink(customer) + else: + drink_count += 1 + selected_drink = Drinks.find_by_id(choice) + if select_drink: + print(Fore.GREEN + f"\n{selected_drink.name}, right up!" + Style.RESET_ALL) + Drink_Orders.create_order(customer.name, customer.id, selected_drink.name, choice) + + if tab_open: + add_to_tab(drinks_list, choice - 1, customer) + else: + open_tab(customer) + +def create_specialty_drink(customer): + print(Fore.CYAN + "Enter the name for your specialty drink:" + Style.RESET_ALL) + drink_name = input("> ").strip() + + if not drink_name: + print(Fore.RED + "You must enter a drink name!" + Style.RESET_ALL) + return + + # Create a new specialty drink and save it to the database + try: + new_drink = Drinks.create(drink_name) + print(Fore.GREEN + f"Your specialty drink '{new_drink.name}' has been created and added!" + Style.RESET_ALL) + # Optionally, you could add this drink to the tab right away, or return it for later + Drink_Orders.create_order(customer.name, customer.id, new_drink.name, new_drink._id) + if tab_open: + add_to_tab([new_drink], 0, customer) + delete_drink(new_drink) else: - print("Invalid choice") + open_tab(customer) + + + except Exception as e: + print(Fore.RED + f"Error creating the drink: {e}" + Style.RESET_ALL) + + option_select(customer) + +def delete_drink(customer, copy_of_ids): + print(Fore.RED + "Enter number of drink to delete or go back" + Style.RESET_ALL) + + back_option = str(len(copy_of_ids) + 3) + copy_of_ids.append(back_option) + choice = get_valid_choice(copy_of_ids) + + if choice == back_option: + select_drink(customer) + else: + drink = Drinks.find_by_id(choice) + drink.delete() + option_select(customer) + + +def view_tab(customer): + customer_list = customer.get_all() + print(Fore.GREEN + "Please select tab number:" + Style.RESET_ALL) + ids = [] + for i in customer_list: + print(f"{i.id}. {i.name}", end=" | ") + ids.append(str(i.id)) + print() + + choice = get_valid_choice(ids) + select_tab(choice, customer) + +def select_tab(choice, customer): + customer = Customer.find_by_id(choice) + if customer: + customer_drinks = Drink_Orders.find_by_customer(customer.id) + if customer_drinks: + print(Style.BRIGHT + Fore.CYAN + f"Tab for {customer.name}:" + Style.RESET_ALL) + for drink_order in customer_drinks: + customer_name = drink_order[0] + drink_name = drink_order[2] + quantity = drink_order[4] + print(f"{customer_name} has ordered {quantity} {drink_name}") + else: + print(Fore.RED + "No tab open" + Style.RESET_ALL) + else: + print(Fore.RED + "Customer not found." + Style.RESET_ALL) + + # Don't allow ordering new drinks, just show tab details + print(Fore.CYAN + "\nPress enter to continue" + Style.RESET_ALL) + input() + option_select(customer) + + +def open_tab(customer): + global tab_open + print(Style.BRIGHT + Fore.CYAN + "\nWould you like to open a tab?" + Style.RESET_ALL) + print("y. yes") + print("n. no") + + choice = get_valid_choice(["y", "n"]) + if choice == "y": + print(Fore.GREEN + "Opening tab!" + Style.RESET_ALL) + tab_open = True + elif choice == "n": + print(Fore.GREEN + "Here's your total: $$$" + Style.RESET_ALL) + + print(Fore.CYAN + "\nPress enter to continue" + Style.RESET_ALL) + user_input = input() + option_select(customer) + +def add_to_tab(drinks, choice, customer): + print(Fore.GREEN + f"Adding {drinks[choice].name} to tab!" + Style. RESET_ALL) + option_select(customer) + +def close_tab(customer): + global tab_open + print(Style.BRIGHT + Fore.CYAN + "\nAre you sure?:" + Style.RESET_ALL) + print(Fore.RED + "y. yes" + Style.RESET_ALL) + print("n. No") + + choice = get_valid_choice(["y", "n"]) + if choice == "y": + # Close the tab + tab_open = False + Drink_Orders.delete_orders(customer.id) + leave_bar(customer) + elif choice == "n": + option_select(customer) + +#leaving the bar +def leave_bar(customer): + #show this if just closing tab + print(Fore.GREEN + "\nClosing Tab!" + Style.RESET_ALL) + option_select(customer) + -def menu(): - print("Please select an option:") - print("0. Exit the program") - print("1. Some useful function") +def leave(customer): + print(Style.BRIGHT + Fore.CYAN + "\nAre you sure?" + Style.RESET_ALL) + print(Fore.RED + "y. yes" + Style.RESET_ALL) + print("n. no") + choice = get_valid_choice(["y", "n"]) + if choice == "y": + exit_program(customer) + elif choice == "n": + option_select(customer) if __name__ == "__main__": main() diff --git a/lib/debug.py b/lib/debug.py index 6fadf6e66..c886a7962 100644 --- a/lib/debug.py +++ b/lib/debug.py @@ -1,8 +1,29 @@ #!/usr/bin/env python3 # lib/debug.py +#import ipdb +# from models.Customer import Customer +# from models.Drinks import Drinks +# from models.Drink_Orders import Drink_Orders -from models.__init__ import CONN, CURSOR -import ipdb +# from models.__init__ import CONN, CURSOR +# Customer.create_table() +# Drinks.create_table() -ipdb.set_trace() +# Jay = Customer(name="Jay", age=23) +# Victoria = Customer(name="Victoria", age= 25) +# Kerissa = Customer(name="Kerissa", age=33) +# Madison = Customer(name="Madison", age=20) +# Johnathan = Customer(name="Johnathan", age=18) + +# Cosmo = Drinks(name="Cosmo") +# Manhattan = Drinks(name="Manhattan") +# Tequila_Sunrise = Drinks(name="Tequila Sunrise") +# Rum_Runner = Drinks(name="Rum Runner") +# Bees_Knees = Drinks(name="Bees Knees") + + + +# Customer.delete_all() +# Drinks.delete_all() +#ipdb.set_trace() diff --git a/lib/helpers.py b/lib/helpers.py index f10df049c..c8ce05425 100644 --- a/lib/helpers.py +++ b/lib/helpers.py @@ -1,9 +1,50 @@ # lib/helpers.py +# from debug import Jay +# from debug import Victoria +# from debug import Kerissa +# from debug import Madison +# from debug import Johnathan -def helper_1(): - print("Performing useful function#1.") +from colorama import Fore, Style, init +from models.Customer import Customer +init() -def exit_program(): - print("Goodbye!") +def customer_name(): + while True: + name = input("Enter name (1-10 characters): ").strip() + try: + customer = Customer(name=name, age=25) + return customer + except (ValueError, TypeError) as e: + print(Fore.RED + str(e) + Style.RESET_ALL) + print(Fore.CYAN + "Please enter a valid name." + Style.RESET_ALL) + +def customer_age(customer): + while True: + age = input("Enter your age: ") + try: + customer.age = int(age) + customer.save() + return customer.age + except(ValueError, TypeError) as e: + print(Fore.RED + str(e) + Style.RESET_ALL) + print(Fore.CYAN + "Please enter a valid age." + Style.RESET_ALL) + +def age_checker(customer): + if customer.age >= 21: + print(Fore.GREEN + "\nWelcome in!" + Style.RESET_ALL) + else: + delete_customer(customer) + print(Fore.RED + "\nSorry gotta go!" + Style.RESET_ALL) + exit() + + +def exit_program(customer): + delete_customer(customer) + print(Fore.GREEN + "\n See ya later!" + Style.RESET_ALL) exit() + +def delete_customer(customer): + if customer: + customer.delete() \ No newline at end of file diff --git a/lib/models/Customer.py b/lib/models/Customer.py new file mode 100644 index 000000000..3ad8716aa --- /dev/null +++ b/lib/models/Customer.py @@ -0,0 +1,132 @@ +from models.__init__ import CONN, CURSOR +import ipdb + +class Customer(): + def __init__(self, name, age, id=None): + self._id = id + self.name = name + self.age = age + + @property + def id(self): + return self._id + + @property + def name(self): + return self._name + + @name.setter + def name(self, value): + if not isinstance(value, str): + raise TypeError("Name has to be a string") + if not (1 <= len(value) <= 10): + raise ValueError("Name has to be from 1-10 characters") + self._name = value + + @property + def age(self): + return self._age + + @age.setter + def age(self, value): + if not isinstance(value, int): + raise TypeError("Age has to be of type int") + if not (1 <= value <= 122): + raise ValueError("Enter a valid age") + self._age = value + + def save(self): + sql = """ + INSERT INTO customer (name, age) + VALUES (?, ?); + """ + + CURSOR.execute(sql, (self.name, self.age)) + CONN.commit() + + self._id = CURSOR.lastrowid + + def update(self): + sql = """ + UPDATE customer + SET name = ?, age = ? + WHERE id = ?; + """ + CURSOR.execute(sql, (self.name, self.age, self.id)) + CONN.commit() + + def delete(self): + sql = """ + DELETE FROM customer + WHERE id = ?; + """ + + CURSOR.execute(sql, (self.id,)) + CONN.commit() + self._id = None + + + + @classmethod + def instance_from_row(cls, row): + return cls(name=row[1], age=row[2], id=row[0]) + + @classmethod + def get_all(cls): + sql = """ + SELECT * FROM customer; + """ + + customer_rows = CURSOR.execute(sql).fetchall() + return [cls.instance_from_row(row) for row in customer_rows] + + @classmethod + def find_by_id(cls, id): + sql = """ + SELECT * FROM customer + WHERE id = ?; + """ + + row = CURSOR.execute(sql, (id,)).fetchone() + if row: + return cls.instance_from_row(row) + else: + return None + + @classmethod + def create(cls, name, age): + new_customer = cls(name=name, age=age) + new_customer.save() + return new_customer + + @classmethod + def delete_all(cls): + sql = """ + DELETE FROM customer; + """ + + CURSOR.execute(sql) + CONN.commit() + + @classmethod + def create_table(cls): + sql = """ + CREATE TABLE IF NOT EXISTS customer ( + id INTEGER PRIMARY KEY, + name TEXT, + age INTEGER + ); + """ + + CURSOR.execute(sql) + CONN.commit() + + @classmethod + def drop_table(cls): + sql = "DROP TABLE IF EXISTS customer;" + + CURSOR.execute(sql) + CONN.commit() + + def __repr__(self): + return f'' \ No newline at end of file diff --git a/lib/models/Drink_Orders.py b/lib/models/Drink_Orders.py new file mode 100644 index 000000000..fac79cb0d --- /dev/null +++ b/lib/models/Drink_Orders.py @@ -0,0 +1,54 @@ +from models.__init__ import CONN, CURSOR + + +class Drink_Orders: + def __init__(self, customer_name, customer_id, drink_name, drink_id, quantity=1): + self.customer_name = customer_name + self.customer_id = customer_id + self.drink_name = drink_name + self.drink_id = drink_id + self.quantity = quantity + + @classmethod + def create_order(cls, customer_name, customer_id, drink_name, drink_id): + # Check if the customer has already ordered this drink + existing_order = CURSOR.execute(''' + SELECT quantity FROM drink_orders + WHERE customer_id = ? AND drink_id = ? + ''', (customer_id, drink_id)).fetchone() + + if existing_order: + # If the drink exists, update the quantity + new_quantity = existing_order[0] + 1 + CURSOR.execute(''' + UPDATE drink_orders + SET quantity = ? + WHERE customer_id = ? AND drink_id = ? + ''', (new_quantity, customer_id, drink_id)) + CONN.commit() + print(f"{customer_name} has ordered another {drink_name}. New quantity: {new_quantity}") + else: + CURSOR.execute(''' + INSERT INTO drink_orders (customer_name, customer_id, drink_name, drink_id, quantity) + VALUES (?, ?, ?, ?, ?) + ''', (customer_name, customer_id, drink_name, drink_id, 1)) + CONN.commit() + print(f"Order for {customer_name} - {drink_name} added to the database.") + + @classmethod + def delete_orders(cls, customer_id): + sql = "DELETE FROM drink_orders WHERE customer_id = ?" + CURSOR.execute(sql, (customer_id,)) + CONN.commit() + + @classmethod + def find_by_customer(cls, customer_id): + sql = ''' + SELECT * FROM drink_orders + WHERE customer_id = ? + ''' + rows = CURSOR.execute(sql, (customer_id,)).fetchall() + if rows: + return rows + else: + return None diff --git a/lib/models/Drinks.py b/lib/models/Drinks.py new file mode 100644 index 000000000..9de02a8c2 --- /dev/null +++ b/lib/models/Drinks.py @@ -0,0 +1,114 @@ +from models.__init__ import CONN, CURSOR +import ipdb + + +class Drinks(): + age_requirement = 21 + + def __init__(self, name, id=None): + self._id = id + self.name = name + + @property + def name(self): + return self._name + + @name.setter + def name(self, value): + if not isinstance(value, str): + raise TypeError("Name has to be a string") + self._name = value + + def save(self): + sql = """ + INSERT INTO drinks (name) + VALUES (?); + """ + + CURSOR.execute(sql, (self.name,)) + CONN.commit() + + self._id = CURSOR.lastrowid + + def update(self): + sql = """ + UPDATE drinks + SET name = ?, + WHERE id = ?; + """ + CURSOR.execute(sql, (self.name, self.id)) + CONN.commit() + + def delete(self): + sql = """ + DELETE FROM drinks + WHERE id = ?; + """ + + CURSOR.execute(sql, (self._id,)) + CONN.commit() + self._id = None + + @classmethod + def instance_from_row(cls, row): + return cls(name=row[1], id=row[0]) + + @classmethod + def get_all(cls): + sql = """ + SELECT * FROM drinks; + """ + + drinks_rows = CURSOR.execute(sql).fetchall() + return [cls.instance_from_row(row) for row in drinks_rows] + + @classmethod + def find_by_id(cls, id): + sql = """ + SELECT * FROM drinks + WHERE id = ?; + """ + + row = CURSOR.execute(sql, (id,)).fetchone() + if row: + return cls.instance_from_row(row) + else: + return None + + @classmethod + def create(cls, name): + new_drink = cls(name=name) + new_drink.save() + return new_drink + + @classmethod + def delete_all(cls): + sql = """ + DELETE FROM drinks; + """ + + CURSOR.execute(sql) + CONN.commit() + + @classmethod + def create_table(cls): + sql = """ + CREATE TABLE IF NOT EXISTS drinks ( + id INTEGER PRIMARY KEY, + name TEXT + ); + """ + + CURSOR.execute(sql) + CONN.commit() + + @classmethod + def drop_table(cls): + sql = "DROP TABLE IF EXISTS drinks;" + + CURSOR.execute(sql) + CONN.commit() + + def __repr__(self): + return f'' + \ No newline at end of file diff --git a/lib/models/__init__.py b/lib/models/__init__.py index d5b061e1e..e7b34e125 100644 --- a/lib/models/__init__.py +++ b/lib/models/__init__.py @@ -2,3 +2,5 @@ CONN = sqlite3.connect('company.db') CURSOR = CONN.cursor() + + diff --git a/lib/models/model_1.py b/lib/models/model_1.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/lib/models/seed.py b/lib/models/seed.py new file mode 100644 index 000000000..81519bbe5 --- /dev/null +++ b/lib/models/seed.py @@ -0,0 +1,97 @@ +import sqlite3 + +# Create a connection to an SQLite database (it will create the file if it doesn't exist) +conn = sqlite3.connect('company.db') + +# Create a cursor object to interact with the database +cursor = conn.cursor() + +# Drop the tables if they exist +cursor.execute('DROP TABLE IF EXISTS customer') +cursor.execute('DROP TABLE IF EXISTS drinks') +cursor.execute('DROP TABLE IF EXISTS drink_orders') + +# Create tables +cursor.execute(''' +CREATE TABLE IF NOT EXISTS customer ( + id INTEGER PRIMARY KEY, + name TEXT, + age INTEGER +) +''') + +cursor.execute(''' +CREATE TABLE IF NOT EXISTS drinks ( + id INTEGER PRIMARY KEY, + name TEXT +) +''') + +cursor.execute(''' +CREATE TABLE IF NOT EXISTS drink_orders ( + customer_name TEXT, + customer_id INTEGER, + drink_name TEXT, + drink_id INTEGER, + quantity INTEGER DEFAULT 1, + PRIMARY KEY (customer_name, customer_id, drink_name, drink_id), + FOREIGN KEY (customer_name) REFERENCES customer(name), + FOREIGN KEY (customer_id) REFERENCES customer(id), + FOREIGN KEY (drink_name) REFERENCES drinks(name), + FOREIGN KEY (drink_id) REFERENCES drinks(id) +) +''') + +# Function to insert data into the customer and drinks tables +def seed_db(): + # Sample user data + customers = [ + ('Jay', 23), + ('Victoria', 25), + ('Kerissa', 33), + ('Madison', 23), + ('Johnathan', 21) + ] + drinks = [ + ('Cosmo',), + ('Manhattan',), + ('Tequila Sunrise',), + ('Rum Runner',), + ('Bees Knees',) + ] + + drink_orders = [ + ('Jay', 1, 'Cosmo', 1) # Jay ordered Cosmo + +] + + # Insert sample customers into the database + cursor.executemany(''' + INSERT INTO customer (name, age) + VALUES (?, ?) + ''', customers) + + # Insert sample drinks into the database + cursor.executemany(''' + INSERT INTO drinks (name) + VALUES (?) + ''', drinks) + + cursor.executemany(''' + INSERT INTO drink_orders (customer_name, customer_id, drink_name, drink_id) + VALUES (?, ?, ?, ?) + ''', drink_orders) + + # Commit the transaction + conn.commit() + + print(f"{len(customers)} customers added to the database.") + print(f"{len(drinks)} drinks added to the database.") + print(f"{len(customers)} customers, {len(drinks)} drinks, and {len(drink_orders)} drink-orders associations were added to the database.") + +# Run the seed function +if __name__ == "__main__": + seed_db() + +# Close the connection +conn.close()