update in lead and schedule

This commit is contained in:
ismail 2025-05-08 17:00:03 +03:00
parent 90a84934d6
commit f0f3712291
7 changed files with 140 additions and 93 deletions

View File

@ -1014,10 +1014,9 @@ class LeadForm(forms.ModelForm):
id_car_make = forms.ModelChoiceField( id_car_make = forms.ModelChoiceField(
label=_("Make"), label=_("Make"),
queryset=CarMake.objects.filter(is_sa_import=True), queryset=CarMake.objects.all(),
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
"hx-get": "", "hx-get": "",
"hx-include": "#id_id_car_make", "hx-include": "#id_id_car_make",
"hx-select": "#div_id_id_car_model", "hx-select": "#div_id_id_car_model",
@ -1059,13 +1058,15 @@ class LeadForm(forms.ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def filter_qs(self,**kwargs):
dealer = kwargs['dealer']
dealer_make_list = DealersMake.objects.filter(dealer=dealer).values_list("car_make",flat=True)
if "id_car_make" in self.fields: if "id_car_make" in self.fields:
queryset = self.fields["id_car_make"].queryset.filter(is_sa_import=True) queryset = self.fields["id_car_make"].queryset.filter(is_sa_import=True,pk__in=dealer_make_list)
self.fields["id_car_make"].choices = [ self.fields["id_car_make"].choices = [
(obj.id_car_make, obj.get_local_name()) for obj in queryset (obj.id_car_make, obj.get_local_name()) for obj in queryset
] ]
class ScheduleForm(forms.ModelForm): class ScheduleForm(forms.ModelForm):
""" """
Represents a form for scheduling events, extending ModelForm to bind to the Represents a form for scheduling events, extending ModelForm to bind to the

View File

@ -7,6 +7,6 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
Service.objects.all().delete() Service.objects.all().delete()
Service.objects.create(name='Call', price=0,duration=datetime.timedelta(minutes=10),currency='SAR',description='15 min call') Service.objects.create(name='call', price=0,duration=datetime.timedelta(minutes=10),currency='SAR',description='15 min call')
Service.objects.create(name='Meeting', price=0,duration=datetime.timedelta(minutes=30),currency='SAR',description='30 min meeting') Service.objects.create(name='meeting', price=0,duration=datetime.timedelta(minutes=30),currency='SAR',description='30 min meeting')
Service.objects.create(name='Visit', price=0,duration=datetime.timedelta(minutes=30),currency='SAR',description='30 min visit') Service.objects.create(name='email', price=0,duration=datetime.timedelta(minutes=30),currency='SAR',description='30 min visit')

View File

@ -0,0 +1,24 @@
# Generated by Django 5.1.7 on 2025-05-07 14:32
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0010_organization_active'),
]
operations = [
migrations.AddField(
model_name='lead',
name='organization',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='organization_leads', to='inventory.organization'),
),
migrations.AlterField(
model_name='lead',
name='customer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='customer_leads', to='inventory.customer'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 5.1.7 on 2025-05-08 10:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0011_lead_organization_alter_lead_customer'),
]
operations = [
migrations.AlterField(
model_name='customer',
name='dob',
field=models.DateField(blank=True, null=True, verbose_name='Date of Birth'),
),
migrations.AlterField(
model_name='customer',
name='national_id',
field=models.CharField(blank=True, max_length=10, null=True, unique=True, verbose_name='National ID'),
),
]

View File

@ -173,7 +173,6 @@ class CarMake(models.Model, LocalizedNameMixin):
class Meta: class Meta:
verbose_name = _("Make") verbose_name = _("Make")
class CarModel(models.Model, LocalizedNameMixin): class CarModel(models.Model, LocalizedNameMixin):
id_car_model = models.AutoField(primary_key=True) id_car_model = models.AutoField(primary_key=True)
id_car_make = models.ForeignKey(CarMake, models.DO_NOTHING, db_column="id_car_make") id_car_make = models.ForeignKey(CarMake, models.DO_NOTHING, db_column="id_car_make")
@ -927,9 +926,10 @@ class Staff(models.Model, LocalizedNameMixin):
def add_group(self,group): def add_group(self,group):
try: try:
self.user.groups.add(group) self.user.groups.add(group)
self.add_as_manager() if self.staff_type in ["accountant","manager"]:
self.add_as_manager()
except Exception as e: except Exception as e:
pass print(e)
def add_as_manager(self): def add_as_manager(self):
if self.staff_type in ["accountant","manager"]: if self.staff_type in ["accountant","manager"]:
EntityManagementModel.objects.get_or_create( EntityManagementModel.objects.get_or_create(
@ -1049,10 +1049,10 @@ class Customer(models.Model):
max_length=1, max_length=1,
verbose_name=_("Gender"), verbose_name=_("Gender"),
) )
dob = models.DateField(verbose_name=_("Date of Birth")) dob = models.DateField(verbose_name=_("Date of Birth"), null=True, blank=True)
email = models.EmailField(unique=True, verbose_name=_("Email")) email = models.EmailField(unique=True, verbose_name=_("Email"))
national_id = models.CharField( national_id = models.CharField(
max_length=10, unique=True, verbose_name=_("National ID") max_length=10, unique=True, verbose_name=_("National ID"), null=True,blank=True
) )
phone_number = PhoneNumberField( phone_number = PhoneNumberField(
region="SA", unique=True, verbose_name=_("Phone Number") region="SA", unique=True, verbose_name=_("Phone Number")
@ -1095,6 +1095,8 @@ class Customer(models.Model):
except Exception: except Exception:
pass pass
customer.save() customer.save()
self.customer_model = customer
self.save()
return customer return customer
def update_user_model(self): def update_user_model(self):
@ -1127,6 +1129,8 @@ class Customer(models.Model):
) )
user.set_password("Tenhal@123") user.set_password("Tenhal@123")
user.save() user.save()
self.user = user
self.save()
return user return user
def deactivate_account(self): def deactivate_account(self):
self.active = False self.active = False
@ -1184,6 +1188,8 @@ class Organization(models.Model, LocalizedNameMixin):
except Exception: except Exception:
pass pass
customer.save() customer.save()
self.customer_model = customer
self.save()
return customer return customer
def update_user_model(self): def update_user_model(self):
@ -1214,6 +1220,8 @@ class Organization(models.Model, LocalizedNameMixin):
) )
user.set_password("Tenhal@123") user.set_password("Tenhal@123")
user.save() user.save()
self.user = user
self.save()
return user return user
def deactivate_account(self): def deactivate_account(self):
@ -1258,12 +1266,13 @@ class Lead(models.Model):
max_length=50, choices=[("customer", _("Customer")), ("organization", _("Organization"))], verbose_name=_("Lead Type") max_length=50, choices=[("customer", _("Customer")), ("organization", _("Organization"))], verbose_name=_("Lead Type")
,default="customer") ,default="customer")
customer = models.ForeignKey( customer = models.ForeignKey(
CustomerModel, on_delete=models.CASCADE, related_name="leads", Customer, on_delete=models.CASCADE, related_name="customer_leads",
null=True,blank=True
)
organization = models.ForeignKey(
Organization, on_delete=models.CASCADE, related_name="organization_leads",
null=True,blank=True null=True,blank=True
) )
# car = models.ForeignKey(
# Car, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("Car")
# )
id_car_make = models.ForeignKey( id_car_make = models.ForeignKey(
CarMake, CarMake,
on_delete=models.DO_NOTHING, on_delete=models.DO_NOTHING,
@ -1347,30 +1356,16 @@ 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,lead): def convert_to_customer(self):
customer = entity.get_customers().filter(email=self.email).first()
if entity and not customer:
customer = entity.create_customer(
commit=False,
customer_model_kwargs={
"customer_name": self.full_name,
"address_1": self.address,
"phone": self.phone_number,
"email": self.email,
}
)
customer.additional_info.update({"info":self.to_dict()})
if lead.lead_type == "organization":
customer.additional_info.update({"type":"organization"})
else:
customer.additional_info.update({"type":"customer"})
customer.save()
self.customer = customer
self.status = Status.QUALIFIED self.status = Status.QUALIFIED
self.save() self.save()
return customer return self.get_customer_model()
def get_customer_model(self):
if self.customer:
return self.customer.customer_model
if self.organization:
return self.organization.customer_model
def get_latest_schedule(self): def get_latest_schedule(self):
return self.schedules.order_by('-scheduled_at').first() return self.schedules.order_by('-scheduled_at').first()
def get_latest_schedules(self): def get_latest_schedules(self):
@ -1378,15 +1373,15 @@ class Lead(models.Model):
def get_all_schedules(self): def get_all_schedules(self):
return self.schedules.all().order_by('-scheduled_at') return self.schedules.all().order_by('-scheduled_at')
def get_calls(self): def get_calls(self):
return self.get_all_schedules().filter(scheduled_type='Call') return self.get_all_schedules().filter(scheduled_type='call')
def get_meetings(self): def get_meetings(self):
return self.get_all_schedules().filter(scheduled_type='Meeting') return self.get_all_schedules().filter(scheduled_type='meeting')
def get_emails(self): def get_emails(self):
return Email.objects.filter(content_type__model="lead", object_id=self.id) return Email.objects.filter(content_type__model="lead", object_id=self.pk)
def get_notes(self): def get_notes(self):
return Notes.objects.filter(content_type__model="lead", object_id=self.id) return Notes.objects.filter(content_type__model="lead", object_id=self.pk)
def get_activities(self): def get_activities(self):
return Activity.objects.filter(content_type__model="lead", object_id=self.id) return Activity.objects.filter(content_type__model="lead", object_id=self.pk)
class Schedule(models.Model): class Schedule(models.Model):
PURPOSE_CHOICES = [ PURPOSE_CHOICES = [

View File

@ -150,7 +150,7 @@ from plans.quota import get_user_quota
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from django_tables2.export.views import ExportMixin from django_tables2.export.views import ExportMixin
from appointment.models import Appointment, AppointmentRequest, Service, StaffMember from appointment.models import Appointment, AppointmentRequest, Service, StaffMember
from django.db.models.functions import Lower
from .models import SaleOrder from .models import SaleOrder
from .services import ( from .services import (
decodevin, decodevin,
@ -2494,6 +2494,7 @@ def UserGroupView(request, 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))
@ -4601,13 +4602,7 @@ def lead_create(request):
:return: An HTTP response object rendering the lead creation form or redirecting to the lead list page upon success. :return: An HTTP response object rendering the lead creation form or redirecting to the lead list page upon success.
:rtype: HttpResponse :rtype: HttpResponse
""" """
form = forms.LeadForm() dealer = get_user_type(request)
make = request.GET.get("id_car_make", None)
if make:
form.fields["id_car_model"].queryset = models.CarModel.objects.filter(
id_car_make=int(make)
)
if request.method == "POST": if request.method == "POST":
form = forms.LeadForm(request.POST) form = forms.LeadForm(request.POST)
@ -4620,51 +4615,57 @@ def lead_create(request):
try: try:
if form.is_valid(): if form.is_valid():
instance = form.save(commit=False) instance = form.save(commit=False)
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 if instance.lead_type == "customer":
customer = ( customer = models.Customer.objects.filter(email=instance.email)
dealer.entity.get_customers().filter(email=instance.email).first() if not customer:
) customer = models.Customer(
if not customer: dealer=dealer,
customer = dealer.entity.create_customer( address=instance.address,
commit=False, phone_number=instance.phone_number,
customer_model_kwargs={ email=instance.email,
"customer_name": instance.full_name, first_name=instance.first_name,
"address_1": instance.address, last_name=instance.last_name,
"phone": instance.phone_number, )
"email": instance.email, customer.create_user_model()
"sales_tax_rate": 0.15, customer.create_customer_model()
}, customer.save()
) instance.customer = customer
customer_info = {
"first_name": instance.first_name,
"last_name": instance.last_name, if instance.lead_type == "organization":
"address": instance.address, organization = models.Organization.objects.filter(email=instance.email)
"phone_number": str(instance.phone_number), if not organization:
"email": instance.email, organization = models.Organization(
"crn": form.cleaned_data["crn"], dealer=dealer,
"vrn": form.cleaned_data["vrn"], address=instance.address,
} phone_number=instance.phone_number,
customer.additional_info.update({"customer_info": customer_info}) email=instance.email,
customer.additional_info.update({"type": "lead"}) name=instance.first_name + " " + instance.last_name,
customer.save() )
instance.customer = customer organization.create_user_model()
# try: organization.create_customer_model()
# user = User.objects.get(email=customer.email) organization.save()
# user.first_name = instance.first_name instance.organization = organization
# user.last_name = instance.last_name
# user.save()
# except Exception as e:
# print(e)
instance.save() instance.save()
messages.success(request, _("Lead created successfully")) messages.success(request, _("Lead created successfully"))
return redirect("lead_list") return redirect("lead_list")
else:
messages.error(request, f"Lead was not created ... : {str(form.errors)}")
except Exception as e: except Exception as e:
messages.error(request, f"Lead was not created ... : {str(e)}") messages.error(request, f"Lead was not created ... : {str(e)}")
form = forms.LeadForm()
form.filter_qs(dealer=dealer)
make = request.GET.get("id_car_make", None)
if make:
form.fields["id_car_model"].queryset = models.CarModel.objects.filter(
id_car_make=int(make)
)
return render(request, "crm/leads/lead_form.html", {"form": form}) return render(request, "crm/leads/lead_form.html", {"form": form})
@ -4870,7 +4871,7 @@ def lead_convert(request, pk):
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,lead) customer = lead.convert_to_customer()
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")
@ -4896,6 +4897,7 @@ def schedule_lead(request, pk):
method and validity of the form submission. method and validity of the form submission.
:rtype: HttpResponse :rtype: HttpResponse
""" """
if not request.is_staff: if not request.is_staff:
messages.error(request, _("You do not have permission to schedule lead")) messages.error(request, _("You do not have permission to schedule lead"))
return redirect("lead_list") return redirect("lead_list")
@ -4907,10 +4909,12 @@ def schedule_lead(request, pk):
instance = form.save(commit=False) instance = form.save(commit=False)
instance.lead = lead instance.lead = lead
instance.scheduled_by = request.user instance.scheduled_by = request.user
instance.customer = lead.customer
instance.customer = lead.get_customer_model()
# Create AppointmentRequest # Create AppointmentRequest
service,_ = Service.objects.get_or_create(name=instance.scheduled_type,duration=datetime.timedelta(minutes=10),price=0) # service,_ = Service.objects.get_or_create(name=instance.scheduled_type,duration=datetime.timedelta(minutes=10),price=0)
service = Service.objects.get(name=instance.scheduled_type)
# 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!")
@ -5008,7 +5012,7 @@ def send_lead_email(request, pk, email_pk=None):
lead.status = models.Status.CONTACTED lead.status = models.Status.CONTACTED
lead.save() lead.save()
# 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")

View File

@ -153,15 +153,15 @@
{% 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" %}
<a href="{% url 'appointment:get_user_appointments' %}"> <a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span> <span class="badge badge-phoenix badge-phoenix-primary text-primary {% if schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span>
{{ schedule.scheduled_at }}</span></a> {{ schedule.scheduled_at }}</span></a>
{% elif schedule.scheduled_type == "Meeting" %} {% elif schedule.scheduled_type == "meeting" %}
<a href="{% url 'appointment:get_user_appointments' %}"> <a href="{% url 'appointment:get_user_appointments' %}">
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span> <span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span>
{{ schedule.scheduled_at }}</span></a> {{ schedule.scheduled_at }}</span></a>
{% elif schedule.scheduled_type == "Email" %} {% elif schedule.scheduled_type == "email" %}
<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>