diff --git a/.idea/dataSources.local.xml b/.idea/dataSources.local.xml new file mode 100644 index 0000000..2c7a435 --- /dev/null +++ b/.idea/dataSources.local.xml @@ -0,0 +1,10 @@ + + + + + + false + true + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..40072a6 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,16 @@ + + + + + sqlite.xerial + true + true + $PROJECT_DIR$/pizza/settings.py + org.sqlite.JDBC + jdbc:sqlite:C:\Harvard\CSCI E-33A\project3\db.sqlite3 + + + + + + \ No newline at end of file diff --git a/.idea/libraries/R_User_Library.xml b/.idea/libraries/R_User_Library.xml new file mode 100644 index 0000000..71f5ff7 --- /dev/null +++ b/.idea/libraries/R_User_Library.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..65531ca --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7fe81e3 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/project3.iml b/.idea/project3.iml new file mode 100644 index 0000000..4908703 --- /dev/null +++ b/.idea/project3.iml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..91b2230 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,665 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ topping }} + + {% endfor %} + + {% else %} +

No Toppings to Select

+ {% endif %} +
+
+ +
+
+ + + + + {% endif %} + + +{% endblock %} \ No newline at end of file diff --git a/orders/templates/index.html b/orders/templates/index.html new file mode 100644 index 0000000..29b0f78 --- /dev/null +++ b/orders/templates/index.html @@ -0,0 +1,125 @@ +{% extends 'visitor.html' %} +{% block menu_active %}active{% endblock %} + +{% block body %} +
+
+
+
+
+ {% for type in types %} +

{{ type.description }}

+ + + + {% for size in sizes %} + + {% endfor %} + + + {% for option in options %} + + + {% for pizza in pizzas %} + {% if pizza.option.description == option.description and pizza.type.description == type.description%} + + {% endif %} + {% endfor %} + + {% endfor %} + +
+ {{ size.description}} +
+ {{ option.description}} + {{pizza.price}}
+ {% endfor %} +
+
+
+
+
+
+

Toppings

+
    + {% for topping in toppings %} +
  • {{ topping.description }}
  • + {% endfor %} +
+
+
+
+
+
+
+
+
+

Pasta

+ + + {% for pasta in pastas %} + + + + + {% endfor %} + +
{{pasta.description}}{{pasta.price}}
+
+
+
+
+
+
+
+
+

Salads

+ + + {% for salad in salads %} + + + + + {% endfor %} + +
{{salad.description}}{{salad.price}}
+
+
+
+
+
+
+
+
+

Dinner Plates

+ + + + {% for size in sizes %} + + {% endfor %} + + + {% for plate in plates %} + + + {% for item in items %} + {% if item.type.description == plate.description %} + + {% endif %} + {% endfor %} + + {% endfor %} + +
+ {{ size.description}} +
+ {{ plate.description}} + {{item.price}}
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/orders/templates/login.html b/orders/templates/login.html new file mode 100644 index 0000000..50639ca --- /dev/null +++ b/orders/templates/login.html @@ -0,0 +1,48 @@ +{% extends 'visitor.html' %} +{% block title %}Log In{% endblock %} +{% block login_active %}active{% endblock %} + +{% block body %} +
+
+
+
+
+

Log In

+ {% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %} +
+ {% csrf_token %} + + {% for field in form %} + + + + + + + {% endfor %} +
+ + + {{ field }} +
+
+
+ +
+
+
+
+
+
+
+ +
+ +{% endblock %} \ No newline at end of file diff --git a/orders/templates/order.html b/orders/templates/order.html new file mode 100644 index 0000000..30d75e9 --- /dev/null +++ b/orders/templates/order.html @@ -0,0 +1,102 @@ +{% extends 'visitor.html' %} +{% block title %}Cart{% endblock %} +{% block cart_active %}active{% endblock %} + +{% block body %} +
+ {% if order %} +
+
+
+
+
+ {% csrf_token %} +

Please Review Your Order

+
    +
  • Order ID: {{ order.id }}
  • +
  • Total: {{ order.total }}
  • +
+
+
+ +
+
+
+
+
+
+ {% endif %} +
+
+
+ {% if error %} +

{{ error }}

+ {% endif %} + {% if order %} + {% for pizza_assembly in order.pizzas_assemblies.all %} +
+
+
+ Card image +

{{ pizza_assembly.pizza.type.description }}

+

Size: {{ pizza_assembly.pizza.size.description }}

+

Price: {{ pizza_assembly.pizza.price }}

+ {% for topping in pizza_assembly.toppings.all %} +

{{ topping.description}}

+ {% endfor %} +
+
+
+ {% endfor %} + {% for salad in order.salads.all %} +
+
+
+ Card image +

{{ salad.description }}

+

Price: {{ salad.price }}

+
+
+
+ {% endfor %} + {% for pasta in order.pastas.all %} +
+
+
+ Card image +

{{ pasta.description }}

+

Price: {{ pasta.price }}

+
+
+
+ {% endfor %} + {% for plate in order.dinner_plates.all %} +
+
+
+ Card image +

{{ plate.type.description }}

+

Price: {{ plate.size.price }}

+

Price: {{ plate.price }}

+
+
+
+ {% endfor %} +
+ {% csrf_token %} +
+
+ +
+
+
+ {% endif %} +
+ +
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/orders/templates/order_list.html b/orders/templates/order_list.html new file mode 100644 index 0000000..7387c40 --- /dev/null +++ b/orders/templates/order_list.html @@ -0,0 +1,82 @@ +{% extends 'visitor.html' %} +{% block title %}Orders{% endblock %} +{% block order_active %}active{% endblock %} + +{% block body %} +
+
+
+
+ {% if error %} +

{{ error }}

+ {% endif %} + {% if orders %} + + + + + + + + + + + {% for order in orders%} + + + + + {% if order.is_complete == True %} + + {% else %} + + {% endif %} + + {% endfor %} + +
Order NumberOrder TotalOrder ItemsOrder Status
{{ order.id }}${{ order.total }} +
    + {% for pizza_assembly in order.pizzas_assemblies.all %} +
  1. + {{ pizza_assembly.pizza.type.description}}, + {{ pizza_assembly.pizza.size.description}}, + {{ pizza_assembly.pizza.option.description}},
    + {% for topping in pizza_assembly.toppings.all %} +
      +
    • {{ topping.description}}
    • +
    + {% endfor %} + {% if pizza_assembly.toppings.all|length == 0 %} +
      +
    • No Toppings
    • +
    + {% endif %} +
  2. + {% endfor %} + {% for salad in order.salads.all %} +
  3. + {{ salad.description}} +
  4. + {% endfor %} + {% for pasta in order.pastas.all %} +
  5. + {{ pasta.description}} +
  6. + {% endfor %} + {% for plate in order.dinner_plates.all %} +
  7. + {{ plate.type.description}}, + {{ plate.size.description}} +
  8. + {% endfor %} +
+
DeliveredIn Progress
+ {% endif %} +
+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/orders/templates/register.html b/orders/templates/register.html new file mode 100644 index 0000000..28ebd58 --- /dev/null +++ b/orders/templates/register.html @@ -0,0 +1,46 @@ +{% extends 'visitor.html' %} +{% block title %}Register{% endblock %} +{% block register_active %}active{% endblock %} + +{% block body %} +
+
+
+
+
+

Register Account

+ {% if messages %} +
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+ {% endif %} +
+ {% csrf_token %} + + {% for field in form %} + + + + + + + {% endfor %} +
+ + + {{ field }} +
+
+
+ +
+
+
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/orders/templates/visitor.html b/orders/templates/visitor.html new file mode 100644 index 0000000..41eb675 --- /dev/null +++ b/orders/templates/visitor.html @@ -0,0 +1,51 @@ + + + + + Pizza App + + + + + + + +{% block body %} +{% endblock %} + + \ No newline at end of file diff --git a/orders/urls.py b/orders/urls.py index 2d9cdc0..2719386 100644 --- a/orders/urls.py +++ b/orders/urls.py @@ -2,6 +2,17 @@ from . import views +app_name = 'orders' + urlpatterns = [ - path("", views.index, name="index") -] + path("", views.index, name="index"), + path("register", views.register, name='register'), + path("enter", views.enter, name='enter'), + path("exit", views.exit, name='exit'), + path("pizza//", views.process_order, name='process_order'), + path("cart/", views.process_cart, name='process_cart'), + path("display_orders", views.display_orders, name='display_orders'), + path("clear_cart", views.clear_cart, name='clear_cart') + + +] \ No newline at end of file diff --git a/orders/views.py b/orders/views.py index c2bb9aa..98bee52 100644 --- a/orders/views.py +++ b/orders/views.py @@ -1,6 +1,242 @@ -from django.http import HttpResponse +from django.contrib.auth import authenticate, login, logout +from .forms import RegisterForm, LoginForm, ToppingsForm +from .models import Topping, Pizza_Assembly, Pizza_Type, Pizza, Order, Size, Option, Salad, Pasta, Item, Dinner_Plate_Type from django.shortcuts import render +from django.shortcuts import redirect +from decimal import Decimal +from django.contrib import messages -# Create your views here. def index(request): - return HttpResponse("Project 3: TODO") + + + # Get all collections needed to display menu + pizzas = Pizza.objects.all() + toppings = Topping.objects.all() + sizes = Size.objects.all() + types = Pizza_Type.objects.all() + options = Option.objects.all() + salads = Salad.objects.all() + pastas = Pasta.objects.all() + items = Item.objects.all() + plates = Dinner_Plate_Type.objects.all() + + # Pass all collections to the index page + return render(request, 'index.html', {'pizzas': pizzas, 'toppings': toppings, 'sizes': sizes, 'types': types, + 'options': options, 'salads': salads, 'pastas': pastas, 'items': items, + 'plates': plates }) + +def exit(request): + + # Logout current user and redirect to the menu + logout(request) + return redirect("/") + +def enter(request): + + # Create form from the request + form = LoginForm(request.POST or None) + + # If form is valid extract data + if form.is_valid(): + username = form.cleaned_data['username'] + password = form.cleaned_data['password'] + + # Try to authenticate the user + user = authenticate(username=username, password=password) + + # If user exists but not in the active state return an error + # If user does not exist return and error + # Otherwise login the user + if user is not None: + if user.is_active: + login(request, user) + return redirect("/") + else: + messages.error(request, "User is not active !!!") + else: + messages.error(request, "Incorrect user login !!!") + + return render(request, 'login.html', {'form': form}) + + +def register(request): + + # Create form from the request + form = RegisterForm(request.POST or None) + + # If form is valid extract data and save the user in the database + if form.is_valid(): + user = form.save(commit=False) + username = form.cleaned_data['username'] + password = form.cleaned_data['password'] + user.set_password(password) + user.save() + user = authenticate(username=username, password=password) + + # If user is not found return all the error encountered during registration + if user is not None: + login(request, user) + return redirect("/") + else: + messages.error(request, form.errors) + else: + messages.error(request, form.errors) + + return render(request, 'register.html', {'form': form}) + +def process_order(request, id, item): + + # If user is not authenticated redirect them to the login page + if not request.user.is_authenticated: + return render(request, 'login.html') + else: + if request.method == "POST": + + # Retrieve and order from the data base that has not been completed. It is impossible to have more than + # one uncompleted order for the same user + order = Order.objects.filter(customer=request.user.id, is_paid=False).first() + + # If order does not exist it must be new order + if order is None: + order = Order() + order.customer = request.user + order.is_complete = False + order.is_paid = False + order.save() + + # Check to see what is being ordered + if item == "pizza": + + pizza = Pizza.objects.get(pk=id) + toppings = Topping.objects.filter(description__in=request.POST.getlist('toppings')) + + if pizza.option.number_of_topings != len(request.POST.getlist('toppings')): + form = ToppingsForm() + return render(request, 'cart.html', {'error': 'Number of selected topics does not match choice of Pizza', + 'pizza': pizza, 'form': form }) + + # Looks like user is ordering pizza + pizza_assembly = Pizza_Assembly() + pizza_assembly.pizza = pizza + pizza_assembly.save() + pizza_assembly.toppings.add(*list(toppings)) + pizza_assembly.save() + + + order.pizzas_assemblies.add(pizza_assembly) + order.total = Decimal(order.total) + pizza.price + order.save() + + elif item == "salad": + + # Looks like user is ordering salad + salad = Salad.objects.get(pk=id) + order.salads.add(salad) + order.total = Decimal(order.total) + salad.price + order.save() + + elif item == "pasta": + + # Looks like user is ordering pasta + pasta = Pasta.objects.get(pk=id) + order.pastas.add(pasta) + order.total = Decimal(order.total) + pasta.price + order.save() + + elif item == "plate": + + # Looks like user is ordering dinner plate + plate = Item.objects.get(pk=id) + order.dinner_plates.add(plate) + order.total = Decimal(order.total) + plate.price + order.save() + + return render(request, 'order.html', {'order': order}) + + elif request.method == "GET": + + # if user is ordering pizza display toppings sellection form + if item == "pizza": + form = ToppingsForm() + pizza = Pizza.objects.get(pk=id) + + return render(request, 'cart.html', {'pizza': pizza, 'form': form}) + + elif item == "salad": + salad = Salad.objects.get(pk=id) + + return render(request, 'cart.html', {'salad': salad }) + + elif item == "pasta": + pasta = Pasta.objects.get(pk=id) + + return render(request, 'cart.html', {'pasta': pasta }) + + elif item == "plate": + plate = Item.objects.get(pk=id) + + return render(request, 'cart.html', {'plate': plate }) + + else: + return redirect("/") + +def process_cart(request, order_id): + + # If user is not authenticated redirect them to the login page + if not request.user.is_authenticated: + return render(request, 'login.html') + else: + if request.method == "POST": + + # Looks like user is trying to pay for the order + order = Order.objects.get(pk=order_id) + order.is_paid = True + order.save() + + return redirect("/") + + elif request.method == "GET": + + # Looks like user is trying to see what's in the cart + if order_id is not '0': + # If order id is passed fetch it, otherwise get first order for the user that has not been paid + order = Order.objects.get(pk=order_id) + else: + order = Order.objects.filter(customer=request.user.id, is_paid=False).first() + + if order is None: + return render(request, 'order.html', {'error': 'There are currently no active orders in the cart !!!'}) + else: + return render(request, 'order.html', {'order': order}) + +def clear_cart(request): + + # If user is not authenticated redirect them to the login page + if not request.user.is_authenticated: + return render(request, 'login.html') + else: + if request.method == "POST": + + # Looks like user is trying to start over. Let's delete first incomplete order + order = Order.objects.filter(customer=request.user.id, is_paid=False).first() + if order is not None: + order.delete() + + return redirect("/") + + +def display_orders(request): + + # If user is not authenticated redirect them to the login page + if not request.user.is_authenticated: + return render(request, 'login.html') + else: + + # Fetch all the paid orders for a given user + orders = Order.objects.filter(customer=request.user.id, is_paid=True).all() + + if len(orders) == 0: + return render(request, 'order_list.html', + {'error': 'You have no orders !!!'}) + else: + return render(request, 'order_list.html', {'orders': orders}) diff --git a/pizza/__pycache__/__init__.cpython-36.pyc b/pizza/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..cbc2c5f Binary files /dev/null and b/pizza/__pycache__/__init__.cpython-36.pyc differ diff --git a/pizza/__pycache__/settings.cpython-36.pyc b/pizza/__pycache__/settings.cpython-36.pyc new file mode 100644 index 0000000..9594f14 Binary files /dev/null and b/pizza/__pycache__/settings.cpython-36.pyc differ diff --git a/pizza/__pycache__/urls.cpython-36.pyc b/pizza/__pycache__/urls.cpython-36.pyc new file mode 100644 index 0000000..6972e66 Binary files /dev/null and b/pizza/__pycache__/urls.cpython-36.pyc differ diff --git a/pizza/__pycache__/wsgi.cpython-36.pyc b/pizza/__pycache__/wsgi.cpython-36.pyc new file mode 100644 index 0000000..b0ac9fc Binary files /dev/null and b/pizza/__pycache__/wsgi.cpython-36.pyc differ