from django.shortcuts import render, get_object_or_404, redirect from django.http import JsonResponse from django.db import transaction from django.db.models import Sum, F from django.utils import timezone from django.contrib import messages from django.contrib.auth import login, logout, authenticate from django.contrib.auth.forms import AuthenticationForm, UserCreationForm from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.models import User from .models import Ingredient, MenuItem, MenuItemIngredient, Order, OrderItem, UserProfile import json def is_manager(user): return user.is_authenticated and hasattr(user, 'profile') and user.profile.role == 'manager' def is_cashier(user): return user.is_authenticated and hasattr(user, 'profile') and user.profile.role == 'cashier' def manager_required(view_func): return user_passes_test(is_manager, login_url='login')(view_func) def cashier_or_manager_required(view_func): return user_passes_test(lambda u: is_manager(u) or is_cashier(u), login_url='login')(view_func) def login_view(request): if request.method == 'POST': form = AuthenticationForm(request, data=request.POST) if form.is_valid(): user = form.get_user() login(request, user) if is_manager(user): return redirect('dashboard') return redirect('pos') else: form = AuthenticationForm() return render(request, 'core/login.html', {'form': form}) def logout_view(request): logout(request) return redirect('login') def home(request): """Redirect home to login or dashboard/pos based on role.""" if request.user.is_authenticated: if is_manager(request.user): return redirect('dashboard') return redirect('pos') return render(request, "core/index.html") @cashier_or_manager_required def pos_view(request): """Cashier POS interface.""" menu_items = MenuItem.objects.filter(is_active=True) return render(request, "core/pos.html", {"menu_items": menu_items}) @cashier_or_manager_required def create_order(request): """Handle order creation and stock deduction.""" if request.method == "POST": try: data = json.loads(request.body) cart = data.get("cart", []) notes = data.get("notes", "") if not cart: return JsonResponse({"success": False, "error": "Cart is empty"}, status=400) with transaction.atomic(): order = Order.objects.create(customer_notes=notes) total_price = 0 for item in cart: menu_item = get_object_or_404(MenuItem, id=item["id"]) quantity = int(item["quantity"]) # Deduct stock for recipe_item in menu_item.ingredients.all(): required_qty = recipe_item.quantity_required * quantity ingredient = recipe_item.ingredient if ingredient.stock_quantity < required_qty: raise Exception(f"Insufficient stock for {ingredient.name}") ingredient.stock_quantity = F('stock_quantity') - required_qty ingredient.save() # Create OrderItem OrderItem.objects.create( order=order, menu_item=menu_item, quantity=quantity, price_at_order=menu_item.price ) total_price += menu_item.price * quantity order.total_price = total_price order.save() return JsonResponse({"success": True, "order_number": order.order_number}) except Exception as e: return JsonResponse({"success": False, "error": str(e)}, status=400) return JsonResponse({"success": False, "error": "Invalid request"}, status=405) @cashier_or_manager_required def receipt_view(request, order_number): """Printable receipt view.""" order = get_object_or_404(Order, order_number=order_number) return render(request, "core/receipt.html", {"order": order}) @manager_required def dashboard_view(request): """Manager dashboard for stock and reports.""" ingredients = Ingredient.objects.all() # Summary of last 30 orders orders = Order.objects.prefetch_related('items__menu_item').order_by('-created_at')[:50] total_sales = Order.objects.aggregate(Sum('total_price'))['total_price__sum'] or 0 return render(request, "core/dashboard.html", { "ingredients": ingredients, "orders": orders, "total_sales": total_sales, }) @manager_required def manage_users(request): """Manager only: Create and view accounts.""" users = User.objects.all().select_related('profile') if request.method == 'POST': username = request.POST.get('username') password = request.POST.get('password') role = request.POST.get('role') if username and password and role: if User.objects.filter(username=username).exists(): messages.error(request, f"User {username} already exists.") else: user = User.objects.create_user(username=username, password=password) profile, created = UserProfile.objects.get_or_create(user=user) profile.role = role profile.save() messages.success(request, f"User {username} created as {role}.") return redirect('manage_users') else: messages.error(request, "Please fill all fields.") return render(request, 'core/user_management.html', {'users': users})