This commit is contained in:
gitea 2025-02-09 07:36:28 +00:00
parent 1f2cf5a7ec
commit 778a41aa47
10 changed files with 198 additions and 98 deletions

View File

@ -1,3 +1,4 @@
from django.urls import reverse
from django_countries.widgets import CountrySelectWidget
from phonenumber_field.formfields import PhoneNumberField
from django.core.validators import MinLengthValidator
@ -35,8 +36,7 @@ from .models import (
# SaleQuotationCar,
AdditionalServices,
Staff,
Opportunity, Priority, Sources, Lead, Activity, Notes, CarModel,
SaleOrder
Opportunity, Priority, Sources, Lead, Activity, Notes, CarModel,SaleOrder,CarMake
)
from django_ledger.models import ItemModel, InvoiceModel, BillModel,VendorModel
from django.forms import ModelMultipleChoiceField, ValidationError, DateInput,DateTimeInput
@ -650,6 +650,12 @@ class EmailForm(forms.Form):
class LeadForm(forms.ModelForm):
id_car_make = forms.ModelChoiceField(label="Make",
queryset=CarMake.objects.filter(is_sa_import=True),
widget=forms.Select(attrs={"class": "form-control form-control-sm","hx-get":"","hx-include":"#id_id_car_make","hx-select":"#div_id_id_car_model","hx-target":"#div_id_id_car_model","hx-swap":"outerHTML"}),
required=True
)
id_car_model = forms.ModelChoiceField(label="Model", queryset=CarModel.objects.none(),widget=forms.Select(attrs={"class": "form-control form-control-sm"}),required=True)
class Meta:
model = Lead
fields = [
@ -658,7 +664,9 @@ class LeadForm(forms.ModelForm):
'email',
'phone_number',
'address',
'car',
'id_car_make',
'id_car_model',
'year',
'source',
'channel',
'staff',
@ -666,8 +674,8 @@ class LeadForm(forms.ModelForm):
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
if "id_car_make" in self.fields:
queryset = self.fields["id_car_make"].queryset.filter(is_sa_import=True)
self.fields["id_car_make"].choices = [

View File

@ -0,0 +1,14 @@
# Generated by Django 4.2.17 on 2025-02-06 10:08
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('inventory', '0002_alter_carregistration_car'),
('inventory', '0011_remove_lead_year_alter_schedule_customer'),
]
operations = [
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-02-06 11:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0012_merge_20250206_1308'),
]
operations = [
migrations.AlterField(
model_name='carregistration',
name='text2',
field=models.CharField(blank=True, max_length=1, null=True, verbose_name='Text 2'),
),
migrations.AlterField(
model_name='carregistration',
name='text3',
field=models.CharField(blank=True, max_length=1, null=True, verbose_name='Text 3'),
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 4.2.17 on 2025-02-06 12:07
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inventory', '0013_alter_carregistration_text2_and_more'),
]
operations = [
migrations.RemoveField(
model_name='lead',
name='car',
),
migrations.AddField(
model_name='lead',
name='id_car_make',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmake', verbose_name='Make'),
),
migrations.AddField(
model_name='lead',
name='id_car_model',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='inventory.carmodel', verbose_name='Model'),
),
migrations.AddField(
model_name='lead',
name='year',
field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='Year'),
),
]

View File

@ -1096,26 +1096,26 @@ class Lead(models.Model):
CustomerModel, on_delete=models.CASCADE, related_name="leads",
null=True,blank=True
)
car = models.ForeignKey(
Car, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("Car")
# car = models.ForeignKey(
# Car, on_delete=models.DO_NOTHING, blank=True, null=True, verbose_name=_("Car")
# )
id_car_make = models.ForeignKey(
CarMake,
on_delete=models.DO_NOTHING,
blank=True,
null=True,
verbose_name=_("Make"),
)
id_car_model = models.ForeignKey(
CarModel,
on_delete=models.DO_NOTHING,
blank=True,
null=True,
verbose_name=_("Model"),
)
year = models.PositiveSmallIntegerField(
verbose_name=_("Year"), blank=True, null=True
)
# id_car_make = models.ForeignKey(
# CarMake,
# on_delete=models.DO_NOTHING,
# blank=True,
# null=True,
# verbose_name=_("Make"),
# )
# id_car_model = models.ForeignKey(
# CarModel,
# on_delete=models.DO_NOTHING,
# blank=True,
# null=True,
# verbose_name=_("Model"),
# )
# year = models.PositiveSmallIntegerField(
# verbose_name=_("Year"), blank=True, null=True
# )
source = models.CharField(
max_length=50, choices=Sources.choices, verbose_name=_("Source")
)
@ -1167,7 +1167,8 @@ class Lead(models.Model):
"email": str(self.email),
"address": str(self.address),
"phone_number": str(self.phone_number),
"car": self.car.to_dict(),
"make": str(self.id_car_make.name),
"model": str(self.id_car_model.name),
"created_at": str(self.created.strftime("%Y-%m-%d")),
}
@property
@ -1225,8 +1226,9 @@ class Schedule(models.Model):
def __str__(self):
return f"Scheduled {self.purpose} with {self.customer.customer_name} on {self.scheduled_at}"
@property
def schedule_past_date(self):
if self.scheduled_at < timezone.now():
if self.scheduled_at < now():
return True
return False

View File

@ -319,10 +319,10 @@ def number_to_words_arabic(number):
return ' '.join(words)
@register.filter(name='num2words')
def num2words(number, language='en'):
"""Template filter to convert a number to words in the specified language."""
if language == 'ar':
return number_to_words_arabic(number)
else:
return number_to_words_english(number)
# @register.filter(name='num2words')
# def num2words(number, language='en'):
# """Template filter to convert a number to words in the specified language."""
# if language == 'ar':
# return number_to_words_arabic(number)
# else:
# return number_to_words_english(number)

View File

@ -88,7 +88,7 @@ urlpatterns = [
path(
"crm/leads/<int:pk>/view/", views.LeadDetailView.as_view(), name="lead_detail"
),
path("crm/leads/create/", views.LeadCreateView.as_view(), name="lead_create"),
path("crm/leads/create/", views.lead_create, name="lead_create"),
path(
"crm/leads/<int:pk>/update/", views.LeadUpdateView.as_view(), name="lead_update"
),
@ -194,7 +194,6 @@ urlpatterns = [
),
path("cars/add/", views.CarCreateView.as_view(), name="car_add"),
path("ajax/", views.AjaxHandlerView.as_view(), name="ajax_handler"),
path("cars/get-car-models/", views.get_car_models, name="get_car_models"),
path(
"cars/<int:car_pk>/add-color/", views.CarColorCreate.as_view(), name="add_color"
),

View File

@ -1,3 +1,4 @@
from appointment.models import Appointment
from calendar import month_name
from random import randint
from rich import print
@ -2944,28 +2945,25 @@ class LeadDetailView(DetailView):
return context
class LeadCreateView(CreateView, SuccessMessageMixin, LoginRequiredMixin):
model = models.Lead
form_class = forms.LeadForm
template_name = "crm/leads/lead_form.html"
success_message = "Lead created successfully!"
success_url = reverse_lazy("lead_list")
def form_valid(self, form):
dealer = get_user_type(self.request)
form.instance.dealer = dealer
return super().form_valid(form)
def get_car_models(request):
make_id = request.GET.get("id_car_make")
if make_id:
car_models = models.CarModel.objects.filter(id_car_make=make_id).values(
"id_car_model", "name", "arabic_name"
)
return JsonResponse(list(car_models), safe=False)
return JsonResponse([], safe=False)
def lead_create(request):
form = forms.LeadForm()
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":
form = forms.LeadForm(request.POST)
form.fields['id_car_model'].queryset = models.CarModel.objects.filter(id_car_make=int(request.POST['id_car_make']))
if form.is_valid():
instance = form.save(commit=False)
dealer = get_user_type(request)
instance = form.save(commit=False)
instance.dealer = dealer
instance.save()
messages.success(request, "Lead created successfully!")
return redirect("lead_list")
return render(request, "crm/leads/lead_form.html", {"form": form})
class LeadUpdateView(UpdateView):
model = models.Lead
@ -2973,6 +2971,10 @@ class LeadUpdateView(UpdateView):
template_name = "crm/leads/lead_form.html"
success_url = reverse_lazy("lead_list")
def get_form(self, form_class=None):
form = super().get_form(form_class)
form.fields["id_car_model"].queryset = form.instance.id_car_make.carmodel_set.all()
return form
def LeadDeleteView(request,pk):
lead = get_object_or_404(models.Lead, pk=pk)

View File

@ -4,49 +4,68 @@ from decimal import Decimal
from django_ledger.models import EstimateModel,EntityModel
from rich import print
from datetime import date
from inventory.models import VatRate
from inventory.models import VatRate,Lead,CarMake,CarModel,Schedule
from inventory.utils import CarFinanceCalculator
from appointment.models import Appointment,AppointmentRequest,Service,StaffMember
from django.contrib.auth import get_user_model
from django_ledger.io.io_core import get_localdate
from datetime import datetime, timedelta
def run():
# estimate = EstimateModel.objects.first()
# calculator = CarFinanceCalculator(estimate)
# finance_data = calculator.get_finance_data()
User = get_user_model()
def run():
# print(Service.objects.first().pk)
# print(Appointment.objects.first().client)
# print(finance_data)
# entity = EntityModel.objects.get(name="ismail")
# bs_report = entity.get_balance_sheet_statement(
# to_date=date(2025, 1, 1),
# save_pdf=False,
# filepath='./'
# )
# ic_report = entity.get_income_statement(
# from_date=date(2022, 1, 1),
# to_date=date(2022, 12, 31),
# save_pdf=False,
# filepath='./'
# appointment = Appointment.objects.create(
# client_name="John Doe",
# client_email="john@example.com",
# service="Haircut",
# date_time="2023-10-15 10:00:00",
# status="pending")
make = CarMake.objects.first()
# Lead.objects.create(
# first_name="John",
# last_name="Doe",
# email="john@example.com",
# phone_number="123-456-7890",
# address="123 Main St",
# id_car_make=make,
# id_car_model=make.carmodel_set.first(),
# year="2022",
# source="website",
# channel="online",
# staff="John Doe",
# priority="high",
# )
# # print(bs_report)
# print(ic_report.get_report_data())
# estimate = EstimateModel.objects.first()
# calculator = CarFinanceCalculator(estimate)
# finance_data = calculator.get_finance_data()
# schedult = Schedule.objects.create(
# name="John Doe",
# email="john@example.com",
# phone_number="123-456-7890",
# address="123 Main St",
# id_car_make=make,
# id_car_model=make.carmodel_set.first(),
# year="2022",
# source="website",
# channel="online",
# staff="John Doe",
# priority="high",
# )
service = Service.objects.first()
appointment_request = AppointmentRequest.objects.create(
date=get_localdate(),
start_time=datetime.now().strftime("%H:%M:%S"),
end_time=datetime.time(datetime.now() + timedelta(minutes=30)).strftime("%H:%M:%S"),
service=service,
staff_member=StaffMember.objects.first(),
)
# invoice_itemtxs = {
# i.get("item_number"): {
# "unit_cost": i.get("total_price"),
# "quantity": i.get("quantity"),
# "total_amount": i.get("total_vat"),
# }
# for i in finance_data.get("cars")
# }
# invoice = InvoiceModel.objects.first()
entity = EntityModel.objects.filter(name="ismail").first()
invoice_qs = InvoiceModel.objects.for_entity(
entity_slug=entity.slug,
user_model=entity.admin,
).unpaid()
print(accruable_net_summary(invoice_qs))
appointment = Appointment.objects.create(
client=User.objects.first(),
appointment_request=appointment_request,
phone="123-456-7890",
address="123 Main St",
)

View File

@ -72,7 +72,7 @@
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
<span>{{ _("Source")|capfirst }}</span>
</div>
</th>``
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
@ -135,13 +135,13 @@
</div>
</td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.car.id_car_make.get_local_name }} - {{ lead.car.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="tel:{{ lead.phone_number }}">{{ lead.phone_number }}</a></td>
<td class="align-middle white-space-nowrap fw-semibold">
{% if lead.get_latest_schedule %}
{% if lead.get_latest_schedule.scheduled_type == "Call" %}
<span class="badge badge-phoenix badge-phoenix-primary text-primary fw-semibold"><span class="text-primary" data-feather="phone"></span>
<span class="badge badge-phoenix badge-phoenix-primary text-primary {% if lead.get_latest_schedule.schedule_past_date %}badge-phoenix-danger text-danger{% endif %} fw-semibold"><span class="text-primary {% if lead.get_latest_schedule.schedule_past_date %}text-danger{% endif %}" data-feather="phone"></span>
{{ lead.get_latest_schedule.scheduled_at }}</span>
{% elif lead.get_latest_schedule.scheduled_type == "Meeting" %}
<span class="badge badge-phoenix badge-phoenix-success text-success fw-semibold"><span class="text-success" data-feather="calendar"></span>