diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index a262fa5..a1dbf7f 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index aaa26e7..fa3e5c8 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/templates/base.html b/core/templates/base.html index e6c9160..33c17ee 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -169,6 +169,9 @@ + @@ -203,7 +206,7 @@ {% endfor %} {% endif %} diff --git a/core/templates/core/dashboard.html b/core/templates/core/dashboard.html index 5bed782..3f3ef5d 100644 --- a/core/templates/core/dashboard.html +++ b/core/templates/core/dashboard.html @@ -8,7 +8,11 @@

Overview of your restaurant's performance and stock.

- Manage Users + + Manage Menu + Manage Users Go to POS
@@ -114,4 +118,44 @@ -{% endblock %} \ No newline at end of file + + + +{% endblock %} diff --git a/core/templates/core/edit_menu_item.html b/core/templates/core/edit_menu_item.html new file mode 100644 index 0000000..294aba5 --- /dev/null +++ b/core/templates/core/edit_menu_item.html @@ -0,0 +1,134 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+
+

Edit Menu Item

+

Updating: {{ menu_item.name }}

+
+
+ Cancel & Go Back +
+
+ +
+
+
+
+
+ {% csrf_token %} +
+
+ + +
+
+ + +
+
+ + +
+
+ + + {% if menu_item.image_url %} +
+ Preview +
+ {% endif %} +
+
+
+ + +
+
+ +
+
+
Recipe / Ingredients
+
+ {% for current in current_ingredients %} +
+
+ + +
+
+ + +
+
+ +
+
+ {% empty %} +
+
+ + +
+
+ + +
+
+ +
+
+ {% endfor %} +
+ +
+ +
+ +
+
+
+
+
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/menu_management.html b/core/templates/core/menu_management.html new file mode 100644 index 0000000..c99220d --- /dev/null +++ b/core/templates/core/menu_management.html @@ -0,0 +1,161 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+
+

Menu Management

+

Create and edit your restaurant's menu items.

+
+
+ Back to Dashboard +
+
+ +
+ +
+
+
+

Add New Item

+
+ {% csrf_token %} +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ +
+
Recipe / Ingredients
+
+
+
+ +
+
+ +
+
+
+ + + +
+
+
+
+ + +
+
+
+

Current Menu

+
+ + + + + + + + + + + {% for item in menu_items %} + + + + + + + {% empty %} + + + + {% endfor %} + +
ItemPriceStatusActions
+
+ {% if item.image_url %} + {{ item.name }} + {% else %} +
+ +
+ {% endif %} +
+
{{ item.name }}
+
{{ item.ingredients.count }} ingredients
+
+
+
{{ item.price|floatformat:2 }} EGP + {% if item.is_active %} + Active + {% else %} + Inactive + {% endif %} + + +
+

No menu items found. Add your first one!

+
+
+
+
+
+
+
+ + +{% endblock %} diff --git a/core/templates/core/user_management.html b/core/templates/core/user_management.html index 19a0392..27275f2 100644 --- a/core/templates/core/user_management.html +++ b/core/templates/core/user_management.html @@ -97,6 +97,12 @@ at {{ u.date_joined|date:"H:i" }} + {% if u.id != request.user.id %} + + + + {% endif %} @@ -119,4 +125,4 @@ -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/core/urls.py b/core/urls.py index 98d3001..94ac2f9 100644 --- a/core/urls.py +++ b/core/urls.py @@ -10,4 +10,9 @@ urlpatterns = [ path('receipt//', views.receipt_view, name='receipt'), path('dashboard/', views.dashboard_view, name='dashboard'), path('manage-users/', views.manage_users, name='manage_users'), + path('delete-user//', views.delete_user, name='delete_user'), + path('manage-ingredients/', views.manage_ingredients, name='manage_ingredients'), + path('manage-menu/', views.manage_menu, name='manage_menu'), + path('edit-menu-item//', views.edit_menu_item, name='edit_menu_item'), + path('toggle-menu-item//', views.toggle_menu_item_status, name='toggle_menu_item_status'), ] diff --git a/core/views.py b/core/views.py index 13d1dae..c408930 100644 --- a/core/views.py +++ b/core/views.py @@ -144,3 +144,145 @@ def manage_users(request): messages.error(request, "Please fill all fields.") return render(request, 'core/user_management.html', {'users': users}) + +@manager_required +def delete_user(request, user_id): + """Manager only: Delete a user account.""" + if request.user.id == user_id: + messages.error(request, "You cannot delete your own account.") + return redirect('manage_users') + + user = get_object_or_404(User, id=user_id) + username = user.username + user.delete() + messages.success(request, f"User {username} has been deleted.") + return redirect('manage_users') + +@manager_required +def manage_ingredients(request): + """Manager only: View and add ingredients.""" + if request.method == 'POST': + name = request.POST.get('name') + stock_quantity = request.POST.get('stock_quantity', 0) + unit = request.POST.get('unit', 'grams') + + if name: + if Ingredient.objects.filter(name__iexact=name).exists(): + messages.error(request, f"Ingredient '{name}' already exists.") + else: + Ingredient.objects.create( + name=name, + stock_quantity=stock_quantity, + unit=unit + ) + messages.success(request, f"Ingredient '{name}' added successfully.") + else: + messages.error(request, "Ingredient name is required.") + return redirect('dashboard') + + return redirect('dashboard') + +@manager_required +def manage_menu(request): + """Manager only: View and create menu items.""" + menu_items = MenuItem.objects.all() + ingredients = Ingredient.objects.all() + + if request.method == 'POST': + name = request.POST.get('name') + price = request.POST.get('price') + description = request.POST.get('description', '') + image_url = request.POST.get('image_url', '') + is_active = request.POST.get('is_active') == 'on' + + # Handle ingredient IDs and quantities from the form + ingredient_ids = request.POST.getlist('ingredients') + quantities = request.POST.getlist('quantities') + + if name and price: + try: + with transaction.atomic(): + menu_item = MenuItem.objects.create( + name=name, + price=price, + description=description, + image_url=image_url, + is_active=is_active + ) + + # Add ingredients if provided + for i_id, qty in zip(ingredient_ids, quantities): + if i_id and qty and float(qty) > 0: + ingredient = get_object_or_404(Ingredient, id=i_id) + MenuItemIngredient.objects.create( + menu_item=menu_item, + ingredient=ingredient, + quantity_required=qty + ) + + messages.success(request, f"Menu item '{name}' created successfully.") + return redirect('manage_menu') + except Exception as e: + messages.error(request, f"Error creating menu item: {str(e)}") + else: + messages.error(request, "Name and price are required.") + + return render(request, 'core/menu_management.html', { + 'menu_items': menu_items, + 'ingredients': ingredients + }) + +@manager_required +def edit_menu_item(request, pk): + """Manager only: Edit an existing menu item.""" + menu_item = get_object_or_404(MenuItem, pk=pk) + ingredients = Ingredient.objects.all() + + if request.method == 'POST': + menu_item.name = request.POST.get('name') + menu_item.price = request.POST.get('price') + menu_item.description = request.POST.get('description', '') + menu_item.image_url = request.POST.get('image_url', '') + menu_item.is_active = request.POST.get('is_active') == 'on' + + ingredient_ids = request.POST.getlist('ingredients') + quantities = request.POST.getlist('quantities') + + if menu_item.name and menu_item.price: + try: + with transaction.atomic(): + menu_item.save() + + # Update ingredients: Clear existing and re-add + menu_item.ingredients.all().delete() + for i_id, qty in zip(ingredient_ids, quantities): + if i_id and qty and float(qty) > 0: + ingredient = get_object_or_404(Ingredient, id=i_id) + MenuItemIngredient.objects.create( + menu_item=menu_item, + ingredient=ingredient, + quantity_required=qty + ) + + messages.success(request, f"Menu item '{menu_item.name}' updated successfully.") + return redirect('manage_menu') + except Exception as e: + messages.error(request, f"Error updating menu item: {str(e)}") + else: + messages.error(request, "Name and price are required.") + + return render(request, 'core/edit_menu_item.html', { + 'menu_item': menu_item, + 'ingredients': ingredients, + 'current_ingredients': menu_item.ingredients.all() + }) + +@manager_required +def toggle_menu_item_status(request, pk): + """Manager only: Toggle menu item active/inactive status.""" + menu_item = get_object_or_404(MenuItem, pk=pk) + menu_item.is_active = not menu_item.is_active + menu_item.save() + status = "activated" if menu_item.is_active else "deactivated" + messages.success(request, f"Menu item '{menu_item.name}' {status}.") + return redirect('manage_menu')