From 86d3c3d5860c62a1d8817b83214cf5bc2c2e4169 Mon Sep 17 00:00:00 2001 From: gitea Date: Thu, 27 Feb 2025 15:02:41 +0000 Subject: [PATCH] update --- .gitignore | 2 + inventory/models.py | 28 +- inventory/signals.py | 4 + inventory/urls.py | 4 +- inventory/utils.py | 1 - inventory/views.py | 93 ++++--- templates/base.html | 2 +- templates/crm/leads/lead_list.html | 4 +- templates/customers/customer_list.html | 12 + templates/inventory/car_form.html | 16 +- .../organizations/organization_list.html | 261 +++++++++--------- templates/sales/estimates/estimate_form.html | 34 ++- templates/sales/orders/order_list.html | 2 + templates/sales/payments/payment_list.html | 4 + templates/users/user_form.html | 9 +- 15 files changed, 273 insertions(+), 203 deletions(-) diff --git a/.gitignore b/.gitignore index 71c44dd4..0fde4c4f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ __pycache__ **/*__pycache__ db.sqlite db.sqlite3 +db.sqlite3.backup +db.sqlite* media car_inventory/settings.py scripts/dsrpipe.py diff --git a/inventory/models.py b/inventory/models.py index 4735de77..2fb05ef9 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -944,7 +944,7 @@ class StaffTypes(models.TextChoices): class Staff(models.Model, LocalizedNameMixin): staff_member = models.OneToOneField(StaffMember, on_delete=models.CASCADE, related_name="staff") - dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff") + dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="staff") name = models.CharField(max_length=255, verbose_name=_("Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) @@ -1225,6 +1225,8 @@ class Lead(models.Model): def __str__(self): return f"{self.first_name} {self.last_name}" + def get_user_model(self): + return User.objects.get(email=self.email) or None @property def is_converted(self): return bool(self.customer) @@ -1247,20 +1249,20 @@ class Lead(models.Model): customer = entity.get_customers().filter(email=self.email).first() if entity and not customer: customer = entity.create_customer( - customer_model_kwargs={ - "customer_name": self.full_name, - "address_1": self.address, - "phone": self.phone_number, - "email": self.email, - } - ) - - customer.additional_info = {} + commit=False, + customer_model_kwargs={ + "customer_name": self.full_name, + "address_1": self.address, + "phone": self.phone_number, + "email": self.email, + } + ) + customer.additional_info.update({"info":self.to_dict()}) - customer.additional_info.update({"stage":"qualified"}) + customer.additional_info.update({"type":"customer"}) + customer.save() self.customer = customer self.status = Status.QUALIFIED - customer.save() self.save() return customer @@ -1760,7 +1762,7 @@ class SaleOrder(models.Model): ('cash', 'Cash'), ('finance', 'Finance'), ('lease', 'Lease'), - ]) + ]) comments = models.TextField(blank=True, null=True) formatted_order_id = models.CharField(max_length=10, unique=True, editable=False) created = models.DateTimeField(auto_now_add=True) diff --git a/inventory/signals.py b/inventory/signals.py index d39f65ad..e495810e 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -666,9 +666,13 @@ def create_ledger_vendor(sender, instance, created, **kwargs): @receiver(post_save, sender=models.CustomerModel) def create_customer_user(sender, instance, created, **kwargs): if created: + first_name = instance.additional_info.get("customer_info").get("first_name") + last_name = instance.additional_info.get("customer_info").get("last_name") user = User.objects.create( username=instance.email, email=instance.email, + first_name=first_name if first_name else '', + last_name=last_name if last_name else '', ) instance.additional_info.update({"user_info": to_dict(user)}) user.set_unusable_password() diff --git a/inventory/urls.py b/inventory/urls.py index 38802a90..6c6a3dad 100644 --- a/inventory/urls.py +++ b/inventory/urls.py @@ -74,11 +74,11 @@ urlpatterns = [ "customers/create/", views.CustomerCreateView, name="customer_create" ), path( - "customers//update/", + "customers//update/", views.CustomerUpdateView, name="customer_update", ), - path("customers//delete/", views.delete_customer, name="customer_delete"), + path("customers//delete/", views.delete_customer, name="customer_delete"), path( "customers//opportunities/create/", views.OpportunityCreateView.as_view(), diff --git a/inventory/utils.py b/inventory/utils.py index 19286b77..da094f10 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -247,7 +247,6 @@ def get_financial_values(model): additional_services = [] for i in data: - print(i) if i.item_model.additional_info["additional_services"]: additional_services.extend( [ diff --git a/inventory/views.py b/inventory/views.py index 6d2de5b7..ff33128a 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -10,7 +10,7 @@ from calendar import month_name from pyzbar.pyzbar import decode from urllib.parse import urlparse, urlunparse ##################################################################### - +from django.db.models.deletion import RestrictedError # Django from django.db.models import Q from django.conf import settings @@ -1250,7 +1250,6 @@ class CustomerDetailView(LoginRequiredMixin, DetailView): context["total"] = total return context - def add_note_to_customer(request, customer_id): customer = get_object_or_404(CustomerModel, pk=customer_id) if request.method == "POST": @@ -1312,9 +1311,9 @@ def CustomerCreateView(request): "email": form.cleaned_data["email"], } ) - customer.additional_info = {} - customer.additional_info["customer_info"] = customer_dict - customer.additional_info["type"] = "customer" + # customer.additional_info = {} + customer.additional_info.update({"customer_info": customer_dict}) + customer.additional_info.update({"type": "customer"}) customer.save() messages.success(request, _("Customer created successfully.")) @@ -1375,11 +1374,15 @@ def CustomerUpdateView(request, pk): - @login_required def delete_customer(request, pk): - customer = get_object_or_404(models.Customer, pk=pk) - customer.delete() + customer = get_object_or_404(models.CustomerModel, pk=pk) + user = User.objects.get(email=customer.email) + customer.active = False + user.is_active = False + customer.save() + user.save() + messages.success(request, _("Customer deleted successfully.")) return redirect("customer_list") @@ -1581,10 +1584,11 @@ class UserCreateView( email = form.cleaned_data["email"] password = "Tenhal@123" + user = User.objects.create_user(username=form.cleaned_data["name"], email=email, password=password) user.is_staff = True user.save() - staff_member = StaffMember.objects.create(user=user) + staff_member = StaffMember.objects.create(user=user) for service in form.cleaned_data["service_offered"]: staff_member.services_offered.add(service) staff = form.save(commit=False) @@ -1639,9 +1643,9 @@ class UserUpdateView( return super().form_valid(form) def UserDeleteview(request, pk): - user = get_object_or_404(models.Staff, pk=pk) - user.staff_member.delete() - user.delete() + staff = get_object_or_404(models.Staff, pk=pk) + staff.staff_member.delete() + staff.delete() messages.success(request, _("User deleted successfully.")) return redirect("user_list") @@ -1767,9 +1771,14 @@ def OrganizationUpdateView(request,pk): # success_message = "Organization deleted successfully." def OrganizationDeleteView(request, pk): organization = get_object_or_404(CustomerModel, pk=pk) - organization.delete() - messages.success(request, _("Organization deleted successfully.")) - return redirect("organization_list") + try: + User.objects.get(email=organization.email).delete() + organization.delete() + messages.success(request, _("Organization deleted successfully.")) + except Exception as e: + print("unable to delete user", e) + messages.error(request,_("Unable to delete organization")) + return redirect("organization_list") class RepresentativeListView(LoginRequiredMixin, ListView): model = models.Representative @@ -2157,7 +2166,7 @@ def create_estimate(request,pk=None): form = forms.EstimateModelCreateForm( entity_slug=entity.slug, user_model=entity.admin ) - form.fields["customer"].queryset = entity.get_customers().filter(active=True) + form.fields["customer"].queryset = entity.get_customers().filter(active=True,additional_info__type="customer") if pk: opportunity = models.Opportunity.objects.get(pk=pk) @@ -2181,7 +2190,8 @@ def create_estimate(request,pk=None): } for x in car_list ], - "opportunity_id": pk if pk else None + "opportunity_id": pk if pk else None, + "customer_count": entity.get_customers().count() } return render(request, "sales/estimates/estimate_form.html", context) @@ -2686,28 +2696,40 @@ def lead_create(request): if form.is_valid(): instance = form.save(commit=False) dealer = get_user_type(request) - instance.dealer = dealer - # staff = None - # if hasattr(request.user, "staffmember"): - # staff = request.user.staffmember.staff - # instance.staff = staff + instance.dealer = dealer instance.staff = form.cleaned_data.get("staff") - + # creating customer in ledger customer = dealer.entity.get_customers().filter(email=instance.email).first() if not customer: customer = dealer.entity.create_customer( + commit=False, customer_model_kwargs={ "customer_name": instance.full_name, "address_1": instance.address, "phone": instance.phone_number, "email": instance.email, - "sales_tax_rate": 0.15, + "sales_tax_rate": 0.15, } ) - customer.additional_info.update({'stage': 'lead'}) - customer.save() + customer_info = { + "first_name": instance.first_name, + "last_name": instance.last_name, + "address": instance.address, + "phone_number": str(instance.phone_number), + "email": instance.email, + } + customer.additional_info.update({"customer_info": customer_info }) + customer.additional_info.update({"type":"lead"}) + customer.save() instance.customer = customer + # try: + # user = User.objects.get(email=customer.email) + # user.first_name = instance.first_name + # user.last_name = instance.last_name + # user.save() + # except Exception as e: + # print(e) instance.save() messages.success(request, "Lead created successfully!") return redirect("lead_list") @@ -2732,6 +2754,11 @@ class LeadUpdateView(UpdateView): @login_required def LeadDeleteView(request,pk): lead = get_object_or_404(models.Lead, pk=pk) + try: + User.objects.get(email=lead.customer.email).delete() + lead.customer.delete() + except Exception as e: + print(e) lead.delete() messages.success(request, "Lead deleted successfully!") return redirect("lead_list") @@ -2809,11 +2836,11 @@ def lead_convert(request, pk): @login_required def schedule_lead(request, pk): - if not hasattr(request.user,"staffmember"): + if not request.is_staff: messages.error(request, "You do not have permission to schedule lead.") return redirect("lead_list") dealer = get_user_type(request) - + lead = get_object_or_404(models.Lead, pk=pk, dealer=dealer) if request.method == "POST": form = forms.ScheduleForm(request.POST) @@ -2821,13 +2848,13 @@ def schedule_lead(request, pk): instance = form.save(commit=False) instance.lead = lead instance.scheduled_by = request.user + instance.customer = lead.customer # Create AppointmentRequest service = Service.objects.filter(name=instance.scheduled_type).first() if not service: messages.error(request, "Service not found!") - return redirect("lead_list") - staff_member = request.user.staffmember + return redirect("lead_list") try: appointment_request = AppointmentRequest.objects.create( @@ -2835,7 +2862,7 @@ def schedule_lead(request, pk): start_time=instance.scheduled_at.time(), end_time=(instance.scheduled_at + instance.duration).time(), service=service, - staff_member=staff_member, + staff_member=request.user.staffmember, ) except ValidationError as e: messages.error(request, str(e)) @@ -3426,6 +3453,10 @@ class OrderListView(ListView): template_name = "sales/orders/order_list.html" context_object_name = "orders" + def get_queryset(self): + dealer = get_user_type(self.request) + qs = super().get_queryset() + return qs.filter(estimate__entity=dealer.entity) # email @login_required diff --git a/templates/base.html b/templates/base.html index 15155fe9..f1719ce8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -104,7 +104,7 @@ - + {% comment %} {% endcomment %} diff --git a/templates/crm/leads/lead_list.html b/templates/crm/leads/lead_list.html index 512ea4f2..c5646718 100644 --- a/templates/crm/leads/lead_list.html +++ b/templates/crm/leads/lead_list.html @@ -140,11 +140,11 @@

-

-
+
diff --git a/templates/customers/customer_list.html b/templates/customers/customer_list.html index e06d2fdf..cd7bc7a7 100644 --- a/templates/customers/customer_list.html +++ b/templates/customers/customer_list.html @@ -50,6 +50,11 @@
{{ _("Address")|capfirst }} + @@ -76,6 +81,13 @@ + + + diff --git a/templates/sales/payments/payment_list.html b/templates/sales/payments/payment_list.html index 233289f5..5e4b52c8 100644 --- a/templates/sales/payments/payment_list.html +++ b/templates/sales/payments/payment_list.html @@ -32,6 +32,10 @@ + {% elif journal.ledger.billmodel %} + {% else %} {% endif %} diff --git a/templates/users/user_form.html b/templates/users/user_form.html index 509c0679..f13c2bbe 100644 --- a/templates/users/user_form.html +++ b/templates/users/user_form.html @@ -27,8 +27,13 @@ {% csrf_token %} - {{ redirect_field }} - {{ form|crispy }} + {{ redirect_field }} + {{ form.name|as_crispy_field }} + {{ form.arabic_name|as_crispy_field }} + {{ form.email|as_crispy_field }} + {{ form.phone_number|as_crispy_field }} + {{ form.staff_type|as_crispy_field }} + {{ form.service_offered|as_crispy_field }} {% for error in form.errors %}
{{ error }}
{% endfor %}
+
+
{{ _("Active")|capfirst }} +
+
{{ _("Create date") }} {{ customer.additional_info.customer_info.national_id }} {{ customer.address_1 }} + {% if customer.active %} + {{customer.active}} + {% else %} + {{customer.active}} + {% endif %} + {{ customer.created|date }} diff --git a/templates/inventory/car_form.html b/templates/inventory/car_form.html index bb5ff1d8..db4b365b 100644 --- a/templates/inventory/car_form.html +++ b/templates/inventory/car_form.html @@ -18,12 +18,10 @@ {% include 'partials/form_errors.html' %}
-

{% trans 'Add Car' %}

- -
+
@@ -46,7 +44,7 @@
-
+
{% trans 'Year' %}
-
+
-
+
- - {% if request.GET.q %} - - - - {% endif %} - -
- -
-
+
+
+
+ - -
- - - - - - - - - - - - - - - - {% for org in organizations %} - - - - - - - - - - - - - - {% endfor %} - - -
{{ _("Name")|capfirst }} -
-
{% trans "CRN" %} -
-
-
-
{% trans "VRN" %} -
-
-
-
{% trans "Phone" %} -
-
-
-
{% trans 'Address' %} -
-
- {{ _("Create date") }}
-
-
{{ org.customer_name }} -
-

{{ org.customer_name}} - -
-
-
-
{{ org.additional_info.organization_info.vrn }}{{ org.phone }} - {{ org.address_1 }}{{ org.created|date }} -
- - -
-
+
+
+ +
+
+
+ +
+ + + + + + + + + + + + + + {% for org in organizations %} + + + + + + + + + + + + {% endfor %} + +
{{ _('Name')|capfirst }} +
+
+ +
{% trans 'CRN' %} +
+
+
+
+ +
{% trans 'VRN' %} +
+
+
+
+ +
{% trans 'Phone' %} +
+
+
+
+ +
{% trans 'Address' %} +
+
{{ _('Create date') }}
+
+
+ {{ org.customer_name }} +
+

{{ org.customer_name }} +
+
+
+
{{ org.additional_info.organization_info.vrn }} + {{ org.phone }} + {{ org.address_1 }}{{ org.created|date }} +
+ + +
+
+
{% if is_paginated %} - {% include 'partials/pagination.html' %} + {% include 'partials/pagination.html' %} {% endif %} +
-
- - -{% endblock %} \ No newline at end of file + +{% endblock %} diff --git a/templates/sales/estimates/estimate_form.html b/templates/sales/estimates/estimate_form.html index 6a6dcb87..ea09aa84 100644 --- a/templates/sales/estimates/estimate_form.html +++ b/templates/sales/estimates/estimate_form.html @@ -4,18 +4,40 @@ {% block title %}{{ _("Create Quotation") }}{% endblock title %} +{% block customCSS %} + +{% endblock customCSS %} {% block content %} -
+
+ {% if not items %} + + {% endif %} + {% if not customer_count %} + + {% endif %} +

{% trans "Create Quotation" %}

- {% csrf_token %} -
+
{{ form|crispy }}

{{ _("Cars") }}

-
+
-
+
-
+
diff --git a/templates/sales/orders/order_list.html b/templates/sales/orders/order_list.html index f1ef4ff2..e0532a5e 100644 --- a/templates/sales/orders/order_list.html +++ b/templates/sales/orders/order_list.html @@ -14,6 +14,8 @@
{% trans "Order Number" %} {% trans "Customer" %} {% trans "For Quotation" %}
{{ journal.ledger.invoicemodel }} + {{ journal.ledger.billmodel }} +