This commit is contained in:
Marwan Alwali 2025-02-04 22:37:12 +03:00
commit 3febd59d86
26 changed files with 537 additions and 132 deletions

View File

@ -5,4 +5,8 @@ class InventoryConfig(AppConfig):
name = 'inventory' name = 'inventory'
def ready(self): def ready(self):
import inventory.signals import inventory.signals
from decimal import Decimal
from inventory.models import VatRate
VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)

View File

@ -17,6 +17,7 @@ from .models import (
Dealer, Dealer,
# Branch, # Branch,
Vendor, Vendor,
Schedule,
Customer, Customer,
Car, Car,
CarTransfer, CarTransfer,
@ -38,7 +39,7 @@ from .models import (
SaleOrder SaleOrder
) )
from django_ledger.models import ItemModel, InvoiceModel, BillModel,VendorModel from django_ledger.models import ItemModel, InvoiceModel, BillModel,VendorModel
from django.forms import ModelMultipleChoiceField, ValidationError, DateInput from django.forms import ModelMultipleChoiceField, ValidationError, DateInput,DateTimeInput
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.forms import formset_factory from django.forms import formset_factory
@ -651,8 +652,12 @@ class EmailForm(forms.Form):
class LeadForm(forms.ModelForm): class LeadForm(forms.ModelForm):
class Meta: class Meta:
model = Lead model = Lead
fields = ['customer', fields = [
'city', 'first_name',
'last_name',
'email',
'phone_number',
'address',
'id_car_make', 'id_car_make',
'id_car_model', 'id_car_model',
'year', 'year',
@ -671,6 +676,11 @@ class LeadForm(forms.ModelForm):
(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):
scheduled_at = forms.DateTimeField(widget=DateTimeInput(attrs={'type': 'datetime-local'}))
class Meta:
model = Schedule
fields = ['purpose','scheduled_type', 'scheduled_at', 'notes']
class NoteForm(forms.ModelForm): class NoteForm(forms.ModelForm):
class Meta: class Meta:

View File

@ -4,6 +4,8 @@ from django.utils import timezone
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse from django.urls import reverse
from inventory.utils import get_user_type
logger = logging.getLogger('user_activity') logger = logging.getLogger('user_activity')
@ -37,7 +39,8 @@ class InjectParamsMiddleware:
def __call__(self, request): def __call__(self, request):
try: try:
request.entity = request.user.dealer.entity # request.entity = request.user.dealer.entity
request.dealer = get_user_type(request)
except Exception as e: except Exception as e:
pass pass

View File

@ -0,0 +1,21 @@
# Generated by Django 4.2.17 on 2025-02-04 09:34
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='lead',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL),
),
]

View File

@ -0,0 +1,46 @@
# Generated by Django 4.2.17 on 2025-02-04 11:38
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import phonenumber_field.modelfields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0002_alter_lead_customer'),
]
operations = [
migrations.AddField(
model_name='lead',
name='email',
field=models.EmailField(default='x@tenhal.sa', max_length=254, verbose_name='Email'),
preserve_default=False,
),
migrations.AddField(
model_name='lead',
name='first_name',
field=models.CharField(default='test', max_length=50, verbose_name='First Name'),
preserve_default=False,
),
migrations.AddField(
model_name='lead',
name='last_name',
field=models.CharField(default='test', max_length=50, verbose_name='Last Name'),
preserve_default=False,
),
migrations.AddField(
model_name='lead',
name='phone_number',
field=phonenumber_field.modelfields.PhoneNumberField(default='056523656', max_length=128, region='SA', verbose_name='Phone Number'),
preserve_default=False,
),
migrations.AlterField(
model_name='lead',
name='customer',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='leads', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-02-04 14:21
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0003_lead_email_lead_first_name_lead_last_name_and_more'),
]
operations = [
migrations.RemoveField(
model_name='lead',
name='city',
),
migrations.AddField(
model_name='lead',
name='address',
field=models.CharField(default='', max_length=50, verbose_name='address'),
preserve_default=False,
),
]

View File

@ -0,0 +1,33 @@
# Generated by Django 4.2.17 on 2025-02-04 15:15
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.DJANGO_LEDGER_CUSTOMER_MODEL),
('inventory', '0004_remove_lead_city_lead_address'),
]
operations = [
migrations.CreateModel(
name='Schedule',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('purpose', models.CharField(max_length=200)),
('scheduled_at', models.DateTimeField()),
('notes', models.TextField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to=settings.DJANGO_LEDGER_CUSTOMER_MODEL)),
('lead', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='inventory.lead')),
('scheduled_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inventory.staff')),
],
options={
'ordering': ['-scheduled_at'],
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.17 on 2025-02-04 15:31
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0005_schedule'),
]
operations = [
migrations.AlterField(
model_name='schedule',
name='purpose',
field=models.CharField(choices=[('Product Demo', 'Product Demo'), ('Follow-Up Call', 'Follow-Up Call'), ('Contract Discussion', 'Contract Discussion'), ('Sales Meeting', 'Sales Meeting'), ('Support Call', 'Support Call'), ('Other', 'Other')], max_length=200),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.17 on 2025-02-04 15:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('inventory', '0006_alter_schedule_purpose'),
]
operations = [
migrations.AddField(
model_name='schedule',
name='scheduled_type',
field=models.CharField(choices=[('Call', 'Call'), ('Meeting', 'Meeting'), ('Email', 'Email')], default='Call', max_length=200),
),
]

View File

@ -1,3 +1,4 @@
from datetime import timezone
import itertools import itertools
from uuid import uuid4 from uuid import uuid4
from django.conf import settings from django.conf import settings
@ -1087,8 +1088,13 @@ class Representative(models.Model, LocalizedNameMixin):
class Lead(models.Model): class Lead(models.Model):
dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="leads") dealer = models.ForeignKey(Dealer, on_delete=models.CASCADE, related_name="leads")
first_name = models.CharField(max_length=50, verbose_name=_("First Name"))
last_name = models.CharField(max_length=50, verbose_name=_("Last Name"))
email = models.EmailField(verbose_name=_("Email"))
phone_number = PhoneNumberField(region="SA", verbose_name=_("Phone Number"))
customer = models.ForeignKey( customer = models.ForeignKey(
Customer, on_delete=models.CASCADE, related_name="leads" CustomerModel, on_delete=models.CASCADE, related_name="leads",
null=True,blank=True
) )
id_car_make = models.ForeignKey( id_car_make = models.ForeignKey(
CarMake, CarMake,
@ -1113,7 +1119,7 @@ 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")
) )
city = models.CharField(max_length=50, verbose_name=_("City")) address = models.CharField(max_length=50, verbose_name=_("address"))
staff = models.ForeignKey( staff = models.ForeignKey(
Staff, Staff,
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
@ -1146,7 +1152,80 @@ class Lead(models.Model):
def __str__(self): def __str__(self):
return f"{self.first_name} {self.last_name}" return f"{self.first_name} {self.last_name}"
@property
def is_converted(self):
return bool(self.customer)
def to_dict(self):
return {
"first_name": str(self.first_name),
"last_name": str(self.last_name),
"email": str(self.email),
"address": str(self.address),
"phone_number": str(self.phone_number),
"id_car_make": str(self.id_car_make.name),
"id_car_model": str(self.id_car_model.name),
"year": str(self.year),
"created_at": str(self.created.strftime("%Y-%m-%d")),
}
@property
def full_name(self):
return f"{self.first_name} {self.last_name}"
def convert_to_customer(self,entity):
if entity and not CustomerModel.objects.filter(email=self.email).exists():
customer = entity.create_customer(
customer_model_kwargs={
"customer_name": self.full_name,
"address_1": self.address,
"phone": self.phone_number,
"email": self.email,
}
)
customer.additional_info = {}
customer.additional_info.update({"info":self.to_dict()})
customer.save()
self.customer = customer
self.save()
def get_latest_schedule(self):
return self.schedules.order_by('-scheduled_at').first()
class Schedule(models.Model):
PURPOSE_CHOICES = [
('Product Demo', 'Product Demo'),
('Follow-Up Call', 'Follow-Up Call'),
('Contract Discussion', 'Contract Discussion'),
('Sales Meeting', 'Sales Meeting'),
('Support Call', 'Support Call'),
('Other', 'Other'),
]
ScheduledType = [
('Call', 'Call'),
('Meeting', 'Meeting'),
('Email', 'Email'),
]
lead = models.ForeignKey(Lead, on_delete=models.CASCADE, related_name='schedules')
customer = models.ForeignKey(CustomerModel, on_delete=models.CASCADE, related_name='schedules')
scheduled_by = models.ForeignKey(Staff, on_delete=models.CASCADE)
purpose = models.CharField(max_length=200, choices=PURPOSE_CHOICES)
scheduled_at = models.DateTimeField()
scheduled_type = models.CharField(max_length=200, choices=ScheduledType,default='Call')
notes = models.TextField(blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Scheduled {self.purpose} with {self.customer.customer_name} on {self.scheduled_at}"
def schedule_past_date(self):
if self.scheduled_at < timezone.now():
return True
return False
class Meta:
ordering = ['-scheduled_at']
class LeadStatusHistory(models.Model): class LeadStatusHistory(models.Model):
lead = models.ForeignKey( lead = models.ForeignKey(
@ -1181,7 +1260,7 @@ class Opportunity(models.Model):
Dealer, on_delete=models.CASCADE, related_name="opportunities" Dealer, on_delete=models.CASCADE, related_name="opportunities"
) )
customer = models.ForeignKey( customer = models.ForeignKey(
Customer, on_delete=models.CASCADE, related_name="opportunities" Customer, on_delete=models.CASCADE, related_name="opportunities"
) )
car = models.ForeignKey( car = models.ForeignKey(
Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car") Car, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Car")
@ -1213,7 +1292,7 @@ class Opportunity(models.Model):
verbose_name_plural = _("Opportunities") verbose_name_plural = _("Opportunities")
def __str__(self): def __str__(self):
return f"{self.car.id_car_make.name} - {self.car.id_car_model.name} : {self.customer.get_full_name}" return f"{self.car.id_car_make.name} - {self.car.id_car_model.name} : {self.customer}"
class Notes(models.Model): class Notes(models.Model):

View File

@ -811,7 +811,7 @@ def notify_assigned_staff(sender, instance, created, **kwargs):
if instance.staff: # Check if the lead is assigned if instance.staff: # Check if the lead is assigned
models.Notification.objects.create( models.Notification.objects.create(
user=instance.staff.user, user=instance.staff.user,
message=f"You have been assigned a new lead: {instance.customer.get_full_name}." message=f"You have been assigned a new lead: {instance.full_name}."
) )

View File

@ -92,15 +92,25 @@ urlpatterns = [
path( path(
"crm/leads/<int:pk>/update/", views.LeadUpdateView.as_view(), name="lead_update" "crm/leads/<int:pk>/update/", views.LeadUpdateView.as_view(), name="lead_update"
), ),
path( path("crm/leads/<int:pk>/delete/", views.LeadDeleteView, name="lead_delete"),
"crm/leads/<int:pk>/delete/", views.LeadDeleteView.as_view(), name="lead_delete"
),
path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note"), path("crm/leads/<int:pk>/add-note/", views.add_note_to_lead, name="add_note"),
path("crm/leads/<int:pk>/lead-convert/", views.lead_convert, name="lead_convert"),
path( path(
"crm/leads/<int:pk>/add-activity/", "crm/leads/<int:pk>/add-activity/",
views.add_activity_to_lead, views.add_activity_to_lead,
name="add_activity", name="add_activity",
), ),
path(
"crm/leads/<int:pk>/send_lead_email/",
views.send_lead_email,
name="send_lead_email",
),
path(
"crm/leads/<int:pk>/schedule/",
views.schedule_lead,
name="schedule_lead",
),
path( path(
"crm/opportunities/create/", "crm/opportunities/create/",
views.OpportunityCreateView.as_view(), views.OpportunityCreateView.as_view(),

View File

@ -350,7 +350,7 @@ def set_bill_payment(dealer, entity, bill, amount, payment_method):
account=cash_account, # Debit Cash account=cash_account, # Debit Cash
amount=amount, # Payment amount amount=amount, # Payment amount
tx_type="debit", tx_type="debit",
description="Payment Received", description="Bill Payment Received",
) )
TransactionModel.objects.create( TransactionModel.objects.create(
@ -358,7 +358,7 @@ def set_bill_payment(dealer, entity, bill, amount, payment_method):
account=account_payable, # Credit Accounts Receivable account=account_payable, # Credit Accounts Receivable
amount=amount, # Payment amount amount=amount, # Payment amount
tx_type="credit", tx_type="credit",
description="Payment Received", description="Bill Payment Received",
) )
bill.make_payment(amount) bill.make_payment(amount)

View File

@ -1804,7 +1804,7 @@ class OrganizationListView(LoginRequiredMixin, ListView):
class OrganizationDetailView(DetailView): class OrganizationDetailView(DetailView):
model = models.Organization model = CustomerModel
template_name = "organizations/organization_detail.html" template_name = "organizations/organization_detail.html"
context_object_name = "organization" context_object_name = "organization"
@ -1812,12 +1812,8 @@ class OrganizationDetailView(DetailView):
def OrganizationCreateView(request): def OrganizationCreateView(request):
if request.method == "POST": if request.method == "POST":
form = forms.OrganizationForm(request.POST) form = forms.OrganizationForm(request.POST)
# upload logo # upload logo
image = request.FILES.get("logo")
file_name = default_storage.save("images/{}".format(image.name), image)
file_url = default_storage.url(file_name)
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"
} }
@ -1831,7 +1827,12 @@ def OrganizationCreateView(request):
"email": organization_dict["email"], "email": organization_dict["email"],
} }
) )
organization_dict["logo"] = file_url image = request.FILES.get("logo")
if image:
file_name = default_storage.save("images/{}".format(image.name), image)
file_url = default_storage.url(file_name)
organization_dict["logo"] = file_url
organization_dict["pk"] = str(instance.pk) organization_dict["pk"] = str(instance.pk)
instance.additional_info["organization_info"] = organization_dict instance.additional_info["organization_info"] = organization_dict
instance.additional_info["type"] = "organization" instance.additional_info["type"] = "organization"
@ -2475,6 +2476,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()
print(finance_data.get("cars"))
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()
@ -2609,11 +2611,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()
print(
(finance_data["total_vat_amount"] + finance_data["total_price"])
== finance_data["grand_total"]
)
kwargs["data"] = finance_data kwargs["data"] = finance_data
kwargs["payments"] = JournalEntryModel.objects.filter( kwargs["payments"] = JournalEntryModel.objects.filter(
ledger=invoice.ledger ledger=invoice.ledger
@ -2954,11 +2952,10 @@ class LeadCreateView(CreateView, SuccessMessageMixin, LoginRequiredMixin):
model = models.Lead model = models.Lead
form_class = forms.LeadForm form_class = forms.LeadForm
template_name = "crm/leads/lead_form.html" template_name = "crm/leads/lead_form.html"
# success_message = "Lead created successfully!" success_message = "Lead created successfully!"
success_url = reverse_lazy("lead_list") success_url = reverse_lazy("lead_list")
def form_valid(self, form): def form_valid(self, form):
print("Form data:", form.cleaned_data) # Debug form data
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
form.instance.dealer = dealer form.instance.dealer = dealer
return super().form_valid(form) return super().form_valid(form)
@ -2981,10 +2978,11 @@ class LeadUpdateView(UpdateView):
success_url = reverse_lazy("lead_list") success_url = reverse_lazy("lead_list")
class LeadDeleteView(DeleteView): def LeadDeleteView(request,pk):
model = models.Lead lead = get_object_or_404(models.Lead, pk=pk)
template_name = "crm/leads/lead_confirm_delete.html" lead.delete()
success_url = reverse_lazy("lead_list") messages.success(request, "Lead deleted successfully!")
return redirect("lead_list")
def add_note_to_lead(request, pk): def add_note_to_lead(request, pk):
@ -3002,6 +3000,74 @@ def add_note_to_lead(request, pk):
form = forms.NoteForm() form = forms.NoteForm()
return render(request, "crm/add_note.html", {"form": form, "lead": lead}) return render(request, "crm/add_note.html", {"form": form, "lead": lead})
def lead_convert(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
dealer = get_user_type(request)
lead.convert_to_customer(dealer.entity)
messages.success(request, "Lead converted to customer successfully!")
return redirect("lead_list")
def schedule_lead(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
if request.method == "POST":
form = forms.ScheduleForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.lead = lead
instance.customer = lead.customer
if hasattr(request.user, "staff"):
instance.scheduled_by = request.user.staff
instance.save()
messages.success(request, "Lead scheduled successfully!")
return redirect("lead_list")
else:
messages.error(request, f"Invalid form data: {str(form.errors)}")
return redirect("lead_list")
form = forms.ScheduleForm()
return render(request, "crm/leads/schedule_lead.html", {"lead": lead, "form": form})
def send_lead_email(request, pk):
lead = get_object_or_404(models.Lead, pk=pk)
dealer = get_user_type(request)
lead.convert_to_customer(dealer.entity)
if request.method == "POST":
send_email(
"manager@tenhal.com",
request.POST.get("to"),
request.POST.get("subject"),
request.POST.get("message"),
)
messages.success(request, "Email sent successfully!")
return redirect("lead_list")
msg = f"""
السلام عليكم
Dear {lead.full_name},
أود أن أشارككم تقدير المشروع الذي ناقشناه. يرجى العثور على الوثيقة التفصيلية للمقترح المرفقة.
I hope this email finds you well. I wanted to share with you the estimate for the project we discussed. Please find the detailed estimate document attached.
يرجى مراجعة المقترح وإعلامي إذا كانت لديك أي أسئلة أو مخاوف. إذا كانت كل شيء يبدو جيدًا، يمكننا المضي قدمًا في المشروع.
Please review the estimate and let me know if you have any questions or concerns. If everything looks good, we can proceed with the project.
شكراً لاهتمامكم بهذا الأمر.
Thank you for your attention to this matter.
تحياتي,
Best regards,
[Your Name]
[Your Position]
[Your Company]
[Your Contact Information]
"""
return render(
request,
"crm/leads/lead_send.html",
{"lead": lead, "message": msg},
)
def add_activity_to_lead(request, pk): def add_activity_to_lead(request, pk):
lead = get_object_or_404(models.Lead, pk=pk) lead = get_object_or_404(models.Lead, pk=pk)
@ -3244,29 +3310,23 @@ class BillDetailView(LoginRequiredMixin, DetailView):
if bill.get_itemtxs_data(): if bill.get_itemtxs_data():
txs = bill.get_itemtxs_data()[0] txs = bill.get_itemtxs_data()[0]
car_and_item_info = [ transactions = [
{ {
"car": models.Car.objects.get(vin=x.item_model.name), "item": x,
"total": models.Car.objects.get( "total": Decimal(x.unit_cost) * Decimal(x.quantity),
vin=x.item_model.name
).finances.cost_price
* Decimal(x.quantity),
"itemmodel": x,
} }
for x in txs for x in txs
] ]
grand_total = sum( grand_total = sum(
Decimal( Decimal(x.unit_cost) * Decimal(x.quantity)
models.Car.objects.get(vin=x.item_model.name).finances.cost_price
)
* Decimal(x.quantity)
for x in txs for x in txs
) )
vat = models.VatRate.objects.filter(is_active=True).first() # vat = models.VatRate.objects.filter(is_active=True).first()
if vat: # if vat:
grand_total += round(Decimal(grand_total) * Decimal(vat.rate), 2) # grand_total += round(Decimal(grand_total) * Decimal(vat.rate), 2)
kwargs["car_and_item_info"] = car_and_item_info kwargs["transactions"] = transactions
kwargs["grand_total"] = grand_total kwargs["grand_total"] = grand_total
print(dir(txs[0]))
return super().get_context_data(**kwargs) return super().get_context_data(**kwargs)
@ -3345,7 +3405,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."))
@ -3488,9 +3548,7 @@ def bill_create(request):
), ),
} }
) )
car_list = models.Car.objects.filter( car_list = models.Car.objects.filter(dealer=dealer)
dealer=dealer, finances__selling_price__gt=0, status="available"
)
context = { context = {
"form": form, "form": form,
"items": [ "items": [

View File

@ -52,7 +52,6 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"
integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script> crossorigin="anonymous" referrerpolicy="no-referrer"></script>
{% block customCSS %} {% block customCSS %}
@ -135,10 +134,8 @@ function notify(tag,msg){
<script src="https://unpkg.com/htmx.org@2.0.4"></script> <script src="https://unpkg.com/htmx.org@2.0.4"></script>
<script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script> <script src="{% static 'vendors/swiper/swiper-bundle.min.js' %}"></script>
<script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script> <script src="{% static 'vendors/flatpickr/flatpickr.min.js' %}"></script>
<script>
<script>
{% if entity_slug %} {% if entity_slug %}
let entitySlug = "{{ view.kwargs.entity_slug }}" let entitySlug = "{{ view.kwargs.entity_slug }}"
{% endif %} {% endif %}

View File

@ -1,8 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static %} {% load i18n static %}
{% block content %} {% block content %}
<div class="row g-3"> <div class="row g-3">
<div class="col-12"> <div class="col-12">
<div class="row align-items-center justify-content-between g-3 mb-3"> <div class="row align-items-center justify-content-between g-3 mb-3">

View File

@ -1,5 +1,6 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n static crispy_forms_filters %} {% load i18n static crispy_forms_filters %}
{% block content %} {% block content %}
<h1>{% if object %}Update{% else %}Create{% endif %}</h1> <h1>{% if object %}Update{% else %}Create{% endif %}</h1>
<form method="post"> <form method="post">

View File

@ -36,13 +36,12 @@
<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: 10%;">{{ _("Status")|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: 25%;"> <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-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="user"></span></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>
<span>{{ _("Name")|capfirst }}</span> <span>{{ _("Car")|capfirst }}</span>
</div> </div>
</th> </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">
@ -56,12 +55,24 @@
<span>{{ _("Phone Number") }}</span> <span>{{ _("Phone Number") }}</span>
</div> </div>
</th> </th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 15%;">
<div class="d-inline-flex flex-center">
<div class="d-flex align-items-center px-1 py-1 bg-primary-subtle rounded me-2"><span class="text-primary-dark" data-feather="phone"></span></div>
<span>{{ _("Schedule") }}</span>
</div>
</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-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div>
<span>{{ _("Assigned To")|capfirst }}</span>
</div>
</th>
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center"> <div class="d-inline-flex flex-center">
<div class="d-flex align-items-center bg-info-subtle rounded me-2"><span class="text-info-dark" data-feather="database"></span></div> <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> <span>{{ _("Source")|capfirst }}</span>
</div> </div>
</th> </th>``
<th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;"> <th class="align-middle white-space-nowrap text-uppercase" scope="col" style="width: 10%;">
<div class="d-inline-flex flex-center"> <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> <div class="d-flex align-items-center bg-warning-subtle rounded me-2"><span class="text-warning-dark" data-feather="grid"></span></div>
@ -101,29 +112,39 @@
</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="align-middle white-space-nowrap fw-semibold"> <td class="name align-middle white-space-nowrap ps-0">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center"><a href="#!">
{% if lead.status == "new" %} </a>
<span class="badge badge-phoenix badge-phoenix-primary"><span class="badge-label">{{_("New")}}</span><span class="fa fa-bell ms-1"></span></span> <div><a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{lead.full_name}}</a>
{% elif lead.status == "pending" %} <div class="d-flex align-items-center">
<span class="badge badge-phoenix badge-phoenix-warning"><span class="badge-label">{{_("Pending")}}</span><span class="fa fa-clock-o ms-1"></span></span> <p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p>
{% elif lead.status == "in_progress" %} {% if lead.status == "new" %}
<span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{_("In Progress")}}</span><span class="fa fa-wrench ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-primary"><span class="badge-label">{{_("New")}}</span><span class="fa fa-bell ms-1"></span></span>
{% elif lead.status == "qualified" %} {% elif lead.status == "pending" %}
<span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{_("Qualified")}}</span><span class="fa fa-check ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-warning"><span class="badge-label">{{_("Pending")}}</span><span class="fa fa-clock-o ms-1"></span></span>
{% elif lead.status == "canceled" %} {% elif lead.status == "in_progress" %}
<span class="badge badge-phoenix badge-phoenix-danger"><span class="badge-label">{{_("Canceled")}}</span><span class="fa fa-times ms-1"></span></span> <span class="badge badge-phoenix badge-phoenix-info"><span class="badge-label">{{_("In Progress")}}</span><span class="fa fa-wrench ms-1"></span></span>
{% endif %} {% elif lead.status == "qualified" %}
<span class="badge badge-phoenix badge-phoenix-success"><span class="badge-label">{{_("Qualified")}}</span><span class="fa fa-check ms-1"></span></span>
{% elif lead.status == "canceled" %}
<span class="badge badge-phoenix badge-phoenix-danger"><span class="badge-label">{{_("Canceled")}}</span><span class="fa fa-times ms-1"></span></span>
{% endif %}
</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.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"> <td class="align-middle white-space-nowrap fw-semibold">
<div class="d-flex align-items-center"> {% if lead.get_latest_schedule %}
<a class="fs-8 fw-bold" href="{% url 'lead_detail' lead.pk %}">{{ lead.customer.get_full_name }}</a> <span class="text-success" data-feather="calendar"></span> <span class="badge badge-phoenix badge-phoenix-primary text-success fw-semibold">{{ lead.get_latest_schedule.scheduled_type }}</span> <br>
</div> <span class="text-success" data-feather="clock"></span> <span class="badge badge-phoenix badge-phoenix-primary text-success fw-semibold">{{ lead.get_latest_schedule.scheduled_at }}</span>
</td> {% endif %}
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="">{{ lead.customer.email }}</a></td> </td>
<td class="align-middle white-space-nowrap fw-semibold"><a class="text-body-highlight" href="tel:{{ lead.customer.phone_number }}">{{ lead.customer.phone_number }}</a></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 text-body-tertiary">{{ lead.created|date }}</td> <td class="align-middle white-space-nowrap text-body-tertiary text-opacity-85 text-body-tertiary">{{ lead.created|date }}</td>
@ -141,6 +162,11 @@
</button> </button>
<div class="dropdown-menu dropdown-menu-end py-2"> <div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'lead_update' lead.id %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a> <a href="{% url 'lead_update' lead.id %}" class="dropdown-item text-success-dark">{% trans "Edit" %}</a>
<a href="{% url 'send_lead_email' lead.id %}" class="dropdown-item text-success-dark">{% trans "Send Email" %}</a>
<a href="{% url 'schedule_lead' lead.id %}" class="dropdown-item text-success-dark">{% trans "Set Schedule" %}</a>
{% if not lead.is_converted %}
<a href="{% url 'lead_convert' lead.id %}" class="dropdown-item text-success-dark">{% trans "Convert To Customer" %}</a>
{% endif %}
<div class="dropdown-divider"></div> <div class="dropdown-divider"></div>
<button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button> <button class="dropdown-item text-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">{% trans "Delete" %}</button>
</div> </div>

View File

@ -0,0 +1,36 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n static %}
{% block title %}{{ _("Leads") }}{% endblock title %}
{% block content %}
<div class="card email-content">
<h5 class="card-header">Send Mail</h5>
<div class="card-body">
<form class="d-flex flex-column h-100" action="{% url 'send_lead_email' lead.pk %}" method="post">
{% csrf_token %}
<div class="row g-3 mb-2">
<div class="col-12">
<input class="form-control" name="to" type="text" placeholder="To" value="{{lead.email}}" />
</div>
<div class="col-12">
<input class="form-control" name="subject" type="text" placeholder="Subject" value="" />
</div>
</div>
<div class="mb-3 flex-1">
<textarea class="form-control" name="message" rows="15" placeholder="Message">{{message}}</textarea>
</div>
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex">
<a href="{% url 'lead_detail' lead.pk %}" class="btn btn-link text-body fs-10 text-decoration-none">Discard</a>
<button class="btn btn-primary fs-10" type="submit">Send<span class="fa-solid fa-paper-plane ms-1"></span></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,21 @@
{% extends 'base.html' %}
{% load i18n static crispy_forms_filters %}
{% block content %}
<h1>{% if object %}Update{% else %}Create{% endif %}</h1>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button
type="submit"
name="schedule_lead"
id="lead-save"
class="btn btn-phoenix-primary"
>
{{ _("Save") }}
</button>
<a href="{% url 'lead_list' %}" class="btn btn-phoenix-secondary">
{{ _("Cancel") }}
</a>
</form>
{% endblock %}

View File

@ -56,7 +56,7 @@
<!-- ============================================--> <!-- ============================================-->
<!-- <section> begin ============================--> <!-- <section> begin ============================-->
<section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top"> <section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="row-small mt-3"> <div class="row-small mt-3 mx-3">
<div class="d-flex justify-content-between align-items-end mb-4"> <div class="d-flex justify-content-between align-items-end mb-4">
<h2 class="mb-0">{% trans 'Bill' %}</h2> <h2 class="mb-0">{% trans 'Bill' %}</h2>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
@ -217,13 +217,13 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in car_and_item_info %} {% for transaction in transactions %}
<tr> <tr>
<td class="">{{forloop.counter}}</td> <td class=""></td>
<td class="">{{item.car.id_car_model}}</td> <td class="">{{transaction.item.item_model.name}}</td>
<td class="align-middle">{{item.itemmodel.quantity}}</td> <td class="align-middle">{{transaction.item.quantity}}</td>
<td class="align-middle ps-5">{{item.car.finances.cost_price}}</td> <td class="align-middle ps-5">{{transaction.item.unit_cost}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td> <td class="align-middle text-body-tertiary fw-semibold">{{transaction.total}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
@ -235,7 +235,7 @@
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="4">{% trans "Grand Total" %}</td> <td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="4">{% trans "Grand Total" %}</td>
<td class="align-middle text-start fw-bolder"> <td class="align-middle text-start fw-bolder">
<span id="grand-total">{{bill.additional_info.car_finance.total_vat}}</span> <span id="grand-total">{{grand_total}}</span>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -27,11 +27,6 @@
<span class="fas fa-chevron-right"> </span> <span class="fas fa-chevron-right"> </span>
<span class="fas fa-chevron-right"> </span> <span class="fas fa-chevron-right"> </span>
</a> </a>
<span class="fw-bold">{% trans 'Year' %}:</span>
<a href="{{ previous_year_url }}" class="text-decoration-none me-2"><< {{ previous_year }}</a>
<a href="{{ current_year_url }}" class="text-decoration-none me-2">{{ year }}</a>
<a href="{{ next_year_url }}" class="text-decoration-none">{{ next_year }} >></a>
</p> </p>
</div> </div>

View File

@ -5,14 +5,14 @@
<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.crn }}</li> <li class="list-group-item"><strong>{% trans "CRN" %}:</strong> {{ organization.additional_info.organization_info.crn }}</li>
<li class="list-group-item"><strong>{% trans "VRN" %}:</strong> {{ organization.vrn }}</li> <li class="list-group-item"><strong>{% trans "VRN" %}:</strong> {{ organization.additional_info.organization_info.vrn }}</li>
<li class="list-group-item"><strong>{% trans "Phone" %}:</strong> {{ organization.phone_number }}</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 "Address" %}:</strong> {{ organization.address }}</li> <li class="list-group-item"><strong>{% trans "Address" %}:</strong> {{ organization.additional_info.organization_info.address }}</li>
</ul> </ul>
<div class="d-flex"> <div class="d-flex">
<a href="{% url 'organization_update' organization.id %}" 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>
<form method="post" action="{% url 'organization_delete' organization.id %}"> <form method="post" action="{% url 'organization_delete' organization.pk %}">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-sm btn-danger">{% trans "Delete" %}</button> <button type="submit" class="btn btn-sm btn-danger">{% trans "Delete" %}</button>
</form> </form>

View File

@ -108,9 +108,9 @@
<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 'organization_detail' org.pk %}">{{ org.name }}</a> <div><a class="fs-8 fw-bold" href="{% url 'organization_detail' org.pk %}">{{ org.customer_name }}</a>
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<p class="mb-0 text-body-highlight fw-semibold fs-9 me-2">{{ org.arabic_name }}</p><span class="badge badge-phoenix badge-phoenix-primary">{{ org.pk}}</span> <p class="mb-0 text-body-highlight fw-semibold fs-9 me-2"></p><span class="badge badge-phoenix badge-phoenix-primary">{{ org.customer_name}}</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -33,7 +33,7 @@
<!-- <section> begin ============================--> <!-- <section> begin ============================-->
<section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top"> <section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="row-small mt-3"> <div class="row-small mt-3">
<div class="d-flex justify-content-between align-items-end mb-4"> <div class="d-flex justify-content-between align-items-end mb-4 mx-3">
<h2 class="mb-0">{% trans 'Estimate' %}</h2> <h2 class="mb-0">{% trans 'Estimate' %}</h2>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
{% if estimate.status == 'draft' %} {% if estimate.status == 'draft' %}
@ -46,7 +46,7 @@
<a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Invoice' %}</span></a> <a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Invoice' %}</span></a>
{% else %} {% else %}
<a href="{% url 'create_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Sale Order' %}</span></a> <a href="{% url 'create_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Sale Order' %}</span></a>
<a href="{% url 'preview_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview Sale Order' %}</span></a> {% comment %} <a href="{% url 'preview_sale_order' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview Sale Order' %}</span></a> {% endcomment %}
{% endif %} {% endif %}
{% elif estimate.status == 'in_review' %} {% elif estimate.status == 'in_review' %}
<a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span></a> <a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span></a>
@ -83,7 +83,7 @@
<div class="row align-items-center g-0"> <div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5"> <div class="col-auto col-lg-6 col-xl-5">
<h6 class="mb-2 me-3">{% trans 'Customer' %} :</h6> <h6 class="mb-2 me-3">{% trans 'Customer' %} :</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.customer_name}}</p> <p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.customer_name}}</p>
</div> </div>
<div class="col-12 col-lg-4"> <div class="col-12 col-lg-4">
<h6 class="mb-2"> {% trans 'Email' %} :</h6> <h6 class="mb-2"> {% trans 'Email' %} :</h6>
@ -119,7 +119,9 @@
<thead class="bg-body-secondary"> <thead class="bg-body-secondary">
<tr> <tr>
<th scope="col" style="width: 24px;">#</th> <th scope="col" style="width: 24px;">#</th>
<th scope="col" style="min-width: 260px;">{% trans "Item" %}</th> <th scope="col" style="min-width: 260px;">{% trans "Make" %}</th>
<th scope="col" style="min-width: 260px;">{% trans "Model" %}</th>
<th scope="col" style="min-width: 260px;">{% trans "Year" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th> <th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th> <th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Total" %}</th> <th scope="col" style="min-width: 60px;">{% trans "Total" %}</th>
@ -129,27 +131,29 @@
<tbody> <tbody>
{% for item in data.cars %} {% for item in data.cars %}
<tr> <tr>
<td class="">{{forloop.counter}}</td> <td class="align-middle"></td>
<td class="">{{item.make}}</td> <td class="align-middle">{{item.make}}</td>
<td class="align-middle">{{item.model}}</td>
<td class="align-middle">{{item.year}}</td>
<td class="align-middle">{{item.quantity}}</td> <td class="align-middle">{{item.quantity}}</td>
<td class="align-middle ps-5">{{item.unit_price}}</td> <td class="align-middle ps-5">{{item.unit_price}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td> <td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="4">{% trans "Vat" %} ({{data.vat}}%)</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Vat" %} ({{data.vat}}%)</td>
<td class="align-middle text-start fw-semibold"> <td class="align-middle text-start fw-semibold">
<span id="grand-total">+ {{data.total_vat_amount}}</span> <span id="grand-total">+ {{data.total_vat_amount}}</span>
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="4">{% trans "Discount Amount" %}</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Discount Amount" %}</td>
<td class="align-middle text-start text-danger fw-semibold "> <td class="align-middle text-start text-danger fw-semibold ">
<span id="grand-total">- {{data.total_discount}}</span> <span id="grand-total">- {{data.total_discount}}</span>
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="4">{% trans "Additional Services" %}</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-semibold"> <td class="align-middle text-start fw-semibold">
{% for service in data.additionals %} {% for service in data.additionals %}
<small><span class="fw-semibold">+ {{service.name}} - {{service.total}}</span></small><br> <small><span class="fw-semibold">+ {{service.name}} - {{service.total}}</span></small><br>
@ -157,7 +161,7 @@
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="4">{% trans "Grand Total" %}</td> <td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="6">{% trans "Grand Total" %}</td>
<td class="align-middle text-start fw-bolder"> <td class="align-middle text-start fw-bolder">
<span id="grand-total">{{data.grand_total}}</span> <span id="grand-total">{{data.grand_total}}</span>
</td> </td>

View File

@ -55,9 +55,9 @@
</div> </div>
<!-- ============================================--> <!-- ============================================-->
<!-- <section> begin ============================--> <!-- <section> begin ============================-->
<section class="pt-5 pb-9"> <section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="row-small mt-3"> <div class="row-small mt-3 mx-3">
<div class="d-flex justify-content-between align-items-end mb-4"> <div class="d-flex justify-content-between align-items-end mb-4 mx-3">
<h2 class="mb-0">{% trans 'Invoice' %}</h2> <h2 class="mb-0">{% trans 'Invoice' %}</h2>
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
{% if invoice.invoice_status == 'in_review' %} {% if invoice.invoice_status == 'in_review' %}
@ -212,46 +212,50 @@
<thead class="bg-body-secondary"> <thead class="bg-body-secondary">
<tr> <tr>
<th scope="col" style="width: 24px;">#</th> <th scope="col" style="width: 24px;">#</th>
<th scope="col" style="min-width: 260px;">{% trans "Item" %}</th> <th scope="col" style="min-width: 260px;">{% trans "Make" %}</th>
<th scope="col" style="min-width: 260px;">{% trans "Model" %}</th>
<th scope="col" style="min-width: 260px;">{% trans "Year" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th> <th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th> <th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Total" %}</th> <th scope="col" style="min-width: 60px;">{% trans "Total" %}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in car_and_item_info %} {% for item in data.cars %}
<tr> <tr>
<td class="">{{forloop.counter}}</td> <td class="align-middle"></td>
<td class="">{{item.info.make}}</td> <td class="align-middle">{{item.make}}</td>
<td class="align-middle">{{item.model}}</td>
<td class="align-middle">{{item.year}}</td>
<td class="align-middle">{{item.quantity}}</td> <td class="align-middle">{{item.quantity}}</td>
<td class="align-middle ps-5">{{item.finances.selling_price}}</td> <td class="align-middle ps-5">{{item.total}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td> <td class="align-middle text-body-tertiary fw-semibold">{{item.total}}</td>
</tr> </tr>
{% endfor %} {% endfor %}
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="4">{% trans "Discount Amount" %}</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Discount Amount" %}</td>
<td class="align-middle text-start fw-semibold"> <td class="align-middle text-start fw-semibold">
<span id="grand-total">- {{discount_amount}}</span> <span id="grand-total">- {{data.total_discount}}</span>
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="4">{% trans "VAT" %} ({{vat}}%)</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "VAT" %} ({{data.vat}}%)</td>
<td class="align-middle text-start fw-semibold"> <td class="align-middle text-start fw-semibold">
<span id="grand-total">+ {{data.total_vat_amount}}</span> <span id="grand-total">+ {{data.total_vat_amount}}</span>
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="4">{% trans "Additional Services" %}</td> <td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="6">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-bold"> <td class="align-middle text-start fw-bold">
{% for service in additional_services %} {% for service in data.additionals %}
<small><span class="fw-bold">+ {{service.name}} - {{service.price}}</span></small><br> <small><span class="fw-bold">+ {{service.name}} - {{service.price}}</span></small><br>
{% endfor %} {% endfor %}
</td> </td>
</tr> </tr>
<tr class="bg-body-secondary total-sum"> <tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="4">{% trans "Grand Total" %}</td> <td class="align-middle ps-4 fw-bolder text-body-highlight" colspan="6">{% trans "Grand Total" %}</td>
<td class="align-middle text-start fw-bolder"> <td class="align-middle text-start fw-bolder">
<span id="grand-total">{{total}}</span> <span id="grand-total">{{data.grand_total}}</span>
</td> </td>
</tr> </tr>
</tbody> </tbody>