+
+ {% trans 'Sign Up' %}
+{% trans 'Create your account today' %}
+

{% trans 'You are all set!' %}
+{% trans 'Now you can access your account' %}
{% trans 'anytime' %} {% trans 'anywhere' %}
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 00000000..0786c2da
Binary files /dev/null and b/static/images/customers/sun_mountain.jpg differ
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 'Create your account today' %} {% trans 'Now you can access your account' %}
+
+ {% trans 'Sign Up' %}
+ 

{% trans 'You are all set!' %}
+
{% trans 'anytime' %} {% trans 'anywhere' %}
{% trans 'Create your account today' %}
-{% trans 'Now you can access your account' %}
{% trans 'anytime' %} {% trans 'anywhere' %}
{% trans 'Now you can access your account' %}
{% trans 'anytime' %} {% trans 'anywhere' %}
{% 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 }})">{{tx.customer}}
+{{tx}}
{{tx.customer.address}}
@@ -133,24 +128,11 @@{{tx.customer.phone_number}}
{{tx.info.model}}
-{{tx.info.vin}}
-{{tx.info.trim}}
-{{tx.finance.total}}
-
- {{tx.estimate.estimate_number}}
+ {{ tx.estimate.estimate_number}}
{% if tx.estimate.status == "draft" %}
{{tx.estimate.status}}