diff --git a/inventory/forms.py b/inventory/forms.py index e4861464..ec7ac101 100644 --- a/inventory/forms.py +++ b/inventory/forms.py @@ -8,7 +8,7 @@ from django import forms from plans.models import PlanPricing from django.contrib.auth import get_user_model -from inventory.validators import SaudiPhoneNumberValidator +from inventory.validators import SaudiPhoneNumberValidator, vat_rate_validator from .models import CustomGroup, Status, Stage from .mixins import AddClassMixin from django_ledger.forms.invoice import ( @@ -2120,11 +2120,17 @@ class AdditionalFinancesForm(forms.Form): class VatRateForm(forms.ModelForm): + rate = forms.DecimalField( + label="VAT Rate", + max_digits=5, + decimal_places=2, + validators=[vat_rate_validator] + ) + class Meta: model = VatRate fields = ["rate"] - class CustomSetPasswordForm(SetPasswordForm): new_password1 = forms.CharField( label="New Password", diff --git a/inventory/models.py b/inventory/models.py index 80ecd91a..48b3c6b5 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -3,7 +3,7 @@ import uuid from datetime import datetime from django.conf import settings from django.contrib.auth.models import Permission -from inventory.validators import SaudiPhoneNumberValidator +from inventory.validators import SaudiPhoneNumberValidator, vat_rate_validator from decimal import Decimal from django.urls import reverse from django.utils.text import slugify @@ -206,7 +206,7 @@ class UnitOfMeasure(models.TextChoices): class VatRate(models.Model): dealer = models.ForeignKey("Dealer", on_delete=models.CASCADE) - rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.15")) + rate = models.DecimalField(max_digits=5, decimal_places=2, default=Decimal("0.15"),validators=[vat_rate_validator]) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) diff --git a/inventory/validators.py b/inventory/validators.py index 777a8391..791df1dc 100644 --- a/inventory/validators.py +++ b/inventory/validators.py @@ -1,5 +1,6 @@ from django.core.validators import RegexValidator from django.utils.translation import gettext_lazy as _ +from django.core.exceptions import ValidationError import re @@ -14,3 +15,10 @@ class SaudiPhoneNumberValidator(RegexValidator): # Remove any whitespace, dashes, or other separators cleaned_value = re.sub(r"[\s\-\(\)\.]", "", str(value)) super().__call__(cleaned_value) + +def vat_rate_validator(value): + if value < 0 or value > 1: + raise ValidationError( + _('%(value)s is not a valid VAT rate. It must be between 0 and 1.'), + params={'value': value}, + ) \ No newline at end of file diff --git a/inventory/views.py b/inventory/views.py index 8187c6f4..1d2b5f40 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -2336,12 +2336,29 @@ class DealerDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView): return context +from .forms import VatRateForm +@login_required def dealer_vat_rate_update(request, slug): dealer = get_object_or_404(models.Dealer, slug=slug) - models.VatRate.objects.filter(dealer=dealer).update(rate=request.POST.get("rate")) - messages.success(request, _("VAT rate updated successfully")) - return redirect("dealer_detail", slug=slug) + + vat_rate_instance, created = models.VatRate.objects.get_or_create(dealer=dealer) + if request.method == "POST": + + form = VatRateForm(request.POST, instance=vat_rate_instance) + + if form.is_valid(): + form.save() + messages.success(request, _("VAT rate updated successfully")) + return redirect("dealer_detail", slug=slug) + else: + + messages.error(request, _("Please enter valid vat rate between 0 and 1.")) + redirect("dealer_detail", slug=slug) + + return redirect("dealer_detail", slug=slug) + + class DealerUpdateView( LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, UpdateView @@ -2399,11 +2416,6 @@ class StaffDetailView(LoginRequiredMixin, DetailView): -def dealer_vat_rate_update(request, slug): - dealer = get_object_or_404(models.Dealer, slug=slug) - models.VatRate.objects.filter(dealer=dealer).update(rate=request.POST.get("rate")) - messages.success(request, _("VAT rate updated successfully")) - return redirect("dealer_detail", slug=slug) class CustomerListView(LoginRequiredMixin, PermissionRequiredMixin, ListView): diff --git a/static/images/car_images/29e73964e0b1d9d4c15581e2bb2635518d0e859b8662e6c046cff9b24f8053c0.png b/static/images/car_images/29e73964e0b1d9d4c15581e2bb2635518d0e859b8662e6c046cff9b24f8053c0.png new file mode 100644 index 00000000..e213d619 Binary files /dev/null and b/static/images/car_images/29e73964e0b1d9d4c15581e2bb2635518d0e859b8662e6c046cff9b24f8053c0.png differ diff --git a/staticfiles/images/car_images/29e73964e0b1d9d4c15581e2bb2635518d0e859b8662e6c046cff9b24f8053c0.png b/staticfiles/images/car_images/29e73964e0b1d9d4c15581e2bb2635518d0e859b8662e6c046cff9b24f8053c0.png new file mode 100644 index 00000000..e213d619 Binary files /dev/null and b/staticfiles/images/car_images/29e73964e0b1d9d4c15581e2bb2635518d0e859b8662e6c046cff9b24f8053c0.png differ diff --git a/templates/crm/leads/lead_detail.html b/templates/crm/leads/lead_detail.html index a52d691f..263d2024 100644 --- a/templates/crm/leads/lead_detail.html +++ b/templates/crm/leads/lead_detail.html @@ -804,6 +804,8 @@ + + {% include 'modal/delete_modal.html' %} {% include "components/email_modal.html" %}