update customer and organization & staffmember

This commit is contained in:
gitea 2025-03-02 12:18:32 +00:00
parent 21089f8995
commit a96b1131d3
7 changed files with 253 additions and 221 deletions

View File

@ -1,5 +1,5 @@
from django.core.cache import cache from django.core.cache import cache
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.auth.models import Group from django.contrib.auth.models import Group
from appointment.models import Appointment, Service, StaffMember from appointment.models import Appointment, Service, StaffMember
from django.urls import reverse from django.urls import reverse
@ -39,14 +39,14 @@ from .models import (
InteriorColors, InteriorColors,
# SaleQuotation, # SaleQuotation,
CarLocation, CarLocation,
Representative, Representative,
# SaleQuotationCar, # SaleQuotationCar,
AdditionalServices, AdditionalServices,
Staff, Staff,
Opportunity, Opportunity,
Lead, Lead,
Activity, Activity,
Notes, Notes,
@ -56,7 +56,7 @@ from .models import (
DealerSettings DealerSettings
) )
from django_ledger import models as ledger_models from django_ledger import models as ledger_models
from django.forms import ( from django.forms import (
DateInput, DateInput,
DateTimeInput, DateTimeInput,
) )
@ -86,7 +86,7 @@ class StaffForm(forms.ModelForm):
label="Email", label="Email",
widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}), widget=forms.EmailInput(attrs={"class": "form-control form-control-sm"}),
) )
service_offered = forms.ModelMultipleChoiceField( service_offered = forms.ModelMultipleChoiceField(
label="Services Offered", label="Services Offered",
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}), widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
@ -130,22 +130,17 @@ class DealerForm(forms.ModelForm):
class CustomerForm(forms.Form): class CustomerForm(forms.Form):
first_name = forms.CharField() first_name = forms.CharField()
middle_name = forms.CharField()
last_name = forms.CharField() last_name = forms.CharField()
national_id = forms.CharField(max_length=10)
email = forms.EmailField()
phone_number = PhoneNumberField(region="SA")
address = forms.CharField()
class OrganizationForm(forms.Form):
name = forms.CharField()
arabic_name = forms.CharField() arabic_name = forms.CharField()
email = forms.EmailField() email = forms.EmailField()
phone_number = PhoneNumberField(region="SA") phone_number = PhoneNumberField(region="SA")
crn = forms.CharField() national_id = forms.CharField(max_length=10,required=False)
vrn = forms.CharField() crn = forms.CharField(required=False)
vrn = forms.CharField(required=False)
address = forms.CharField() address = forms.CharField()
class OrganizationForm(CustomerForm):
contact_person = forms.CharField(required=False) contact_person = forms.CharField(required=False)
logo = forms.ImageField(required=False) logo = forms.ImageField(required=False)
@ -448,7 +443,7 @@ class CarSelectionTable(tables.Table):
class WizardForm1(forms.Form): class WizardForm1(forms.Form):
hx_attrs = { hx_attrs = {
"hx-post":"", "hx-post":"",
"hx-target": "#wizardValidationForm1", "hx-target": "#wizardValidationForm1",
"hx-select": "#wizardValidationForm1", "hx-select": "#wizardValidationForm1",
@ -516,10 +511,10 @@ class WizardForm1(forms.Form):
), ),
error_messages={ error_messages={
"required": _("You must accept the terms and privacy policy."), "required": _("You must accept the terms and privacy policy."),
}, },
) )
def clean_email(self): def clean_email(self):
email = self.cleaned_data.get("email") email = self.cleaned_data.get("email")
if email: if email:
@ -528,7 +523,7 @@ class WizardForm1(forms.Form):
_("An account with this email already exists.") _("An account with this email already exists.")
) )
return email return email
def clean_confirm_password(self): def clean_confirm_password(self):
password = self.cleaned_data.get("password") password = self.cleaned_data.get("password")
confirm_password = self.cleaned_data.get("confirm_password") confirm_password = self.cleaned_data.get("confirm_password")
@ -569,7 +564,7 @@ class WizardForm2(forms.Form):
phone_number = PhoneNumberField( phone_number = PhoneNumberField(
label=_("Phone Number"), label=_("Phone Number"),
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
"placeholder": _("Phone"), "placeholder": _("Phone"),
} }
), ),
@ -578,7 +573,7 @@ class WizardForm2(forms.Form):
"required": _("This field is required."), "required": _("This field is required."),
"invalid": _("Phone number must be in the format 05xxxxxxxx"), "invalid": _("Phone number must be in the format 05xxxxxxxx"),
}, },
required=True, required=True,
) )
@ -741,6 +736,8 @@ class LeadForm(forms.ModelForm):
"address", "address",
"id_car_make", "id_car_make",
"id_car_model", "id_car_model",
"crn",
"vrn",
"year", "year",
"source", "source",
"channel", "channel",
@ -761,7 +758,7 @@ class LeadForm(forms.ModelForm):
class ScheduleForm(forms.ModelForm): class ScheduleForm(forms.ModelForm):
scheduled_at = forms.DateTimeField( scheduled_at = forms.DateTimeField(
widget=DateTimeInput(attrs={"type": "datetime-local"}) widget=DateTimeInput(attrs={"type": "datetime-local"})
) )
class Meta: class Meta:
model = Schedule model = Schedule
fields = ["purpose", "scheduled_type", "scheduled_at", "duration", "notes",] fields = ["purpose", "scheduled_type", "scheduled_at", "duration", "notes",]
@ -788,7 +785,7 @@ class OpportunityForm(forms.ModelForm):
class InvoiceModelCreateForm(InvoiceModelCreateFormBase): class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields["cash_account"].widget = forms.HiddenInput() self.fields["cash_account"].widget = forms.HiddenInput()
self.fields["prepaid_account"].widget = forms.HiddenInput() self.fields["prepaid_account"].widget = forms.HiddenInput()
self.fields["unearned_account"].widget = forms.HiddenInput() self.fields["unearned_account"].widget = forms.HiddenInput()
@ -806,7 +803,7 @@ class InvoiceModelCreateForm(InvoiceModelCreateFormBase):
class BillModelCreateForm(BillModelCreateFormBase): class BillModelCreateForm(BillModelCreateFormBase):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields["cash_account"].widget = forms.HiddenInput() self.fields["cash_account"].widget = forms.HiddenInput()
self.fields["prepaid_account"].widget = forms.HiddenInput() self.fields["prepaid_account"].widget = forms.HiddenInput()
self.fields["unearned_account"].widget = forms.HiddenInput() self.fields["unearned_account"].widget = forms.HiddenInput()
@ -877,8 +874,8 @@ class OpportunityStatusForm(forms.Form):
"hx-select": ".other-information", "hx-select": ".other-information",
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
"hx-on::after-request": "this.setAttribute('disabled','true')", "hx-on::after-request": "this.setAttribute('disabled','true')",
"disabled": "disabled", "disabled": "disabled",
} }
), ),
required=True, required=True,
) )
@ -887,7 +884,7 @@ class OpportunityStatusForm(forms.Form):
choices=Stage.choices, choices=Stage.choices,
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
"class": "form-control form-control-sm", "class": "form-control form-control-sm",
"hx-target": ".other-information", "hx-target": ".other-information",
"hx-select": ".other-information", "hx-select": ".other-information",
"hx-swap": "outerHTML", "hx-swap": "outerHTML",
@ -895,9 +892,9 @@ class OpportunityStatusForm(forms.Form):
"disabled": "disabled", "disabled": "disabled",
} }
), ),
required=True, required=True,
) )
class GroupForm(forms.ModelForm): class GroupForm(forms.ModelForm):
class Meta: class Meta:
model = CustomGroup model = CustomGroup
@ -912,11 +909,11 @@ class PermissionForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
cache.set('permissions_queryset', Permission.objects.filter(content_type__app_label__in=["inventory","django_ledger"]), 60*60) cache.set('permissions_queryset', Permission.objects.filter(content_type__app_label__in=["inventory","django_ledger"]), 60*60)
class Meta: class Meta:
model = Permission model = Permission
fields = ["name"] fields = ["name"]
class UserGroupForm(forms.ModelForm): class UserGroupForm(forms.ModelForm):
name = forms.ModelMultipleChoiceField( name = forms.ModelMultipleChoiceField(
queryset= CustomGroup.objects.all(), queryset= CustomGroup.objects.all(),
@ -927,10 +924,10 @@ class UserGroupForm(forms.ModelForm):
model = CustomGroup model = CustomGroup
fields = ["name"] fields = ["name"]
class DealerSettingsForm(forms.ModelForm): class DealerSettingsForm(forms.ModelForm):
class Meta: class Meta:
model = DealerSettings model = DealerSettings
fields = "__all__" fields = "__all__"
class LeadTransferForm(forms.Form): class LeadTransferForm(forms.Form):
transfer_to = forms.ModelChoiceField(label="to",queryset=Staff.objects.all()) transfer_to = forms.ModelChoiceField(label="to",queryset=Staff.objects.all())

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-03-01 21:22
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0052_lead_lead_type'),
]
operations = [
migrations.AddField(
model_name='lead',
name='crn',
field=models.CharField(blank=True, max_length=10, null=True, unique=True, verbose_name='Commercial Registration Number'),
),
migrations.AddField(
model_name='lead',
name='vrn',
field=models.CharField(blank=True, max_length=15, null=True, unique=True, verbose_name='VAT Registration Number'),
),
]

View File

@ -454,14 +454,14 @@ class Car(models.Model):
self.status = CarStatusChoices.SOLD self.status = CarStatusChoices.SOLD
self.save() self.save()
Activity.objects.create(dealer=dealer,content_object=self, notes="Car Sold",created_by=request.user,activity_type=ActionChoices.SALE_CAR) Activity.objects.create(dealer=dealer,content_object=self, notes="Car Sold",created_by=request.user,activity_type=ActionChoices.SALE_CAR)
def cancel_reservation(self): def cancel_reservation(self):
if self.reservations.exists(): if self.reservations.exists():
self.reservations.all().delete() self.reservations.all().delete()
def cancel_transfer(self): def cancel_transfer(self):
if self.transfer_logs.exists(): if self.transfer_logs.exists():
self.transfer_logs.all().delete() self.transfer_logs.all().delete()
def to_dict(self): def to_dict(self):
return { return {
"vin": self.vin, "vin": self.vin,
@ -580,9 +580,9 @@ class CarFinance(models.Model):
verbose_name=_("Discount Amount"), verbose_name=_("Discount Amount"),
default=Decimal("0.00"), default=Decimal("0.00"),
) )
@property @property
def total(self): def total(self):
return self.selling_price return self.selling_price
@property @property
@ -947,7 +947,7 @@ class StaffTypes(models.TextChoices):
class Staff(models.Model, LocalizedNameMixin): class Staff(models.Model, LocalizedNameMixin):
staff_member = models.OneToOneField(StaffMember, on_delete=models.CASCADE, related_name="staff") 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")) name = models.CharField(max_length=255, verbose_name=_("Name"))
arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name")) arabic_name = models.CharField(max_length=255, verbose_name=_("Arabic Name"))
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number")) phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
@ -957,23 +957,26 @@ class Staff(models.Model, LocalizedNameMixin):
objects = StaffUserManager() objects = StaffUserManager()
@property
def email(self):
return self.staff_member.user.email
@property @property
def user(self): def user(self):
return self.staff_member.user return self.staff_member.user
@property @property
def groups(self): def groups(self):
return [x.customgroup for x in self.user.groups.all()] return [x.customgroup for x in self.user.groups.all()]
def clear_groups(self): def clear_groups(self):
return self.user.groups.clear() return self.user.groups.clear()
def add_group(self,group): def add_group(self,group):
try: try:
self.user.groups.add(group) self.user.groups.add(group)
except Exception as e: except Exception as e:
pass pass
class Meta: class Meta:
verbose_name = _("Staff") verbose_name = _("Staff")
verbose_name_plural = _("Staff") verbose_name_plural = _("Staff")
@ -1197,6 +1200,12 @@ class Lead(models.Model):
channel = models.CharField( channel = models.CharField(
max_length=50, choices=Channel.choices, verbose_name=_("Channel") max_length=50, choices=Channel.choices, verbose_name=_("Channel")
) )
crn = models.CharField(
max_length=10, unique=True, verbose_name=_("Commercial Registration Number"), blank=True, null=True
)
vrn = models.CharField(
max_length=15, unique=True, verbose_name=_("VAT Registration Number"), blank=True, null=True
)
address = models.CharField(max_length=50, verbose_name=_("address")) address = models.CharField(max_length=50, verbose_name=_("address"))
staff = models.ForeignKey( staff = models.ForeignKey(
Staff, Staff,
@ -1251,7 +1260,7 @@ class Lead(models.Model):
@property @property
def full_name(self): def full_name(self):
return f"{self.first_name} {self.last_name}" return f"{self.first_name} {self.last_name}"
def convert_to_customer(self,entity): def convert_to_customer(self,entity,lead):
customer = entity.get_customers().filter(email=self.email).first() customer = entity.get_customers().filter(email=self.email).first()
if entity and not customer: if entity and not customer:
customer = entity.create_customer( customer = entity.create_customer(
@ -1262,10 +1271,13 @@ class Lead(models.Model):
"phone": self.phone_number, "phone": self.phone_number,
"email": self.email, "email": self.email,
} }
) )
customer.additional_info.update({"info":self.to_dict()}) customer.additional_info.update({"info":self.to_dict()})
customer.additional_info.update({"type":"customer"}) if lead.lead_type == "organization":
customer.additional_info.update({"type":"organization"})
else:
customer.additional_info.update({"type":"customer"})
customer.save() customer.save()
self.customer = customer self.customer = customer
self.status = Status.QUALIFIED self.status = Status.QUALIFIED
@ -1415,7 +1427,7 @@ class Email(models.Model):
from_email = models.TextField(verbose_name=_("From Email"),null=True,blank=True) from_email = models.TextField(verbose_name=_("From Email"),null=True,blank=True)
to_email = models.TextField(verbose_name=_("To Email"),null=True,blank=True) to_email = models.TextField(verbose_name=_("To Email"),null=True,blank=True)
subject = models.TextField(verbose_name=_("Subject"),null=True,blank=True) subject = models.TextField(verbose_name=_("Subject"),null=True,blank=True)
message = models.TextField(verbose_name=_("Message"),null=True,blank=True) message = models.TextField(verbose_name=_("Message"),null=True,blank=True)
status = models.CharField(max_length=20, choices=EmailStatus.choices, verbose_name=_("Status"),default=EmailStatus.OPEN) status = models.CharField(max_length=20, choices=EmailStatus.choices, verbose_name=_("Status"),default=EmailStatus.OPEN)
created_by = models.ForeignKey( created_by = models.ForeignKey(
User, on_delete=models.DO_NOTHING, related_name="emails_created" User, on_delete=models.DO_NOTHING, related_name="emails_created"
@ -1749,7 +1761,7 @@ class UserActivityLog(models.Model):
def __str__(self): def __str__(self):
return f"{self.user.email} - {self.action} - {self.timestamp}" return f"{self.user.email} - {self.action} - {self.timestamp}"
class SaleOrder(models.Model): class SaleOrder(models.Model):
estimate = models.ForeignKey( estimate = models.ForeignKey(
EstimateModel, EstimateModel,
on_delete=models.CASCADE, on_delete=models.CASCADE,
@ -1772,12 +1784,12 @@ class SaleOrder(models.Model):
comments = models.TextField(blank=True, null=True) comments = models.TextField(blank=True, null=True)
formatted_order_id = models.CharField(max_length=10, unique=True, editable=False) formatted_order_id = models.CharField(max_length=10, unique=True, editable=False)
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
class Meta: class Meta:
ordering = ['-created'] ordering = ['-created']
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if not self.formatted_order_id: if not self.formatted_order_id:
last_order = SaleOrder.objects.order_by('-id').first() last_order = SaleOrder.objects.order_by('-id').first()
if last_order: if last_order:
next_id = last_order.id + 1 next_id = last_order.id + 1
@ -1792,17 +1804,17 @@ class SaleOrder(models.Model):
@property @property
def full_name(self): def full_name(self):
return f"{self.customer.customer_name}" return f"{self.customer.customer_name}"
@property @property
def price(self): def price(self):
return self.car.finances.selling_price return self.car.finances.selling_price
@property @property
def items(self): def items(self):
if self.estimate.get_itemtxs_data(): if self.estimate.get_itemtxs_data():
return self.estimate.get_itemtxs_data()[0] return self.estimate.get_itemtxs_data()[0]
return [] return []
@property @property
def customer(self): def customer(self):
return self.estimate.customer return self.estimate.customer
@ -1811,27 +1823,27 @@ class CustomGroup(models.Model):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="groups") dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="groups")
group = models.OneToOneField("auth.Group", verbose_name=_(""), on_delete=models.CASCADE) group = models.OneToOneField("auth.Group", verbose_name=_(""), on_delete=models.CASCADE)
@property @property
def users(self): def users(self):
return self.group.user_set.all() return self.group.user_set.all()
@property @property
def permissions(self): def permissions(self):
return self.group.permissions.all() return self.group.permissions.all()
def clear_permissions(self): def clear_permissions(self):
self.group.permissions.clear() self.group.permissions.clear()
def add_permission(self, permission): def add_permission(self, permission):
try: try:
self.group.permissions.add(permission) self.group.permissions.add(permission)
except Permission.DoesNotExist: except Permission.DoesNotExist:
pass pass
def __str__(self): def __str__(self):
return self.name return self.name
def set_default_manager_permissions(self): def set_default_manager_permissions(self):
self.clear_permissions() self.clear_permissions()
try: try:
@ -1839,7 +1851,7 @@ class CustomGroup(models.Model):
self.add_permission(perm) self.add_permission(perm)
except Exception as e: except Exception as e:
pass pass
# def set_default_inventory_permissions(self): # def set_default_inventory_permissions(self):
# self.clear_permissions() # self.clear_permissions()
# allowed_models = ["car","carequipment","interiorcolors","exteriorcolors","carcolors","carlocation","customcard"] # allowed_models = ["car","carequipment","interiorcolors","exteriorcolors","carcolors","carlocation","customcard"]
@ -1849,14 +1861,14 @@ class CustomGroup(models.Model):
# allowed_models = ["car","carfinance","carlocation","customcard"] # allowed_models = ["car","carfinance","carlocation","customcard"]
# allowed_models_ledger = ["accountmodel","chartofaccountmodel","customcard","billmodel"] # allowed_models_ledger = ["accountmodel","chartofaccountmodel","customcard","billmodel"]
# self.set_permissions(allowed_models=allowed_models,other_perms=['view_carfinance']) # self.set_permissions(allowed_models=allowed_models,other_perms=['view_carfinance'])
# self.set_permissions(app="django_ledger",allowed_models=allowed_models_ledger) # self.set_permissions(app="django_ledger",allowed_models=allowed_models_ledger)
def set_default_permissions(self): def set_default_permissions(self):
self.clear_permissions() self.clear_permissions()
if self.name == "Manager": if self.name == "Manager":
self.set_permissions(app="inventory",allowed_models=["car","carfinance","carlocation","customcard"]) self.set_permissions(app="inventory",allowed_models=["car","carfinance","carlocation","customcard"])
self.set_permissions(app="django_ledger",allowed_models=["accountmodel","chartofaccountmodel","customcard","billmodel"]) self.set_permissions(app="django_ledger",allowed_models=["accountmodel","chartofaccountmodel","customcard","billmodel"])
elif self.name == "Inventory": elif self.name == "Inventory":
self.set_permissions(allowed_models=["car","carequipment","interiorcolors","exteriorcolors","carcolors","carlocation","customcard"] self.set_permissions(allowed_models=["car","carequipment","interiorcolors","exteriorcolors","carcolors","carlocation","customcard"]
,other_perms=['view_carfinance']) ,other_perms=['view_carfinance'])
elif self.name == "Sales": elif self.name == "Sales":
@ -1869,9 +1881,9 @@ class CustomGroup(models.Model):
elif self.name == "Agent": elif self.name == "Agent":
# Todo : set permissions for agent # Todo : set permissions for agent
pass pass
def set_permissions(self,app="inventory", allowed_models=[],other_perms=[]):
def set_permissions(self,app="inventory", allowed_models=[],other_perms=[]):
try: try:
for perm in Permission.objects.filter(content_type__app_label=app,content_type__model__in=allowed_models): for perm in Permission.objects.filter(content_type__app_label=app,content_type__model__in=allowed_models):
self.add_permission(perm) self.add_permission(perm)
@ -1880,19 +1892,19 @@ class CustomGroup(models.Model):
self.add_permission(perm) self.add_permission(perm)
except Exception as e: except Exception as e:
pass pass
class DealerSettings(models.Model):
dealer = models.OneToOneField(Dealer, on_delete=models.CASCADE, related_name="settings",null=True, blank=True)
class DealerSettings(models.Model):
dealer = models.OneToOneField(Dealer, on_delete=models.CASCADE, related_name="settings",null=True, blank=True)
invoice_cash_account = models.ForeignKey(AccountModel,related_name="invoice_cash", on_delete=models.SET_NULL, null=True, blank=True) invoice_cash_account = models.ForeignKey(AccountModel,related_name="invoice_cash", on_delete=models.SET_NULL, null=True, blank=True)
invoice_prepaid_account = models.ForeignKey(AccountModel,related_name="invoice_prepaid", on_delete=models.SET_NULL, null=True, blank=True) invoice_prepaid_account = models.ForeignKey(AccountModel,related_name="invoice_prepaid", on_delete=models.SET_NULL, null=True, blank=True)
invoice_unearned_account = models.ForeignKey(AccountModel,related_name="invoice_unearned", on_delete=models.SET_NULL, null=True, blank=True) invoice_unearned_account = models.ForeignKey(AccountModel,related_name="invoice_unearned", on_delete=models.SET_NULL, null=True, blank=True)
bill_cash_account = models.ForeignKey(AccountModel,related_name="bill_cash", on_delete=models.SET_NULL, null=True, blank=True) bill_cash_account = models.ForeignKey(AccountModel,related_name="bill_cash", on_delete=models.SET_NULL, null=True, blank=True)
bill_prepaid_account = models.ForeignKey(AccountModel,related_name="bill_prepaid", on_delete=models.SET_NULL, null=True, blank=True) bill_prepaid_account = models.ForeignKey(AccountModel,related_name="bill_prepaid", on_delete=models.SET_NULL, null=True, blank=True)
bill_unearned_account = models.ForeignKey(AccountModel,related_name="bill_unearned", on_delete=models.SET_NULL, null=True, blank=True) bill_unearned_account = models.ForeignKey(AccountModel,related_name="bill_unearned", on_delete=models.SET_NULL, null=True, blank=True)
additional_info = models.JSONField(default=dict,null=True,blank=True) additional_info = models.JSONField(default=dict,null=True,blank=True)
def __str__(self): def __str__(self):
return f"Settings for {self.dealer}" return f"Settings for {self.dealer}"

View File

@ -10,7 +10,7 @@ from calendar import month_name
from pyzbar.pyzbar import decode from pyzbar.pyzbar import decode
from urllib.parse import urlparse, urlunparse from urllib.parse import urlparse, urlunparse
##################################################################### #####################################################################
from django.db.models.deletion import RestrictedError from django.db.models.deletion import RestrictedError
# Django # Django
from django.db.models import Q from django.db.models import Q
from django.conf import settings from django.conf import settings
@ -28,7 +28,7 @@ from django.db.models import Count, F, Value
from django.urls import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.utils import timezone, translation from django.utils import timezone, translation
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
@ -137,7 +137,7 @@ logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
class Hash(Func): class Hash(Func):
function = 'get_hash' function = 'get_hash'
def switch_language(request): def switch_language(request):
language = request.GET.get("language", "en") language = request.GET.get("language", "en")
@ -179,12 +179,12 @@ def dealer_signup(request, *args, **kwargs):
form1 = forms.WizardForm1() form1 = forms.WizardForm1()
form2 = forms.WizardForm2() form2 = forms.WizardForm2()
form3 = forms.WizardForm3() form3 = forms.WizardForm3()
if request.method == "POST": if request.method == "POST":
if "Hx-Request" in request.headers: if "Hx-Request" in request.headers:
form1 = forms.WizardForm1(request.POST) form1 = forms.WizardForm1(request.POST)
return render(request,"account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3}) return render(request,"account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3})
data = json.loads(request.body) data = json.loads(request.body)
wf1 = data.get("wizardValidationForm1") wf1 = data.get("wizardValidationForm1")
wf2 = data.get("wizardValidationForm2") wf2 = data.get("wizardValidationForm2")
@ -207,7 +207,7 @@ def dealer_signup(request, *args, **kwargs):
user = User.objects.create(username=email, email=email) user = User.objects.create(username=email, email=email)
user.set_password(password) user.set_password(password)
user.save() user.save()
StaffMember.objects.create(user=user)
models.Dealer.objects.create( models.Dealer.objects.create(
user=user, user=user,
name=name, name=name,
@ -219,7 +219,7 @@ def dealer_signup(request, *args, **kwargs):
) )
return JsonResponse( return JsonResponse(
{"message": "User created successfully."}, status=200 {"message": "User created successfully."}, status=200
) )
except Exception as e: except Exception as e:
return JsonResponse({"error": str(e)}, status=400) return JsonResponse({"error": str(e)}, status=400)
return render(request,"account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3}) return render(request,"account/signup-wizard.html",{"form1": form1, "form2": form2, "form3": form3})
@ -309,7 +309,6 @@ class HomeView(TemplateView):
"total_selling_price": 0, "total_selling_price": 0,
"total_profit": 0, "total_profit": 0,
}) })
return context return context
class TestView(TemplateView): class TestView(TemplateView):
@ -516,7 +515,7 @@ class AjaxHandlerView(LoginRequiredMixin, View):
logger.info( logger.info(
f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}" f"VIN decoded using {decoding_method}: Make={manufacturer_name}, Model={model_name}, Year={year_model}"
) )
if not car_make: if not car_make:
return JsonResponse( return JsonResponse(
@ -724,7 +723,7 @@ class CarColorCreate(LoginRequiredMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
car = get_object_or_404(models.Car, pk=self.kwargs["car_pk"]) car = get_object_or_404(models.Car, pk=self.kwargs["car_pk"])
form.instance.car = car form.instance.car = car
return super().form_valid(form) return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
@ -744,7 +743,7 @@ class CarListView(LoginRequiredMixin, ListView):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
cars = models.Car.objects.filter(dealer=dealer).order_by("receiving_date") cars = models.Car.objects.filter(dealer=dealer).order_by("receiving_date")
context["stats"] = { context["stats"] = {
'all': cars.count(), 'all': cars.count(),
'available':cars.filter(status='available').count(), 'available':cars.filter(status='available').count(),
@ -764,19 +763,19 @@ class CarListView(LoginRequiredMixin, ListView):
if make and model: if make and model:
make_ = models.CarMake.objects.get(id_car_make=int(make)) make_ = models.CarMake.objects.get(id_car_make=int(make))
model_ = models.CarModel.objects.get(id_car_model=int(model)) model_ = models.CarModel.objects.get(id_car_model=int(model))
context['year'] = models.Car.objects.filter(id_car_make=make_,id_car_model=model_).values_list('year').distinct() context['year'] = models.Car.objects.filter(id_car_make=make_,id_car_model=model_).values_list('year').distinct()
return context return context
def get_queryset(self): def get_queryset(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
qs = super().get_queryset() qs = super().get_queryset()
qs = qs.filter(dealer=dealer) qs = qs.filter(dealer=dealer)
status = self.request.GET.get('status') status = self.request.GET.get('status')
search = self.request.GET.get('search') search = self.request.GET.get('search')
make = self.request.GET.get('make',None) make = self.request.GET.get('make',None)
model = self.request.GET.get('model',None) model = self.request.GET.get('model',None)
year = self.request.GET.get('year',None) year = self.request.GET.get('year',None)
car_status = self.request.GET.get('car_status',None) car_status = self.request.GET.get('car_status',None)
if status: if status:
qs=qs.filter(status=status) qs=qs.filter(status=status)
if search: if search:
@ -791,7 +790,7 @@ class CarListView(LoginRequiredMixin, ListView):
if year: if year:
query &= Q(year=year) query &= Q(year=year)
if car_status: if car_status:
query &= Q(status=car_status) query &= Q(status=car_status)
qs = qs.filter(query) qs = qs.filter(query)
return qs return qs
@ -1247,14 +1246,14 @@ class CustomerDetailView(LoginRequiredMixin, DetailView):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
entity = dealer.entity entity = dealer.entity
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
estimates = entity.get_estimates().filter(customer=self.object) estimates = entity.get_estimates().filter(customer=self.object)
invoices = entity.get_invoices().filter(customer=self.object) invoices = entity.get_invoices().filter(customer=self.object)
# txs = entity. transactions(customer=self.object) # txs = entity. transactions(customer=self.object)
total = estimates.count() + invoices.count() total = estimates.count() + invoices.count()
context["estimates"] = estimates context["estimates"] = estimates
context["invoices"] = invoices context["invoices"] = invoices
context["total"] = total context["total"] = total
return context return context
def add_note_to_customer(request, customer_id): def add_note_to_customer(request, customer_id):
@ -1296,14 +1295,13 @@ def CustomerCreateView(request):
form = forms.CustomerForm(request.POST) form = forms.CustomerForm(request.POST)
dealer = get_user_type(request) dealer = get_user_type(request)
if form.is_valid(): if form.is_valid():
if dealer.entity.get_customers().filter(email=form.cleaned_data["email"]).exists(): if dealer.entity.get_customers().filter(email=form.cleaned_data["email"]).exists():
messages.error(request, _("Customer with this email already exists.")) messages.error(request, _("Customer with this email already exists."))
else: else:
# Create customer name # Create customer name
customer_name = ( customer_name = (
f"{form.cleaned_data['first_name']} " f"{form.cleaned_data['first_name']} "
f"{form.cleaned_data['middle_name']} "
f"{form.cleaned_data['last_name']}" f"{form.cleaned_data['last_name']}"
) )
customer_dict = { x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"} customer_dict = { x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"}
@ -1346,8 +1344,6 @@ def CustomerUpdateView(request, pk):
customer_name = ( customer_name = (
customer_dict["first_name"] customer_dict["first_name"]
+ " " + " "
+ customer_dict["middle_name"]
+ " "
+ customer_dict["last_name"] + customer_dict["last_name"]
) )
@ -1367,7 +1363,7 @@ def CustomerUpdateView(request, pk):
user.save() user.save()
except Exception as e: except Exception as e:
raise Exception(e) raise Exception(e)
instance.save() instance.save()
messages.success(request, _("Customer updated successfully.")) messages.success(request, _("Customer updated successfully."))
return redirect("customer_list") return redirect("customer_list")
@ -1384,12 +1380,12 @@ def CustomerUpdateView(request, pk):
@login_required @login_required
def delete_customer(request, pk): def delete_customer(request, pk):
customer = get_object_or_404(models.CustomerModel, pk=pk) customer = get_object_or_404(models.CustomerModel, pk=pk)
user = User.objects.get(email=customer.email) user = User.objects.get(email=customer.email)
customer.active = False customer.active = False
user.is_active = False user.is_active = False
customer.save() customer.save()
user.save() user.save()
messages.success(request, _("Customer deleted successfully.")) messages.success(request, _("Customer deleted successfully."))
return redirect("customer_list") return redirect("customer_list")
@ -1457,15 +1453,15 @@ class GroupListView(LoginRequiredMixin, ListView):
paginate_by = 10 paginate_by = 10
template_name = "groups/group_list.html" template_name = "groups/group_list.html"
def get_queryset(self): def get_queryset(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return dealer.groups.all() return dealer.groups.all()
class GroupDetailView(LoginRequiredMixin, DetailView): class GroupDetailView(LoginRequiredMixin, DetailView):
model = models.CustomGroup model = models.CustomGroup
template_name = "groups/group_detail.html" template_name = "groups/group_detail.html"
context_object_name = "group" context_object_name = "group"
class GroupCreateView( class GroupCreateView(
LoginRequiredMixin, LoginRequiredMixin,
@ -1501,7 +1497,7 @@ class GroupUpdateView(
def form_valid(self, form): def form_valid(self, form):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
instance = form.save(commit=False) instance = form.save(commit=False)
instance.group.name = f"{dealer.pk}_{instance.name}" instance.group.name = f"{dealer.pk}_{instance.name}"
instance.save() instance.save()
return super().form_valid(form) return super().form_valid(form)
@ -1521,7 +1517,7 @@ def GroupPermissionView(request, pk):
for i in permissions: for i in permissions:
group.add_permission(Permission.objects.get(id=int(i))) group.add_permission(Permission.objects.get(id=int(i)))
messages.success(request, _("Permission added successfully.")) messages.success(request, _("Permission added successfully."))
return redirect("group_detail", pk=group.pk) return redirect("group_detail", pk=group.pk)
form = forms.PermissionForm(initial={"name": group.permissions}) form = forms.PermissionForm(initial={"name": group.permissions})
return render(request,"groups/group_permission_form.html",{"group": group, "form": form}) return render(request,"groups/group_permission_form.html",{"group": group, "form": form})
@ -1529,18 +1525,18 @@ def GroupPermissionView(request, pk):
def UserGroupView(request, pk): def UserGroupView(request, pk):
staff = get_object_or_404(models.Staff, pk=pk) staff = get_object_or_404(models.Staff, pk=pk)
if request.method == "POST": if request.method == "POST":
form = forms.UserGroupForm(request.POST) form = forms.UserGroupForm(request.POST)
groups = request.POST.getlist("name") groups = request.POST.getlist("name")
staff.clear_groups() staff.clear_groups()
for i in groups: for i in groups:
cg = models.CustomGroup.objects.get(id=int(i)) cg = models.CustomGroup.objects.get(id=int(i))
staff.add_group(cg.group) staff.add_group(cg.group)
messages.success(request, _("Group added successfully.")) messages.success(request, _("Group added successfully."))
return redirect("user_detail", pk=staff.pk) return redirect("user_detail", pk=staff.pk)
form = forms.UserGroupForm(initial={"name": staff.groups}) form = forms.UserGroupForm(initial={"name": staff.groups})
form.fields['name'].queryset = models.CustomGroup.objects.filter(dealer=staff.dealer) form.fields['name'].queryset = models.CustomGroup.objects.filter(dealer=staff.dealer)
return render(request,"users/user_group_form.html",{"staff": staff, "form": form}) return render(request,"users/user_group_form.html",{"staff": staff, "form": form})
@ -1591,7 +1587,7 @@ class UserCreateView(
email = form.cleaned_data["email"] email = form.cleaned_data["email"]
password = "Tenhal@123" password = "Tenhal@123"
user = User.objects.create_user(username=form.cleaned_data["name"], email=email, password=password) user = User.objects.create_user(username=form.cleaned_data["name"], email=email, password=password)
user.is_staff = True user.is_staff = True
user.save() user.save()
@ -1606,7 +1602,7 @@ class UserCreateView(
staff.add_group(group) staff.add_group(group)
staff.save() staff.save()
return super().form_valid(form) return super().form_valid(form)
class UserUpdateView( class UserUpdateView(
LoginRequiredMixin, LoginRequiredMixin,
@ -1629,7 +1625,7 @@ class UserUpdateView(
form.fields['email'].disabled = True form.fields['email'].disabled = True
return form return form
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
initial['email'] = self.object.staff_member.user.email initial['email'] = self.object.staff_member.user.email
initial['service_offered'] = self.object.staff_member.services_offered.all() initial['service_offered'] = self.object.staff_member.services_offered.all()
return initial return initial
@ -1639,16 +1635,16 @@ class UserUpdateView(
self.object.staff_member.services_offered.clear() self.object.staff_member.services_offered.clear()
else: else:
for service in services: for service in services:
self.object.staff_member.services_offered.add(service) self.object.staff_member.services_offered.add(service)
staff = form.save(commit=False) staff = form.save(commit=False)
staff.name = form.cleaned_data["name"] staff.name = form.cleaned_data["name"]
staff.arabic_name = form.cleaned_data["arabic_name"] staff.arabic_name = form.cleaned_data["arabic_name"]
staff.phone_number = form.cleaned_data["phone_number"] staff.phone_number = form.cleaned_data["phone_number"]
staff.staff_type = form.cleaned_data["staff_type"] staff.staff_type = form.cleaned_data["staff_type"]
staff.save() staff.save()
return super().form_valid(form) return super().form_valid(form)
def UserDeleteview(request, pk): def UserDeleteview(request, pk):
staff = get_object_or_404(models.Staff, pk=pk) staff = get_object_or_404(models.Staff, pk=pk)
staff.staff_member.delete() staff.staff_member.delete()
@ -1700,15 +1696,16 @@ def OrganizationCreateView(request):
if CustomerModel.objects.filter(email=request.POST["email"]).exists(): if CustomerModel.objects.filter(email=request.POST["email"]).exists():
messages.error(request, _("An organization with this email already exists.")) messages.error(request, _("An organization with this email already exists."))
return redirect("organization_create") return redirect("organization_create")
organization_dict = { organization_dict = {
x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken" x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"
} }
dealer = get_user_type(request) dealer = get_user_type(request)
name = organization_dict["first_name"] + " " + organization_dict["last_name"]
instance = dealer.entity.create_customer( customer = dealer.entity.create_customer(
commit=False,
customer_model_kwargs={ customer_model_kwargs={
"customer_name": organization_dict["name"], "customer_name": name,
"address_1": organization_dict["address"], "address_1": organization_dict["address"],
"phone": organization_dict["phone_number"], "phone": organization_dict["phone_number"],
"email": organization_dict["email"], "email": organization_dict["email"],
@ -1718,12 +1715,12 @@ def OrganizationCreateView(request):
if image: if image:
file_name = default_storage.save("images/{}".format(image.name), image) file_name = default_storage.save("images/{}".format(image.name), image)
file_url = default_storage.url(file_name) file_url = default_storage.url(file_name)
organization_dict["logo"] = file_url organization_dict["logo"] = file_url
organization_dict["pk"] = str(instance.pk) organization_dict["pk"] = str(customer.pk)
instance.additional_info["organization_info"] = organization_dict customer.additional_info.update({"customer_info": organization_dict})
instance.additional_info["type"] = "organization" customer.additional_info.update({"type": "organization"})
instance.save() customer.save()
messages.success(request, _("Organization created successfully.")) messages.success(request, _("Organization created successfully."))
return redirect("organization_list") return redirect("organization_list")
else: else:
@ -1732,44 +1729,45 @@ def OrganizationCreateView(request):
def OrganizationUpdateView(request,pk): def OrganizationUpdateView(request,pk):
organization = get_object_or_404(CustomerModel, pk=pk) organization = get_object_or_404(CustomerModel, pk=pk)
if request.method == "POST": if request.method == "POST":
form = forms.OrganizationForm(request.POST) form = forms.OrganizationForm(request.POST)
organization_dict = { organization_dict = {
x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken" x: request.POST[x] for x in request.POST if x != "csrfmiddlewaretoken"
} }
dealer = get_user_type(request) dealer = get_user_type(request)
instance = dealer.entity.get_customers().get( instance = dealer.entity.get_customers().get(
pk=organization.additional_info["organization_info"]["pk"] pk=organization.additional_info["customer_info"]["pk"]
) )
instance.customer_name = organization_dict["name"] name = organization_dict["first_name"] + " " + organization_dict["last_name"]
instance.customer_name = name
instance.address_1 = organization_dict["address"] instance.address_1 = organization_dict["address"]
instance.phone = organization_dict["phone_number"] instance.phone = organization_dict["phone_number"]
instance.email = organization_dict["email"] instance.email = organization_dict["email"]
image = request.FILES.get("logo") image = request.FILES.get("logo")
if image: if image:
file_name = default_storage.save("images/{}".format(image.name), image) file_name = default_storage.save("images/{}".format(image.name), image)
file_url = default_storage.url(file_name) file_url = default_storage.url(file_name)
organization_dict["logo"] = file_url organization_dict["logo"] = file_url
else: else:
organization_dict["logo"] = organization.additional_info["organization_info"]["logo"] organization_dict["logo"] = organization.additional_info["customer_info"]["logo"]
organization_dict["pk"] = str(instance.pk) organization_dict["pk"] = str(instance.pk)
instance.additional_info["organization_info"] = organization_dict instance.additional_info["customer_info"] = organization_dict
instance.additional_info["type"] = "organization" instance.additional_info["type"] = "organization"
instance.save() instance.save()
messages.success(request, _("Organization created successfully.")) messages.success(request, _("Organization created successfully."))
return redirect("organization_list") return redirect("organization_list")
else: else:
form = forms.OrganizationForm( form = forms.OrganizationForm(
initial=organization.additional_info["organization_info"] or {} initial=organization.additional_info["customer_info"] or {}
) )
# form.fields.pop("logo", None) # form.fields.pop("logo", None)
return render(request, "organizations/organization_form.html", {"form": form}) return render(request, "organizations/organization_form.html", {"form": form})
# class OrganizationDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView): # class OrganizationDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
# model = models.Organization # model = models.Organization
@ -2047,7 +2045,7 @@ def create_estimate(request,pk=None):
dealer = get_user_type(request) dealer = get_user_type(request)
entity = dealer.entity entity = dealer.entity
if request.method == "POST": if request.method == "POST":
# try: # try:
data = json.loads(request.body) data = json.loads(request.body)
title = data.get("title") title = data.get("title")
@ -2057,13 +2055,13 @@ def create_estimate(request,pk=None):
items = data.get("item", []) items = data.get("item", [])
quantities = data.get("quantity", []) quantities = data.get("quantity", [])
if not all([items, quantities]): if not all([items, quantities]):
return JsonResponse( return JsonResponse(
{"status": "error", "message": "Items and Quantities are required"}, {"status": "error", "message": "Items and Quantities are required"},
status=400, status=400,
) )
if isinstance(quantities, list): if isinstance(quantities, list):
if "0" in quantities: if "0" in quantities:
return JsonResponse( return JsonResponse(
@ -2084,7 +2082,7 @@ def create_estimate(request,pk=None):
if int(quantities) > models.Car.objects.filter(hash=items,status='available').count(): if int(quantities) > models.Car.objects.filter(hash=items,status='available').count():
return JsonResponse( return JsonResponse(
{"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"}, {"status": "error", "message": "Quantity must be less than or equal to the number of cars in stock"},
) )
estimate = entity.create_estimate( estimate = entity.create_estimate(
estimate_title=title, customer_model=customer, contract_terms=terms estimate_title=title, customer_model=customer, contract_terms=terms
) )
@ -2105,7 +2103,7 @@ def create_estimate(request,pk=None):
items_txs = [] items_txs = []
for item in items_list: for item in items_list:
car_instance = ItemModel.objects.filter(additional_info__car_info__hash=item.get("item_id")).all() car_instance = ItemModel.objects.filter(additional_info__car_info__hash=item.get("item_id")).all()
for i in car_instance[:int(quantities[0])]: for i in car_instance[:int(quantities[0])]:
items_txs.append( items_txs.append(
{ {
@ -2148,19 +2146,19 @@ def create_estimate(request,pk=None):
for item in estimate_itemtxs.keys(): for item in estimate_itemtxs.keys():
item_instance = ItemModel.objects.filter(item_number=item).first() item_instance = ItemModel.objects.filter(item_number=item).first()
instance = models.Car.objects.get(vin=item_instance.name) instance = models.Car.objects.get(vin=item_instance.name)
reserve_car(instance, request) reserve_car(instance, request)
else: else:
item_instance = ItemModel.objects.filter(additioinal_info__car_info__hash=items).first() item_instance = ItemModel.objects.filter(additioinal_info__car_info__hash=items).first()
instance = models.Car.objects.get(hash=item) instance = models.Car.objects.get(hash=item)
response = reserve_car(instance, request) response = reserve_car(instance, request)
opportunity_id = data.get("opportunity_id") opportunity_id = data.get("opportunity_id")
if opportunity_id != "None": if opportunity_id != "None":
opportunity = models.Opportunity.objects.get(pk=int(opportunity_id)) opportunity = models.Opportunity.objects.get(pk=int(opportunity_id))
opportunity.estimate = estimate opportunity.estimate = estimate
opportunity.save() opportunity.save()
url = reverse("estimate_detail", kwargs={"pk": estimate.pk}) url = reverse("estimate_detail", kwargs={"pk": estimate.pk})
return JsonResponse( return JsonResponse(
{ {
@ -2174,14 +2172,14 @@ def create_estimate(request,pk=None):
entity_slug=entity.slug, user_model=entity.admin entity_slug=entity.slug, user_model=entity.admin
) )
form.fields["customer"].queryset = entity.get_customers().filter(active=True,additional_info__type="customer") form.fields["customer"].queryset = entity.get_customers().filter(active=True,additional_info__type="customer")
if pk: if pk:
opportunity = models.Opportunity.objects.get(pk=pk) opportunity = models.Opportunity.objects.get(pk=pk)
customer = opportunity.customer customer = opportunity.customer
form.initial['customer'] = customer form.initial['customer'] = customer
car_list = models.Car.objects.filter(dealer=dealer,colors__isnull=False,finances__isnull=False,status="available").annotate(color=F('colors__exterior__rgb'),color_name=F('colors__exterior__name')).values_list( car_list = models.Car.objects.filter(dealer=dealer,colors__isnull=False,finances__isnull=False,status="available").annotate(color=F('colors__exterior__rgb'),color_name=F('colors__exterior__name')).values_list(
'id_car_make__name', 'id_car_model__name','id_car_serie__name','id_car_trim__name','color','color_name','hash').annotate(hash_count=Count('hash')).distinct() 'id_car_make__name', 'id_car_model__name','id_car_serie__name','id_car_trim__name','color','color_name','hash').annotate(hash_count=Count('hash')).distinct()
context = { context = {
"form": form, "form": form,
"items": [ "items": [
@ -2200,7 +2198,7 @@ def create_estimate(request,pk=None):
"opportunity_id": pk if pk else None, "opportunity_id": pk if pk else None,
"customer_count": entity.get_customers().count() "customer_count": entity.get_customers().count()
} }
return render(request, "sales/estimates/estimate_form.html", context) return render(request, "sales/estimates/estimate_form.html", context)
@ -2214,7 +2212,7 @@ class EstimateDetailView(LoginRequiredMixin, DetailView):
if estimate.get_itemtxs_data(): if estimate.get_itemtxs_data():
calculator = CarFinanceCalculator(estimate) calculator = CarFinanceCalculator(estimate)
finance_data = calculator.get_finance_data() finance_data = calculator.get_finance_data()
kwargs["data"] = finance_data kwargs["data"] = finance_data
kwargs["invoice"] = ( kwargs["invoice"] = (
InvoiceModel.objects.all().filter(ce_model=estimate).first() InvoiceModel.objects.all().filter(ce_model=estimate).first()
@ -2238,10 +2236,10 @@ def create_sale_order(request, pk):
item.item_model.additional_info['car_info']['status'] = 'sold' item.item_model.additional_info['car_info']['status'] = 'sold'
item.item_model.save() item.item_model.save()
except KeyError: except KeyError:
pass pass
models.Car.objects.get(vin=item.item_model.name).mark_as_sold(request) models.Car.objects.get(vin=item.item_model.name).mark_as_sold(request)
messages.success(request, "Sale Order created successfully") messages.success(request, "Sale Order created successfully")
return redirect("estimate_detail", pk=pk) return redirect("estimate_detail", pk=pk)
form = forms.SaleOrderForm() form = forms.SaleOrderForm()
@ -2363,7 +2361,7 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView):
if invoice.get_itemtxs_data(): if invoice.get_itemtxs_data():
calculator = CarFinanceCalculator(invoice) calculator = CarFinanceCalculator(invoice)
finance_data = calculator.get_finance_data() finance_data = calculator.get_finance_data()
kwargs["data"] = finance_data kwargs["data"] = finance_data
kwargs["payments"] = JournalEntryModel.objects.filter( kwargs["payments"] = JournalEntryModel.objects.filter(
ledger=invoice.ledger ledger=invoice.ledger
@ -2464,10 +2462,10 @@ def invoice_create(request, pk):
ledger.save() ledger.save()
invoice.save() invoice.save()
calculator = CarFinanceCalculator(estimate) calculator = CarFinanceCalculator(estimate)
finance_data = calculator.get_finance_data() finance_data = calculator.get_finance_data()
invoice_itemtxs = { invoice_itemtxs = {
i.get("item_number"): { i.get("item_number"): {
"unit_cost": i.get("total_vat"), "unit_cost": i.get("total_vat"),
@ -2549,11 +2547,11 @@ def PaymentCreateView(request, pk):
messages.error(request,"fully paid") messages.error(request,"fully paid")
return redirect(redirect_url, pk=model.pk) return redirect(redirect_url, pk=model.pk)
if model.amount_paid + amount > model.amount_due: if model.amount_paid + amount > model.amount_due:
messages.error(request,"Amount exceeds due amount") messages.error(request,"Amount exceeds due amount")
return redirect(redirect_url, pk=model.pk) return redirect(redirect_url, pk=model.pk)
try: try:
if invoice: if invoice:
set_invoice_payment(dealer, entity, invoice, amount, payment_method) set_invoice_payment(dealer, entity, invoice, amount, payment_method)
elif bill: elif bill:
set_bill_payment(dealer, entity, bill, amount, payment_method) set_bill_payment(dealer, entity, bill, amount, payment_method)
@ -2703,9 +2701,9 @@ def lead_create(request):
if form.is_valid(): if form.is_valid():
instance = form.save(commit=False) instance = form.save(commit=False)
dealer = get_user_type(request) dealer = get_user_type(request)
instance.dealer = dealer instance.dealer = dealer
instance.staff = form.cleaned_data.get("staff") instance.staff = form.cleaned_data.get("staff")
# creating customer in ledger # creating customer in ledger
customer = dealer.entity.get_customers().filter(email=instance.email).first() customer = dealer.entity.get_customers().filter(email=instance.email).first()
if not customer: if not customer:
@ -2716,7 +2714,7 @@ def lead_create(request):
"address_1": instance.address, "address_1": instance.address,
"phone": instance.phone_number, "phone": instance.phone_number,
"email": instance.email, "email": instance.email,
"sales_tax_rate": 0.15, "sales_tax_rate": 0.15,
} }
) )
customer_info = { customer_info = {
@ -2725,7 +2723,9 @@ def lead_create(request):
"address": instance.address, "address": instance.address,
"phone_number": str(instance.phone_number), "phone_number": str(instance.phone_number),
"email": instance.email, "email": instance.email,
} "crn": form.cleaned_data["crn"],
"vrn": form.cleaned_data["vrn"],
}
customer.additional_info.update({"customer_info": customer_info }) customer.additional_info.update({"customer_info": customer_info })
customer.additional_info.update({"type":"lead"}) customer.additional_info.update({"type":"lead"})
customer.save() customer.save()
@ -2753,7 +2753,7 @@ class LeadUpdateView(UpdateView):
success_url = reverse_lazy("lead_list") success_url = reverse_lazy("lead_list")
def get_form(self, form_class=None): def get_form(self, form_class=None):
form = super().get_form(form_class) form = super().get_form(form_class)
form.fields["id_car_model"].queryset = form.instance.id_car_make.carmodel_set.all() form.fields["id_car_model"].queryset = form.instance.id_car_make.carmodel_set.all()
return form return form
@ -2761,7 +2761,7 @@ class LeadUpdateView(UpdateView):
@login_required @login_required
def LeadDeleteView(request,pk): def LeadDeleteView(request,pk):
lead = get_object_or_404(models.Lead, pk=pk) lead = get_object_or_404(models.Lead, pk=pk)
try: try:
User.objects.get(email=lead.customer.email).delete() User.objects.get(email=lead.customer.email).delete()
lead.customer.delete() lead.customer.delete()
except Exception as e: except Exception as e:
@ -2791,12 +2791,12 @@ def add_note_to_lead(request, pk):
def add_note_to_opportunity(request, pk): def add_note_to_opportunity(request, pk):
opportunity = get_object_or_404(models.Opportunity, pk=pk) opportunity = get_object_or_404(models.Opportunity, pk=pk)
if request.method == "POST": if request.method == "POST":
notes = request.POST.get("notes") notes = request.POST.get("notes")
if not notes: if not notes:
messages.error(request, "Notes field is required.") messages.error(request, "Notes field is required.")
else: else:
models.Notes.objects.create(content_object=opportunity, created_by=request.user,note=notes) models.Notes.objects.create(content_object=opportunity, created_by=request.user,note=notes)
messages.success(request, "Note added successfully!") messages.success(request, "Note added successfully!")
return redirect("opportunity_detail", pk=opportunity.pk) return redirect("opportunity_detail", pk=opportunity.pk)
@ -2835,8 +2835,8 @@ def lead_convert(request, pk):
dealer = get_user_type(request) dealer = get_user_type(request)
if hasattr(lead, "opportunity"): if hasattr(lead, "opportunity"):
messages.error(request, "Lead is already converted to customer.") messages.error(request, "Lead is already converted to customer.")
else: else:
customer = lead.convert_to_customer(dealer.entity) customer = lead.convert_to_customer(dealer.entity,lead)
models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.PROSPECT,staff=lead.staff,status=models.Status.QUALIFIED) models.Opportunity.objects.create(dealer=dealer,customer=customer,lead=lead,probability=50,stage=models.Stage.PROSPECT,staff=lead.staff,status=models.Status.QUALIFIED)
messages.success(request, "Lead converted to customer successfully!") messages.success(request, "Lead converted to customer successfully!")
return redirect("lead_list") return redirect("lead_list")
@ -2860,7 +2860,7 @@ def schedule_lead(request, pk):
service = Service.objects.filter(name=instance.scheduled_type).first() service = Service.objects.filter(name=instance.scheduled_type).first()
if not service: if not service:
messages.error(request, "Service not found!") messages.error(request, "Service not found!")
return redirect("lead_list") return redirect("lead_list")
try: try:
appointment_request = AppointmentRequest.objects.create( appointment_request = AppointmentRequest.objects.create(
@ -2873,7 +2873,7 @@ def schedule_lead(request, pk):
except ValidationError as e: except ValidationError as e:
messages.error(request, str(e)) messages.error(request, str(e))
return redirect("schedule_lead", pk=lead.pk) return redirect("schedule_lead", pk=lead.pk)
client = get_object_or_404(User, email=lead.email) client = get_object_or_404(User, email=lead.email)
# Create Appointment # Create Appointment
Appointment.objects.create( Appointment.objects.create(
@ -2902,7 +2902,7 @@ def lead_transfer(request,pk):
if form.is_valid(): if form.is_valid():
lead.staff = form.cleaned_data["transfer_to"] lead.staff = form.cleaned_data["transfer_to"]
lead.save() lead.save()
messages.success(request, "Lead transferred successfully!") messages.success(request, "Lead transferred successfully!")
else: else:
messages.error(request, f"Invalid form data: {str(form.errors)}") messages.error(request, f"Invalid form data: {str(form.errors)}")
return redirect("lead_list") return redirect("lead_list")
@ -2919,12 +2919,12 @@ def send_lead_email(request, pk,email_pk=None):
response = HttpResponse(redirect("lead_detail", pk=lead.pk)) response = HttpResponse(redirect("lead_detail", pk=lead.pk))
response['HX-Redirect'] = reverse('lead_detail', args=[lead.pk]) response['HX-Redirect'] = reverse('lead_detail', args=[lead.pk])
return response return response
lead.status = models.Status.CONTACTED lead.status = models.Status.CONTACTED
lead.save() lead.save()
# lead.convert_to_customer(dealer.entity) # lead.convert_to_customer(dealer.entity)
if request.method == "POST": if request.method == "POST":
email_pk = request.POST.get('email_pk') email_pk = request.POST.get('email_pk')
if email_pk not in [None,"None",""]: if email_pk not in [None,"None",""]:
email = get_object_or_404(models.Email, pk=int(email_pk)) email = get_object_or_404(models.Email, pk=int(email_pk))
@ -2940,7 +2940,7 @@ def send_lead_email(request, pk,email_pk=None):
) )
dealer = get_user_type(request) dealer = get_user_type(request)
models.Activity.objects.create(dealer=dealer,content_object=lead, notes="Email sent",created_by=request.user,activity_type=models.ActionChoices.EMAIL) models.Activity.objects.create(dealer=dealer,content_object=lead, notes="Email sent",created_by=request.user,activity_type=models.ActionChoices.EMAIL)
messages.success(request, _("Email sent successfully!")) messages.success(request, _("Email sent successfully!"))
return redirect("lead_list") return redirect("lead_list")
msg = f""" msg = f"""
السلام عليكم السلام عليكم
@ -2982,7 +2982,7 @@ def add_activity_to_lead(request, pk):
if request.method == "POST": if request.method == "POST":
form = forms.ActivityForm(request.POST) form = forms.ActivityForm(request.POST)
if form.is_valid(): if form.is_valid():
activity = form.save(commit=False) activity = form.save(commit=False)
activity.content_object = lead activity.content_object = lead
activity.created_by = request.user activity.created_by = request.user
activity.save() activity.save()
@ -3005,8 +3005,8 @@ class OpportunityCreateView(CreateView, LoginRequiredMixin):
def get_initial(self): def get_initial(self):
initial = super().get_initial() initial = super().get_initial()
if self.kwargs.get('pk',None): if self.kwargs.get('pk',None):
lead = models.Lead.objects.get(pk=self.kwargs.get('pk')) lead = models.Lead.objects.get(pk=self.kwargs.get('pk'))
initial['customer'] = lead.customer initial['customer'] = lead.customer
return initial return initial
@ -3037,11 +3037,11 @@ class OpportunityDetailView(DetailView):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
form = forms.OpportunityStatusForm() form = forms.OpportunityStatusForm()
url = reverse("opportunity_update_status", args=[self.object.pk]) url = reverse("opportunity_update_status", args=[self.object.pk])
form.fields["status"].widget.attrs["hx-get"] = url form.fields["status"].widget.attrs["hx-get"] = url
form.fields["stage"].widget.attrs["hx-get"] = url form.fields["stage"].widget.attrs["hx-get"] = url
form.fields["status"].initial = self.object.status form.fields["status"].initial = self.object.status
form.fields["stage"].initial = self.object.stage form.fields["stage"].initial = self.object.stage
context["status_form"] = form context["status_form"] = form
context["notes"] = models.Notes.objects.filter(content_type__model="opportunity", object_id=self.object.id) context["notes"] = models.Notes.objects.filter(content_type__model="opportunity", object_id=self.object.id)
context["activities"] = models.Activity.objects.filter(content_type__model="opportunity", object_id=self.object.id) context["activities"] = models.Activity.objects.filter(content_type__model="opportunity", object_id=self.object.id)
email_qs = models.Email.objects.filter(content_type__model="opportunity", object_id=self.object.id) email_qs = models.Email.objects.filter(content_type__model="opportunity", object_id=self.object.id)
@ -3061,7 +3061,7 @@ class OpportunityListView(ListView):
def get_queryset(self): def get_queryset(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
return models.Opportunity.objects.filter(dealer=dealer).all() return models.Opportunity.objects.filter(dealer=dealer).all()
@login_required @login_required
def delete_opportunity(request, pk): def delete_opportunity(request, pk):
opportunity = get_object_or_404(models.Opportunity, pk=pk) opportunity = get_object_or_404(models.Opportunity, pk=pk)
@ -3227,7 +3227,7 @@ class BillDetailView(LoginRequiredMixin, DetailView):
bill = kwargs.get("object") bill = kwargs.get("object")
if bill.get_itemtxs_data(): if bill.get_itemtxs_data():
txs = bill.get_itemtxs_data()[0] txs = bill.get_itemtxs_data()[0]
transactions = [ transactions = [
{ {
"item": x, "item": x,
@ -3242,7 +3242,7 @@ class BillDetailView(LoginRequiredMixin, DetailView):
kwargs["transactions"] = transactions kwargs["transactions"] = transactions
kwargs["grand_total"] = grand_total kwargs["grand_total"] = grand_total
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
@ -3323,7 +3323,7 @@ def bill_mark_as_paid(request, pk):
bill.mark_as_paid(user_model=dealer.entity.admin) bill.mark_as_paid(user_model=dealer.entity.admin)
bill.save() bill.save()
bill.ledger.lock_journal_entries() bill.ledger.lock_journal_entries()
bill.ledger.post_journal_entries() bill.ledger.post_journal_entries()
bill.ledger.post() bill.ledger.post()
bill.ledger.save() bill.ledger.save()
messages.success(request, _("Bill marked as paid successfully.")) messages.success(request, _("Bill marked as paid successfully."))
@ -3461,7 +3461,7 @@ class OrderListView(ListView):
def get_queryset(self): def get_queryset(self):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
qs = super().get_queryset() qs = super().get_queryset()
return qs.filter(estimate__entity=dealer.entity) return qs.filter(estimate__entity=dealer.entity)
# email # email
@ -3861,7 +3861,7 @@ def DealerSettingsView(request,pk):
dealer = get_user_type(request) dealer = get_user_type(request)
if request.method == 'POST': if request.method == 'POST':
form = forms.DealerSettingsForm(request.POST, instance=dealer_setting) form = forms.DealerSettingsForm(request.POST, instance=dealer_setting)
if form.is_valid(): if form.is_valid():
instance = form.save(commit=False) instance = form.save(commit=False)
instance.dealer = dealer instance.dealer = dealer
instance.save() instance.save()
@ -3873,7 +3873,7 @@ def DealerSettingsView(request,pk):
form.fields['invoice_cash_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH) form.fields['invoice_cash_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH)
form.fields['invoice_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES) form.fields['invoice_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES)
form.fields['invoice_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE) form.fields['invoice_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE)
form.fields['bill_cash_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH) form.fields['bill_cash_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH)
form.fields['bill_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID) form.fields['bill_prepaid_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID)
form.fields['bill_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE) form.fields['bill_unearned_account'].queryset = dealer.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE)

View File

@ -26,7 +26,7 @@
<table class="table fs-9 mb-0 border-top border-translucent"> <table class="table fs-9 mb-0 border-top border-translucent">
<thead> <thead>
<tr> <tr>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 20%;">{{ _("Lead Name")|capfirst }}</th> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 20%;">{{ _("Lead Name")|capfirst }}</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><i class="text-success-dark fas fa-car"></i></div> <div class="d-flex align-items-center px-1 py-1 bg-success-subtle rounded me-2"><i class="text-success-dark fas fa-car"></i></div>
@ -109,7 +109,7 @@
</div> </div>
</div> </div>
</div> </div>
<tr class="hover-actions-trigger btn-reveal-trigger position-static"> <tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="name align-middle white-space-nowrap ps-0"> <td class="name align-middle white-space-nowrap ps-0">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<div><a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{lead.full_name}}</a> <div><a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{lead.full_name}}</a>
@ -132,12 +132,12 @@
</div> </div>
</div> </div>
</td> </td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.id_car_make.get_local_name }} - {{ lead.id_car_model.get_local_name }} {{ lead.year }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.id_car_make.get_local_name }} - {{ lead.id_car_model.get_local_name }} {{ lead.year }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.email }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td> <td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold"> <td class="align-middle white-space-nowrap fw-semibold">
<div class="accordion" id="accordionExample"> <div class="accordion" id="accordionExample">
<div class="accordion-item"> <div class="accordion-item">
<h2 class="accordion-header" id="headingTwo"> <h2 class="accordion-header" id="headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{lead.pk}}" aria-expanded="false" aria-controls="collapseTwo"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse{{lead.pk}}" aria-expanded="false" aria-controls="collapseTwo">
@ -148,7 +148,7 @@
<div class="accordion-body pt-0"> <div class="accordion-body pt-0">
<div class="d-flex flex-column gap-2"> <div class="d-flex flex-column gap-2">
<table><tbody> <table><tbody>
{% for schedule in lead.get_latest_schedules %} {% for schedule in lead.get_latest_schedules %}
<tr class="schedule-{{ schedule.pk }}"> <tr class="schedule-{{ schedule.pk }}">
<td class="align-middle white-space-nowrap"> <td class="align-middle white-space-nowrap">
{% if schedule.scheduled_type == "Call" %} {% if schedule.scheduled_type == "Call" %}
@ -163,11 +163,11 @@
<a href="{% url 'appointment:get_user_appointments' %}"> <a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span> <span class="badge badge-phoenix badge-phoenix-warning text-warning fw-semibold"><span class="text-warning" data-feather="email"></span>
{{ schedule.scheduled_at }}</span></a> {{ schedule.scheduled_at }}</span></a>
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a style="cursor: pointer;" hx-delete="{% url 'schedule_cancel' schedule.pk %}" hx-target=".schedule-{{ schedule.pk }}" hx-confirm="Are you sure you want to cancel this schedule?"><i class="fa-solid fa-ban text-danger"></i></a> <a style="cursor: pointer;" hx-delete="{% url 'schedule_cancel' schedule.pk %}" hx-target=".schedule-{{ schedule.pk }}" hx-confirm="Are you sure you want to cancel this schedule?"><i class="fa-solid fa-ban text-danger"></i></a>
</td> </td>
{% endfor %} {% endfor %}
</tr> </tr>
<tr><td><small><a href="{% url 'appointment:get_user_appointments' %}">View All ...</a></small></td></tr> <tr><td><small><a href="{% url 'appointment:get_user_appointments' %}">View All ...</a></small></td></tr>
@ -176,11 +176,11 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</td> </td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.staff|upper }}</td>
<td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td> <td class="align-middle white-space-nowrap fw-semibold text-body-highlight">{{ lead.source|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.channel|upper }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">{{ lead.channel|upper }}</td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight"> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity.stage == "prospect" %} {% if lead.opportunity.stage == "prospect" %}
<span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span> <span class="badge text-bg-primary">{{ lead.opportunity.stage|upper }}</span>
@ -192,7 +192,7 @@
<span class="badge text-bg-success">{{ lead.opportunity.stage|upper }}</span> <span class="badge text-bg-success">{{ lead.opportunity.stage|upper }}</span>
{% elif lead.opportunity.stage == "closed_lost" %} {% elif lead.opportunity.stage == "closed_lost" %}
<span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span> <span class="badge text-bg-danger">{{ lead.opportunity.stage|upper }}</span>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight"> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 fw-semibold text-body-highlight">
{% if lead.opportunity %} {% if lead.opportunity %}
@ -203,7 +203,7 @@
<span class="badge badge-phoenix badge-phoenix-danger">{{ _("No") }}</span> <span class="badge badge-phoenix badge-phoenix-danger">{{ _("No") }}</span>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle white-space-nowrap text-end"> <td class="align-middle white-space-nowrap text-end">
{% if user == lead.staff.user or request.is_dealer %} {% if user == lead.staff.user or request.is_dealer %}
<div class="btn-reveal-trigger position-static"> <div class="btn-reveal-trigger position-static">
<button <button

View File

@ -5,10 +5,10 @@
<div class="row my-4"> <div class="row my-4">
<h2>{{ organization.get_local_name }}</h2> <h2>{{ organization.get_local_name }}</h2>
<ul class="list-group mb-4"> <ul class="list-group mb-4">
<li class="list-group-item"><strong>{% trans "CRN" %}:</strong> {{ organization.additional_info.organization_info.crn }}</li> <li class="list-group-item"><strong>{% trans "CRN" %}:</strong> {{ organization.additional_info.customer_info.crn }}</li>
<li class="list-group-item"><strong>{% trans "VRN" %}:</strong> {{ organization.additional_info.organization_info.vrn }}</li> <li class="list-group-item"><strong>{% trans "VRN" %}:</strong> {{ organization.additional_info.customer_info.vrn }}</li>
<li class="list-group-item"><strong>{% trans "Phone" %}:</strong> {{ organization.additional_info.organization_info.phone_number }}</li> <li class="list-group-item"><strong>{% trans "Phone" %}:</strong> {{ organization.additional_info.customer_info.phone_number }}</li>
<li class="list-group-item"><strong>{% trans "Address" %}:</strong> {{ organization.additional_info.organization_info.address }}</li> <li class="list-group-item"><strong>{% trans "Address" %}:</strong> {{ organization.additional_info.customer_info.address }}</li>
</ul> </ul>
<div class="d-flex"> <div class="d-flex">
<a href="{% url 'organization_update' organization.pk %}" class="btn btn-sm btn-warning me-2">{% trans "Edit" %}</a> <a href="{% url 'organization_update' organization.pk %}" class="btn btn-sm btn-warning me-2">{% trans "Edit" %}</a>

View File

@ -107,8 +107,8 @@
</div> </div>
</div> </div>
</td> </td>
<td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.crn }}</td> <td class="email align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.customer_info.crn }}</td>
<td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.organization_info.vrn }}</td> <td class="phone align-middle white-space-nowrap fw-semibold ps-4 border-end border-translucent">{{ org.additional_info.customer_info.vrn }}</td>
<td class="phone align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight"> <td class="phone align-middle white-space-nowrap ps-4 border-end border-translucent fw-semibold text-body-highlight">
<a class="text-body-highlight" href="tel:{{ org.phone }}">{{ org.phone }}</a> <a class="text-body-highlight" href="tel:{{ org.phone }}">{{ org.phone }}</a>
</td> </td>