From eaeab96245ac8da7da641e57b877db510ef70699 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 9 Feb 2026 16:33:02 +0000 Subject: [PATCH] Ahmed version 1 --- core/__pycache__/admin.cpython-311.pyc | Bin 212 -> 2635 bytes core/__pycache__/models.cpython-311.pyc | Bin 209 -> 5957 bytes core/__pycache__/urls.cpython-311.pyc | Bin 347 -> 1019 bytes core/__pycache__/views.cpython-311.pyc | Bin 1364 -> 9631 bytes core/admin.py | 33 ++- core/migrations/0001_initial.py | 65 ++++++ core/migrations/0002_userprofile.py | 24 +++ .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 3711 bytes .../0002_userprofile.cpython-311.pyc | Bin 0 -> 1505 bytes core/models.py | 64 +++++- core/templates/base.html | 112 ++++++++-- core/templates/core/dashboard.html | 79 +++++++ core/templates/core/index.html | 173 +++------------ core/templates/core/login.html | 32 +++ core/templates/core/pos.html | 200 ++++++++++++++++++ core/templates/core/receipt.html | 57 +++++ core/templates/core/user_management.html | 86 ++++++++ core/urls.py | 12 +- core/views.py | 161 ++++++++++++-- 19 files changed, 913 insertions(+), 185 deletions(-) create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/0002_userprofile.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 core/migrations/__pycache__/0002_userprofile.cpython-311.pyc create mode 100644 core/templates/core/dashboard.html create mode 100644 core/templates/core/login.html create mode 100644 core/templates/core/pos.html create mode 100644 core/templates/core/receipt.html create mode 100644 core/templates/core/user_management.html diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index a5ed392d6714413db63120e4233d2e96cbadb5de..8c351d7aeb9f6b189c1254f50d45e1547f52ca42 100644 GIT binary patch literal 2635 zcmb7FId9xX6rSO+%e`0E%Ce-DlNgb=us1f4B0vzt1_VP$BnNP;f++}!9LuzLC_^%_ zx-DF#Qs?{v1&04eY6;n5F_nN+?j*>Siy-gKUebyP6mt3PaOPd#dvAt+R4PRR*FUA- zyj_iuzwu>wZ(5iFLjZLubqltHKRA57{KesdXqt6-ycZNF1){V8cpy~otG zsL*XU@WS_4lU7a?*TWsoT#to`Fg942t|u%I)5Fn)Rs9Kf85aflC#6cyV#a^q(R0sd z&ag1}KdkrpO?Y`j7%{0!OvR<9>MEw@s;2I05R)$I7fd|FxLS(PQZOqt9{H?Ac@<1R z)K#3cEX2?b*d~N-SQZW~OB5|Dh}_i2aoMtdPHlg%Que(#v0N|S^X+|6l5Y@h0uCxM zv$^xadhRjbjo*@UjQr!>_KPTB?Q}a0leEoVF(*wT-u^Y>yYZgwu(lI%)|M%}x3|x+ zA0@yRBJnanXLO&;eAfBCH@(>Tt~a~d*}$9659PD-)qv%3zL*NRqL3>Ea;1tJSBtV9 z`d-L5I){w#I$EDXm`2D02puxRe4(>f3AZ^q=m&8FM_3;TxEEub8i(I2H#=*+a;39| zcV7wRuM_#W(h#{OYU4KQ7g-e=7D!a%Byx7KU}54V`%wDOOWsnx0)94I`Xr$lnC5c` z6FizYhk)HO!Q*7+ODMza^2G|EXf}@}SQ%FUc`$89*1*iUs$^3c)?vU!Ml19^?m0{p zyx6jx#QTNuPr=k?E1yXM6DjhZEMJ^S={87k1SB2b0vMO(Wad6ls;wSX?{pqdP(zh$ zYL_?TxVc8eYNM?^=qm+mLE{wyI2SAr4+djYs;cB`*@+e5xsX8=zXE&_0h20foY`&^ z`ul?&H(A3LN+K-4GqII=<+(vG_8Jd6Pw?(HB+6&Ay+$F6lJBr1%aVr`rolFx4y7bY zY~Sh^wdg?X33GvMOXFW)p!X3T0EnuSLKg>cI)zcf;*3Pdww3f&QR^4mOP5X+mEJieSK%P-&aa-~!Uu#i zl_<+2`JzIrr{pU9o_1FroZ-TU@v1?Tx^!7Qri)#=c&aG0iQ1EJz`BjkQM-xSO>_w% z4&+BxjAOdcr3)B17`O@tYu(w~7&uq~Kr1&#@>1g&gID_ayJn9o#`oA6&T8AQbZ delta 148 zcmX>ta)mKvIWI340}xFAk)LS~q#uJgFu(+5d=>&SrZc24q%h_%Kp_C%cpupS diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index e061640edbdcec3e5c1744466c916e7acdd2763b..373d21b313b873b8a9001da849ce66b779c7d522 100644 GIT binary patch literal 5957 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 a96&KfATE|=n7mI^lKTRK3=kEu0fhi7Fd#Vq diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 5a69659f6c6e0ae848e54157af197c543a09315f..a262fa5489bcd8db96258a6979516a70bcd50acd 100644 GIT binary patch literal 1019 zcmZvazi-n(6vxl;%kQM2KWR%T0}4`F!WF0Pq3vMs#}@5pi133ac8HNigLE^?tS0q?%uuU@8xm<$@Z!6p?5ch z&>v-7x6){G+0+pFf(Rm7ADLQ9(-27!y`M7mmad@`q8b6J@5A*%lKz$XrX%!IesPPK ztYp&H3dxOS@{-9UOkpfjluR~ZN@JO_WO4~JF_x)FCZ903#xj$Vi87=(GBuW&mP|3( zXXbyVn`@QG>#R%VPHF0=(6`GjX@807&TnFW-~$=7Nyv1N2Y&=(GKkmT)gGDY%|i@mS^r# z*1#e=a{2{gID5Oc!3Y-lWbT(u!!o*b&2uP|CzfKf9huKp%A!d24XbOfd#vv;RdA;2 z$5f%2s*)%~H)yMCieemnY~*C{(Tu4-O_WA~#LkH%f*7eNq$m%OxpOJAoFC{?O6aPF zRo<|->shXc>08?IT$|woo4s}hMu*~#&7@mKw?24xmD@6H;`M2REy~5J1kPXCUFe#o zouQ@R=6i;wgPZR~2Bq_dPmZRJUVdyHzY3rlLX|`H402MPAJ+Nw{ga0QY=p4EVI!6o zhEMrS_2gLq^$_YD>ajdGoc+A~l?G4?p~j&WsX>0}nDXVvr|$#U4q=Me#MkU1c^yu{p8KTXzK+$mX!dFlCjrA0Z# zMIgg&v6f|~mKPVXPF~Fv5W@!)0hv(j1tdN&Gcq#XV34_hiXJeCUqD44*cezj8(cbs fIznc!U0{*F$RdA*Mg9Xb6F*Y}HwYH-0F46xCsR6( diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 2a36fd69370b38a98d8b01bf8eb9817c42f16ed6..aaa26e7cbf66a866d638d63ec5fc8ef376578f25 100644 GIT binary patch literal 9631 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 Z7_8sIY@=;W>~Z)MVY#)8vs$Q%|1UcBW)1)V literal 1364 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 literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/0002_userprofile.cpython-311.pyc b/core/migrations/__pycache__/0002_userprofile.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abf00b6dff12e553396f92a6c7cef82635f9cedd GIT binary patch literal 1505 zcmZuxy>Ht_6h9s*e(1xtT(^Qdqzw=tQHofO3ltuTqN;2sY2#R_?V(x-N_V2DP^5CC z?6^bWp+nIrTl*KdE$lxaL;rw|48Xy-sX(V}H0&u;-;tu4wz=cId-uNXckkZumrA9G zppoK_jwvJbmssSjFl8>=!2E;=B9eLMFS)sL&~l)Q&14jP4<#e2++h z7KU0L=ma94!pK@jBhoIatFOfJQC;GCK*P}S?4XW$apc&{3LW1IxH|F)b%Wm2FP%!$ z#pR+TFwqoG2NMY+Di4+16n0m0{sb&fVPwt59WAxha|yvj28l6DGa;lzfnFf$nRWsZ zPiIm4nCPixjsg*b6m3jOq3B})SS~N^2b8s$-*;Tfu|xK@ zIDW8ES9sZ)gudBh)Cwu#r7?3x7CSPZ&?9bu3-~(ULa+nMx_&@S&l*v#FyE!Hkv6hC z%chKL+ZiKdJu4VELe|O{wghNji8R+`&<=d3M+2@A+P5Zd2zPHiGhOQ0;eaa>*pX}F z3?`TxzGp%;&=3$X>I#S%0v!6{peY))?@*TnkLrtDH&eA~@}g-%Ax&HgeAzUgPApd# znfkscz?&Uo~X#Uey-pAp&08of7Rn#pTE?bvEEDy@{)S|FexMB1EITiUcL5b z_1&m;`}sj!yZu7><3`jmBacP3;AJg{YeBRSo>yzpa{cG`;^lhu@q_3qD_ZMD?j%8| zg*P!w?{DFYlwPG2B-ML3^|~Xx?z~WcH{$jC@%rO<{hMg;G&=YWEDxof)VZBHx3O?; z3rY1cPBdj{E-7e6@d5$45+sq0MfLbg(b?Vn>~) - - - {% block title %}Knowledge Base{% endblock %} - {% if project_description %} - - - - {% endif %} - {% if project_image_url %} - - - {% endif %} - {% load static %} - - {% block head %}{% endblock %} + + + Searing Sandwiches | POS & Stock + + + + {% block extra_css %}{% endblock %} - - {% block content %}{% endblock %} - + +
+ {% block content %}{% endblock %} +
+ + + {% block extra_js %}{% endblock %} + diff --git a/core/templates/core/dashboard.html b/core/templates/core/dashboard.html new file mode 100644 index 0000000..baee4b5 --- /dev/null +++ b/core/templates/core/dashboard.html @@ -0,0 +1,79 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+

Manager Dashboard

+ +
+ +
+
+
+
Total Sales (All Time)
+

${{ total_sales|stringformat:".2f" }}

+
+
+
+
+
Ingredient Stock Levels
+
+ {% for ingredient in ingredients %} +
+
+
{{ ingredient.name }}
+
{{ ingredient.stock_quantity|floatformat:0 }} {{ ingredient.unit }}
+
+
+ {% endfor %} +
+
+
+
+ +
+
+

Recent Orders

+
+ + + + + + + + + + + + + {% for order in orders %} + + + + + + + + + {% empty %} + + + + {% endfor %} + +
Order #TimeItemsNotesTotal
{{ order.order_number }}{{ order.created_at|date:"H:i" }} {{ order.created_at|date:"d M" }} + {% for item in order.items.all %} + {{ item.quantity }}x {{ item.menu_item.name }} + {% endfor %} + {{ order.customer_notes|truncatechars:30 }}${{ order.total_price }} + Receipt +
No orders found yet.
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/index.html b/core/templates/core/index.html index faec813..987c50e 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,145 +1,34 @@ -{% extends "base.html" %} - -{% block title %}{{ project_name }}{% endblock %} - -{% block head %} - - - - -{% endblock %} +{% extends 'base.html' %} +{% block title %}Welcome | Liver & Sausage POS{% endblock %} {% block content %} -
-
-

Analyzing your requirements and generating your app…

-
- Loading… +
+
+

+ Professional Cashier System +

+

+ Streamlined order management, automated stock tracking, and real-time reporting for your restaurant. +

+ +
+
+
+
+

Cashier POS

+

Create orders, customize sandwiches, and print receipts instantly.

+ Open POS +
+
+
+
+
+

Manager Dashboard

+

Track liver, sausage, and fries stock. View sales reports and manage prices.

+ View Reports +
+
+
-

AppWizzy AI is collecting your requirements and applying the first changes.

-

This page will refresh automatically as the plan is implemented.

-

- Runtime: Django {{ django_version }} · Python {{ python_version }} - — UTC {{ current_time|date:"Y-m-d H:i:s" }} -

-
-
-
- Page updated: {{ current_time|date:"Y-m-d H:i:s" }} (UTC) -
-{% endblock %} \ No newline at end of file + +{% endblock %} diff --git a/core/templates/core/login.html b/core/templates/core/login.html new file mode 100644 index 0000000..2f715b5 --- /dev/null +++ b/core/templates/core/login.html @@ -0,0 +1,32 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+
+
+

Login

+
+ {% csrf_token %} +
+ + +
+
+ + +
+
+ +
+
+ {% if form.errors %} +
+ Invalid username or password. +
+ {% endif %} +
+
+
+
+{% endblock %} diff --git a/core/templates/core/pos.html b/core/templates/core/pos.html new file mode 100644 index 0000000..70f9ed2 --- /dev/null +++ b/core/templates/core/pos.html @@ -0,0 +1,200 @@ +{% extends 'base.html' %} +{% block title %}POS | Cashier Interface{% endblock %} + +{% block extra_css %} +.menu-item-card { + cursor: pointer; + transition: all 0.2s; +} +.menu-item-card:hover { + border-color: var(--orange); + background-color: #2a2a2d; +} +.cart-sticky { + position: sticky; + top: 90px; + max-height: calc(100vh - 120px); + overflow-y: auto; +} +.cart-item { + border-bottom: 1px solid var(--slate); + padding: 10px 0; +} +.cart-item:last-child { + border-bottom: none; +} +{% endblock %} + +{% block content %} +
+ +
+

Menu

+
+ {% for item in menu_items %} +
+ +
+ {% endfor %} +
+
+ + +
+
+
+

Current Order

+
+
+
+

Cart is empty

+
+ +
+ + +
+ +
+ Subtotal + 0.00 EGP +
+
+

Total

+

0.00 EGP

+
+ + +
+
+
+
+ + + +{% endblock %} + +{% block extra_js %} + +{% endblock %} diff --git a/core/templates/core/receipt.html b/core/templates/core/receipt.html new file mode 100644 index 0000000..96e32fd --- /dev/null +++ b/core/templates/core/receipt.html @@ -0,0 +1,57 @@ + + + + + Receipt - {{ order.order_number }} + + + +
+ + +
+ +
+

LIVER & SAUSAGE

+

RESTAURANT POS

+

Order #: {{ order.order_number }}

+

{{ order.created_at|date:"Y-m-d H:i" }}

+
+ +
+ {% for item in order.items.all %} +
+ {{ item.quantity }} x {{ item.menu_item.name }} + {{ item.price_at_order }} +
+ {% endfor %} +
+ + + +
+

THANK YOU!

+
+ + diff --git a/core/templates/core/user_management.html b/core/templates/core/user_management.html new file mode 100644 index 0000000..824a859 --- /dev/null +++ b/core/templates/core/user_management.html @@ -0,0 +1,86 @@ +{% extends 'base.html' %} + +{% block content %} +
+
+

User Management

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

Create New Account

+
+ {% csrf_token %} +
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ {% if messages %} + {% for message in messages %} +
+ {{ message }} +
+ {% endfor %} + {% endif %} +
+
+
+ + +
+
+
+

Existing Accounts

+
+ + + + + + + + + + {% for user in users %} + + + + + + {% empty %} + + + + {% endfor %} + +
UsernameRoleDate Joined
{{ user.username }} + + {{ user.profile.role|title }} + + {{ user.date_joined|date:"M d, Y" }}
No users found.
+
+
+
+
+
+
+{% endblock %} diff --git a/core/urls.py b/core/urls.py index 6299e3d..98d3001 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,7 +1,13 @@ from django.urls import path - -from .views import home +from . import views urlpatterns = [ - path("", home, name="home"), + path('', views.home, name='home'), + path('login/', views.login_view, name='login'), + path('logout/', views.logout_view, name='logout'), + path('pos/', views.pos_view, name='pos'), + path('api/create-order/', views.create_order, name='create_order'), + path('receipt//', views.receipt_view, name='receipt'), + path('dashboard/', views.dashboard_view, name='dashboard'), + path('manage-users/', views.manage_users, name='manage_users'), ] diff --git a/core/views.py b/core/views.py index c9aed12..13d1dae 100644 --- a/core/views.py +++ b/core/views.py @@ -1,25 +1,146 @@ -import os -import platform - -from django import get_version as django_version -from django.shortcuts import render +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): - """Render the landing screen with loader and environment details.""" - host_name = request.get_host().lower() - agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic" - now = timezone.now() + """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") - context = { - "project_name": "New Style", - "agent_brand": agent_brand, - "django_version": django_version(), - "python_version": platform.python_version(), - "current_time": now, - "host_name": host_name, - "project_description": os.getenv("PROJECT_DESCRIPTION", ""), - "project_image_url": os.getenv("PROJECT_IMAGE_URL", ""), - } - return render(request, "core/index.html", context) +@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})