update customer and organization & staffmember
This commit is contained in:
parent
21089f8995
commit
a96b1131d3
@ -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())
|
||||||
23
inventory/migrations/0053_lead_crn_lead_vrn.py
Normal file
23
inventory/migrations/0053_lead_crn_lead_vrn.py
Normal 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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -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}"
|
||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user