From d6f4ebfd4e3d7effb72a87f556f077922af5dcd8 Mon Sep 17 00:00:00 2001 From: ismail Date: Thu, 3 Jul 2025 15:57:06 +0300 Subject: [PATCH 1/2] update the saleorder --- inventory/views.py | 10 +++++++++- templates/sales/saleorder_detail.html | 28 +++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/inventory/views.py b/inventory/views.py index b4c1ff56..73c93df6 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -4133,7 +4133,6 @@ def sales_list_view(request, dealer_slug): context = {"txs": page_obj, "page_obj": page_obj} return render(request, "sales/sales_list.html", context) - class SaleOrderDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView): model = models.SaleOrder template_name = "sales/saleorder_detail.html" @@ -4155,6 +4154,15 @@ class SaleOrderDetailView(LoginRequiredMixin,PermissionRequiredMixin, DetailView return context + def post(self, request, *args, **kwargs): + sale_order = self.get_object() + status = request.POST.get("status") + if status: + sale_order.status = status + sale_order.save() + messages.success(request, _("Sale order status updated")) + return redirect("order_detail", dealer_slug=sale_order.dealer.slug, pk=sale_order.pk) + # Estimates class EstimateListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): diff --git a/templates/sales/saleorder_detail.html b/templates/sales/saleorder_detail.html index 3f44f34d..862f215d 100644 --- a/templates/sales/saleorder_detail.html +++ b/templates/sales/saleorder_detail.html @@ -19,7 +19,7 @@
-
+

{% trans "Customer Information" %}

{% trans "Name" %}: {{ sale_order.full_name }}
@@ -30,7 +30,7 @@

-
+

{% trans "Order Details" %}

{% trans "Order Date" %}: {{ sale_order.order_date|date }}
@@ -38,6 +38,30 @@ {% trans "Created By" %}: {{ sale_order.created_by }}

+ {% if not prems.inventory.change_saleorder %} +
+
+

{% trans "Update Order Status" %}

+
+ {% csrf_token %} +
+ + +
+ +
+
+
+ {% endif %}
From ae4d981d373d2db58b46f562ba23175dd5b5bb6d Mon Sep 17 00:00:00 2001 From: ismail Date: Sun, 6 Jul 2025 12:47:33 +0300 Subject: [PATCH 2/2] update the signup view and other perms changes --- .../commands/set_custom_permissions.py | 16 + inventory/models.py | 30 +- inventory/tasks.py | 37 +- inventory/utils.py | 51 +-- inventory/views.py | 82 +++-- load_initial_data.sh | 2 + static/images/customers/sun_mountain.jpg | Bin 0 -> 15608 bytes templates/account/signup-wizard-copy.html | 287 +++++++++++++++ templates/account/signup-wizard.html | 335 +++++++++--------- templates/base.html | 4 +- templates/header.html | 208 ++++++----- templates/inventory/car_detail.html | 44 +-- templates/sales/sales_list.html | 22 +- 13 files changed, 701 insertions(+), 417 deletions(-) create mode 100644 inventory/management/commands/set_custom_permissions.py create mode 100644 static/images/customers/sun_mountain.jpg create mode 100644 templates/account/signup-wizard-copy.html diff --git a/inventory/management/commands/set_custom_permissions.py b/inventory/management/commands/set_custom_permissions.py new file mode 100644 index 00000000..23e4a9da --- /dev/null +++ b/inventory/management/commands/set_custom_permissions.py @@ -0,0 +1,16 @@ +from inventory import models +from django.contrib.auth.models import Permission +from django.core.management.base import BaseCommand +from django.contrib.contenttypes.models import ContentType +from django_ledger.models import EstimateModel,BillModel,AccountModel,LedgerModel + + +class Command(BaseCommand): + def handle(self, *args, **kwargs): + Permission.objects.get_or_create(name="Can view crm",codename="can_view_crm",content_type=ContentType.objects.get_for_model(models.Lead)) + Permission.objects.get_or_create(name="Can view sales",codename="can_view_sales",content_type=ContentType.objects.get_for_model(EstimateModel)) + Permission.objects.get_or_create(name="Can view reports",codename="can_view_reports",content_type=ContentType.objects.get_for_model(LedgerModel)) + Permission.objects.get_or_create(name="Can view inventory",codename="can_view_inventory",content_type=ContentType.objects.get_for_model(models.Car)) + Permission.objects.get_or_create(name="Can approve bill",codename="can_approve_billmodel",content_type=ContentType.objects.get_for_model(BillModel)) + Permission.objects.get_or_create(name="Can view financials",codename="can_view_financials",content_type=ContentType.objects.get_for_model(AccountModel)) + Permission.objects.get_or_create(name="Can approve estimate",codename="can_approve_estimatemodel",content_type=ContentType.objects.get_for_model(EstimateModel)) \ No newline at end of file diff --git a/inventory/models.py b/inventory/models.py index d6cf5676..2ba6e7cc 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -2550,15 +2550,6 @@ class CustomGroup(models.Model): pass def set_default_permissions(self): - Permission.objects.get_or_create(name="Can approve estimate",codename="can_approve_estimatemodel",content_type=ContentType.objects.get_for_model(EstimateModel)) - Permission.objects.get_or_create(name="Can approve bill",codename="can_approve_billmodel",content_type=ContentType.objects.get_for_model(BillModel)) - - Permission.objects.get_or_create(name="Can view inventory",codename="can_view_inventory",content_type=ContentType.objects.get_for_model(Car)) - Permission.objects.get_or_create(name="Can view sales",codename="can_view_sales",content_type=ContentType.objects.get_for_model(EstimateModel)) - Permission.objects.get_or_create(name="Can view crm",codename="can_view_crm",content_type=ContentType.objects.get_for_model(Lead)) - Permission.objects.get_or_create(name="Can view financials",codename="can_view_financials",content_type=ContentType.objects.get_for_model(AccountModel)) - Permission.objects.get_or_create(name="Can view reports",codename="can_view_reports",content_type=ContentType.objects.get_for_model(LedgerModel)) - self.clear_permissions() ###################################### ###################################### @@ -2698,7 +2689,6 @@ class CustomGroup(models.Model): "view_carcolors", "view_cartransfer", "view_saleorder", - ], ) self.set_permissions( @@ -2966,4 +2956,22 @@ class ExtraInfo(models.Model): verbose_name_plural = "Extra Info" def __str__(self): - return f"ExtraInfo for {self.content_object} ({self.content_type})" \ No newline at end of file + return f"ExtraInfo for {self.content_object} ({self.content_type})" + + @classmethod + def get_sale_orders(cls, staff=None,is_dealer=False): + if not staff and not is_dealer: + return [] + if is_dealer: + qs = ExtraInfo.objects.filter( + content_type=ContentType.objects.get_for_model(EstimateModel), + related_content_type=ContentType.objects.get_for_model(Staff), + ) + else: + qs = ExtraInfo.objects.filter( + content_type=ContentType.objects.get_for_model(EstimateModel), + related_content_type=ContentType.objects.get_for_model(Staff), + related_object_id=staff.pk, + ) + + return [x.content_object.sale_orders.first for x in qs] diff --git a/inventory/tasks.py b/inventory/tasks.py index 452c28fb..26667b61 100644 --- a/inventory/tasks.py +++ b/inventory/tasks.py @@ -1,10 +1,11 @@ from django.db import transaction from django_ledger.io import roles -from django.core.mail import send_mail -from django.utils.translation import gettext_lazy as _ -from inventory.models import DealerSettings, Dealer from django_q.tasks import async_task - +from django.core.mail import send_mail +from appointment.models import StaffMember +from django.contrib.auth.models import User,Group, Permission +from inventory.models import DealerSettings, Dealer +from django.utils.translation import gettext_lazy as _ def create_settings(pk): instance = Dealer.objects.get(pk=pk) @@ -1459,8 +1460,26 @@ def send_email(from_, to_, subject, message): async_task(send_mail,subject, message, from_email, recipient_list) -# @background -def long_running_task(duration): - """Example background task""" - print("Task completed") - return True +def create_user_dealer(email, password, name, arabic_name, phone, crn, vrn, address): + with transaction.atomic(): + user = User.objects.create(username=email, email=email) + user.set_password(password) + user.save() + group = Group.objects.create(name=f"{user.pk}-Admin") + user.groups.add(group) + for perm in Permission.objects.filter( + content_type__app_label__in=["inventory", "django_ledger"] + ): + group.permissions.add(perm) + + StaffMember.objects.create(user=user) + Dealer.objects.create( + user=user, + name=name, + arabic_name=arabic_name, + crn=crn, + vrn=vrn, + phone_number=phone, + address=address, + ) + diff --git a/inventory/utils.py b/inventory/utils.py index 7f9f64e7..b88d1090 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -1,33 +1,29 @@ import json +import secrets import datetime -from plans.models import AbstractOrder -from django.contrib.auth.models import Group, Permission -from django.db import transaction -from django.urls import reverse import requests from decimal import Decimal +from inventory import models +from django.urls import reverse +from django.conf import settings from django.utils import timezone from django_ledger.io import roles from django.contrib import messages from django.shortcuts import redirect -from django.core.exceptions import ObjectDoesNotExist -from django_ledger.models.journal_entry import JournalEntryModel -from django_ledger.models.transactions import TransactionModel -from inventory import models -from django.conf import settings +from django_q.tasks import async_task from django.core.mail import send_mail -from django.utils.translation import gettext_lazy as _ -from django_ledger.models.items import ItemModel +from plans.models import AbstractOrder from django_ledger.models import ( InvoiceModel, BillModel, VendorModel, ) +from django_ledger.models.items import ItemModel from django.utils.translation import get_language -from appointment.models import StaffMember -from django.contrib.auth.models import User -from django_q.tasks import async_task -import secrets +from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import gettext_lazy as _ +from django_ledger.models.transactions import TransactionModel +from django_ledger.models.journal_entry import JournalEntryModel def make_random_password( @@ -1340,31 +1336,6 @@ def create_make_accounts(dealer): active=True, ) - -def create_user_dealer(email, password, name, arabic_name, phone, crn, vrn, address): - with transaction.atomic(): - user = User.objects.create(username=email, email=email) - user.set_password(password) - user.save() - group = Group.objects.create(name=f"{user.pk}-Admin") - user.groups.add(group) - for perm in Permission.objects.filter( - content_type__app_label__in=["inventory", "django_ledger"] - ): - group.permissions.add(perm) - - StaffMember.objects.create(user=user) - models.Dealer.objects.create( - user=user, - name=name, - arabic_name=arabic_name, - crn=crn, - vrn=vrn, - phone_number=phone, - address=address, - ) - - def handle_payment(request, order): url = "https://api.moyasar.com/v1/payments" callback_url = request.build_absolute_uri(reverse("payment_callback", args=[request.dealer.slug])) diff --git a/inventory/views.py b/inventory/views.py index 73c93df6..90b34499 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -1,5 +1,6 @@ # Standard import os +import re import io import csv import cv2 @@ -48,8 +49,7 @@ from django.shortcuts import HttpResponse from django.db.models import Sum, F, Count from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger -from django.contrib.auth.models import User -from django.contrib.auth.models import Group +from django.contrib.auth.models import User,Group from django.db.models import Value from django.urls import reverse, reverse_lazy from django.utils import timezone, translation @@ -183,7 +183,6 @@ from .services import ( ) from .utils import ( CarFinanceCalculator, - create_user_dealer, get_car_finance_data, get_item_transactions, handle_payment, @@ -194,11 +193,11 @@ from .utils import ( set_invoice_payment, CarTransfer, ) -from .tasks import create_accounts_for_make, send_email +from .tasks import create_accounts_for_make, create_user_dealer, send_email # djago easy audit log from easyaudit.models import RequestEvent, CRUDEvent, LoginEvent - +from django_q.tasks import async_task logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) @@ -290,47 +289,43 @@ def dealer_signup(request): or failure. :rtype: Union[django.http.HttpResponse, django.http.JsonResponse] """ - form1 = forms.WizardForm1() - form2 = forms.WizardForm2() - form3 = forms.WizardForm3() - if request.method == "POST": - if "Hx-Request" in request.headers: - form1 = forms.WizardForm1(request.POST) - return render( - request, - "account/signup-wizard.html", - {"form1": form1, "form2": form2, "form3": form3}, - ) data = json.loads(request.body) - wf1 = data.get("wizardValidationForm1") - wf2 = data.get("wizardValidationForm2") - wf3 = data.get("wizardValidationForm3") - email = wf1.get("email") - password = wf1.get("password") - password_confirm = wf1.get("confirm_password") - name = wf2.get("name") - arabic_name = wf2.get("arabic_name") - phone = wf2.get("phone_number") - crn = wf3.get("crn") - vrn = wf3.get("vrn") - address = wf3.get("address") + + email = data.get("email") + password = data.get("password") + password_confirm = data.get("confirm_password") + name = data.get("name") + arabic_name = data.get("arabic_name") + phone = data.get("phone_number") + crn = data.get("crn") + vrn = data.get("vrn") + address = data.get("address") + + if User.objects.filter(email=email).exists(): + return JsonResponse({"error": _("Email already exists")}, status=400) + if not re.match( + r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$", + email, + ): + return JsonResponse({"error": _("Please enter a valid email address")}, status=400) + + if len(password) < 8: + return JsonResponse({"error": _("Password must be at least 8 characters")}, status=400) if password != password_confirm: return JsonResponse({"error": _("Passwords do not match")}, status=400) try: - #TODO make this a django-q task - create_user_dealer( + async_task(create_user_dealer( email, password, name, arabic_name, phone, crn, vrn, address - ) + )) return JsonResponse({"message": _("User created successfully")}, status=200) except Exception as e: return JsonResponse({"error": str(e)}, status=400) return render( request, "account/signup-wizard.html", - {"form1": form1, "form2": form2, "form3": form3}, ) @@ -1165,7 +1160,7 @@ def inventory_stats_view(request, dealer_slug): "inventory/inventory_stats.html" template. :rtype: HttpResponse """ - + # Base queryset for cars belonging to the dealer cars = models.Car.objects.filter(dealer=request.dealer) @@ -4122,11 +4117,20 @@ def sales_list_view(request, dealer_slug): """ dealer = get_object_or_404(models.Dealer, slug=dealer_slug) entity = dealer.entity - - sale_orders = models.SaleOrder.objects.filter( - dealer=dealer, - ) - paginator = Paginator(sale_orders, 30) + staff = getattr(request.user.staffmember, "staff", None) + qs = [] + try: + if dealer: + qs = models.ExtraInfo.get_sale_orders(staff=staff,is_dealer=True) + else: + qs = models.ExtraInfo.get_sale_orders(staff=staff) + except Exception as e: + print(e) + print(qs) + # sale_orders = models.SaleOrder.objects.filter( + # dealer=dealer, + # ) + paginator = Paginator(qs, 30) page_number = request.GET.get("page") page_obj = paginator.get_page(page_number) @@ -9272,7 +9276,7 @@ def permenant_delete_account(request,dealer_slug, content_type, slug): def PurchaseOrderCreateView(request, dealer_slug,entity_slug): dealer = get_object_or_404(models.Dealer, slug=dealer_slug) entity = dealer.entity - + if request.method == "POST": try: po = entity.create_purchase_order(po_title=request.POST.get("po_title")) diff --git a/load_initial_data.sh b/load_initial_data.sh index 1f8885f5..83a7bec2 100755 --- a/load_initial_data.sh +++ b/load_initial_data.sh @@ -26,6 +26,8 @@ python3 manage.py tenhal_plan python3 manage.py set_vat +python3 manage.py set_custom_permissions + python3 manage.py initial_services_offered echo "Done" \ No newline at end of file diff --git a/static/images/customers/sun_mountain.jpg b/static/images/customers/sun_mountain.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0786c2da5c729b6dbf8a6c9f94cc9d0ac304051f GIT binary patch literal 15608 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 literal 0 HcmV?d00001 diff --git a/templates/account/signup-wizard-copy.html b/templates/account/signup-wizard-copy.html new file mode 100644 index 00000000..1ca17e0e --- /dev/null +++ b/templates/account/signup-wizard-copy.html @@ -0,0 +1,287 @@ +{% extends "welcome_base.html" %} +{% load crispy_forms_filters %} +{% load i18n static %} + + +{% block content %} +
+
+
+ +
+
+ {% trans 'home' %} + {% trans 'home' %} +
+
+
+

{% trans 'Sign Up' %}

+

{% trans 'Create your account today' %}

+
+ +
+ +
+
+ +
+
+ {{form2|crispy}} +
+
+
+
+ {{form3|crispy}} +
+
+
+
+
+
+
+
+
+
{% trans 'You are all set!' %}
+

{% trans 'Now you can access your account' %}
{% trans 'anytime' %} {% trans 'anywhere' %}

+
+
+
+
+
+
+ +
+
+
+
+
+
+ {% include 'footer.html' %} +
+ +{% endblock content %} + +{% block customJS %} + + + +{% endblock customJS %} \ No newline at end of file diff --git a/templates/account/signup-wizard.html b/templates/account/signup-wizard.html index 1ca17e0e..1d204109 100644 --- a/templates/account/signup-wizard.html +++ b/templates/account/signup-wizard.html @@ -19,7 +19,19 @@

{% trans 'Create your account today' %}

-
+
-
+
-
- {{form1|crispy}} - {{ _("Read Terms of Service and Privacy Policy")}} + +
+ + +
+ {% trans "Please enter a valid email address" %} +
+
+
+ + +
+ {% trans "Password does not match. or length is less than 8 characters." %} +
+
+
+ * + +
+ {% trans "Password does not match. or length is less than 8 characters." %} +
+
-
- {{form2|crispy}} + +
+ + +
+
+ + +
+
+ * + +
+ {% trans "Please enter a valid phone number" %} +
+
-
- {{form3|crispy}} + +
+ + +
+
+ + +
+
+ + +
@@ -62,18 +154,18 @@
{% trans 'You are all set!' %}
-

{% trans 'Now you can access your account' %}
{% trans 'anytime' %} {% trans 'anywhere' %}

+

{% trans 'Now you can access your account' %}
{% trans 'anytime' %} {% trans 'anywhere' %}

- - {% endif %} + {% endif %} {% if perms.django_ledger.can_view_reports %}
- -
- {% if perms.inventory.view_carfinance%}

{% trans 'Financial Details' %}

@@ -296,7 +300,7 @@ {% trans "Edit" %} {% else %} {% trans "Cannot Edit, Car in Transfer." %} - {% endif %} + {% endif %} {% endif %} @@ -342,7 +346,7 @@ style="background-color: rgb({{ car.colors.interior.rgb }})">
- + {% if perms.inventory.change_carcolors%} @@ -433,7 +437,7 @@ {% endif %} - + {% endif %} @@ -501,7 +505,7 @@ alt=""> {% endif %}
- +