Compare commits

...

3 Commits

21 changed files with 1363 additions and 725 deletions

View File

@ -583,6 +583,7 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
"price_": str(self.price_),
"taxable": self.taxable,
"uom": self.uom,
"service_tax":str(self.service_tax)
}
@property
@ -594,6 +595,13 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
else self.price
)
@property
def service_tax(self):
vat = VatRate.objects.filter(dealer=self.dealer, is_active=True).first()
return (
Decimal(self.price * vat.rate)
)
class Meta:
verbose_name = _("Additional Services")
verbose_name_plural = _("Additional Services")
@ -865,19 +873,64 @@ class Car(Base):
#
@property
def get_additional_services_amount(self):
return sum([Decimal(x.price) for x in self.additional_services.all()])
@property
def get_additional_services_amount_(self):
return sum([Decimal(x.price_) for x in self.additional_services.all()])
@property
def get_additional_services_vat(self):
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
return sum([Decimal((x.price)*(vat.rate)) for x in self.additional_services.all()])
def get_additional_services(self):
return {"services": [x for x in self.additional_services.all()],"total":self.get_additional_services_amount}
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
return {"services": [[x,(x.price)*(vat.rate)] for x in self.additional_services.all()],
"total_":self.get_additional_services_amount_,
"total":self.get_additional_services_amount,
"services_vat":self.get_additional_services_vat}
@property
def final_price(self):
return Decimal(self.marked_price -self.discount)
@property
def vat_amount(self):
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
return Decimal(self.marked_price) * (vat.rate / 100)
return Decimal(self.final_price) * (vat.rate)
@property
def total_vat(self):
return Decimal(self.marked_price) + Decimal(self.vat_amount)
def total_services_and_car_vat(self):
return self.vat_amount+self.get_additional_services()['services_vat']
@property
def final_price_plus_vat(self):
return Decimal(self.final_price) + Decimal(self.vat_amount)
@property
def final_price_plus_services_plus_vat(self):
return Decimal(self.final_price_plus_vat) + Decimal(self.get_additional_services()['total_']) #total services with vat and car_sell price with vat
# to be used after invoice is created
@property
def invoice(self):
return self.item_model.invoicemodel_set.first() or None
@property
def estimate(self):
return getattr(self.invoice,'ce_model',None)
@property
def discount(self):
if not self.estimate:
return 0
try:
instance = ExtraInfo.objects.get(
dealer=self.dealer,
content_type=ContentType.objects.get_for_model(EstimateModel),
object_id=self.estimate.pk,
)
return Decimal(instance.data.get('discount',0))
except ExtraInfo.DoesNotExist:
return Decimal(0)
# def get_discount_amount(self,estimate,user):
# try:
# instance = models.ExtraInfo.objects.get(

View File

@ -22,6 +22,11 @@ from django.shortcuts import get_object_or_404
from django.urls import reverse
from django_ledger.models import ItemTransactionModel,InvoiceModel,LedgerModel,EntityModel
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView
from django_ledger.forms.chart_of_accounts import (
ChartOfAccountsModelCreateForm,
ChartOfAccountsModelUpdateForm,
)
from django_ledger.forms.purchase_order import (
ApprovedPurchaseOrderModelUpdateForm,
BasePurchaseOrderModelUpdateForm,
@ -30,7 +35,7 @@ from django_ledger.forms.purchase_order import (
get_po_itemtxs_formset_class,
)
from django_ledger.views.purchase_order import PurchaseOrderModelModelViewQuerySetMixIn
from django_ledger.models import PurchaseOrderModel, EstimateModel, BillModel
from django_ledger.models import PurchaseOrderModel, EstimateModel, BillModel, ChartOfAccountModel
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import UpdateView
from django.views.generic.base import RedirectView
@ -973,3 +978,112 @@ class InvoiceModelUpdateView(LoginRequiredMixin, PermissionRequiredMixin, Update
# if not valid, return formset with errors...
return self.render_to_response(context=self.get_context_data(itemtxs_formset=itemtxs_formset))
return super(InvoiceModelUpdateView, self).post(request, **kwargs)
class ChartOfAccountModelModelBaseViewMixIn(LoginRequiredMixin, PermissionRequiredMixin):
queryset = None
permission_required = []
def get_queryset(self):
if self.queryset is None:
entity_model = self.request.dealer.entity
self.queryset = entity_model.chartofaccountmodel_set.all().order_by('-updated')
return super().get_queryset()
def get_redirect_url(self, *args, **kwargs):
return reverse('coa-list', kwargs={'dealer_slug': self.request.dealer.slug,
'entity_slug': self.request.entity.slug})
class ChartOfAccountModelListView(ChartOfAccountModelModelBaseViewMixIn, ListView):
template_name = 'chart_of_accounts/coa_list.html'
context_object_name = 'coa_list'
inactive = False
def get_queryset(self):
qs = super().get_queryset()
if self.inactive:
return qs.filter(active=False)
return qs.active()
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=None, **kwargs)
context['inactive'] = self.inactive
context['header_subtitle'] = self.request.entity.name
context['header_subtitle_icon'] = 'gravity-ui:hierarchy'
context['page_title'] = 'Inactive Chart of Account List' if self.inactive else 'Chart of Accounts List'
context['header_title'] = 'Inactive Chart of Account List' if self.inactive else 'Chart of Accounts List'
return context
class ChartOfAccountModelCreateView(ChartOfAccountModelModelBaseViewMixIn, CreateView):
template_name = 'chart_of_accounts/coa_create.html'
extra_context = {
'header_title': _('Create Chart of Accounts'),
'page_title': _('Create Chart of Account'),
}
def get_initial(self):
return {
'entity': self.request.entity,
}
def get_form(self, form_class=None):
return ChartOfAccountsModelCreateForm(
entity_model=self.request.entity,
**self.get_form_kwargs()
)
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=None, **kwargs)
context['header_subtitle'] = f'New Chart of Accounts: {self.request.entity.name}'
context['header_subtitle_icon'] = 'gravity-ui:hierarchy'
return context
def get_success_url(self):
return reverse('coa-list', kwargs={'dealer_slug': self.request.dealer.slug,
'entity_slug': self.request.entity.slug})
class ChartOfAccountModelUpdateView(ChartOfAccountModelModelBaseViewMixIn, UpdateView):
context_object_name = 'coa_model'
slug_url_kwarg = 'coa_slug'
template_name = 'chart_of_accounts/coa_update.html'
form_class = ChartOfAccountsModelUpdateForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
chart_of_accounts_model: ChartOfAccountModel = self.object
context['page_title'] = f'Update Chart of Account {chart_of_accounts_model.name}'
context['header_title'] = f'Update Chart of Account {chart_of_accounts_model.name}'
return context
def get_success_url(self):
return reverse('coa-list', kwargs={'dealer_slug': self.request.dealer.slug,
'entity_slug': self.request.entity.slug})
class CharOfAccountModelActionView(ChartOfAccountModelModelBaseViewMixIn,
RedirectView,
SingleObjectMixin):
http_method_names = ['get']
slug_url_kwarg = 'coa_slug'
action_name = None
commit = True
def get(self, request, *args, **kwargs):
kwargs['user_model'] = self.request.user
if not self.action_name:
raise ImproperlyConfigured('View attribute action_name is required.')
response = super(CharOfAccountModelActionView, self).get(request, *args, **kwargs)
coa_model: ChartOfAccountModel = self.get_object()
try:
getattr(coa_model, self.action_name)(commit=self.commit, **kwargs)
messages.add_message(request, level=messages.SUCCESS, extra_tags='is-success',
message=_('Successfully updated {} Default Chart of Account to '.format(
request.entity.name) +
'{}'.format(coa_model.name)))
except ValidationError as e:
messages.add_message(request,
message=e.message,
level=messages.ERROR,
extra_tags='is-danger')
return response

View File

@ -43,7 +43,7 @@ urlpatterns = [
#dashboards
path("dashboards/dealer/", views.DealerDashboard.as_view(),name="dealer_dashboard"),
path("dashboards/dealer/", views.DealerDashboard,name="dealer_dashboard"),
path( "dashboards/manager/", views.ManagerDashboard.as_view(),name="manager_dashboard"),
path("dashboards/sales/", views.SalesDashboard.as_view(), name="sales_dashboard"),
path("dashboards/accountant/", views.AccountantDashboard.as_view(), name="accountant_dashboard"),
@ -738,27 +738,27 @@ urlpatterns = [
name="bank_account_delete",
),
path(
"<slug:dealer_slug>/coa_accounts/",
"<slug:dealer_slug>/coa_accounts/<coa_pk>/",
views.AccountListView.as_view(),
name="account_list",
),
path(
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/",
"<slug:dealer_slug>/coa_accounts/<coa_pk>/<uuid:pk>/",
views.AccountDetailView.as_view(),
name="account_detail",
),
path(
"<slug:dealer_slug>/coa_accounts/create/",
"<slug:dealer_slug>/coa_accounts/<coa_pk>/create/",
views.AccountCreateView.as_view(),
name="account_create",
),
path(
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/update/",
"<slug:dealer_slug>/coa_accounts/<coa_pk>/<uuid:pk>/update/",
views.AccountUpdateView.as_view(),
name="account_update",
),
path(
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/delete/",
"<slug:dealer_slug>/coa_accounts/<coa_pk>/<uuid:pk>/delete/",
views.account_delete,
name="account_delete",
),
@ -775,6 +775,7 @@ urlpatterns = [
views.EstimateDetailView.as_view(),
name="estimate_detail",
),
path('<slug:dealer_slug>/sales/estimates/print/<uuid:pk>/', views.EstimatePrintView.as_view(), name='estimate_print'),
path(
"<slug:dealer_slug>/sales/estimates/create/",
views.create_estimate,
@ -1093,6 +1094,29 @@ urlpatterns = [
path('<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/',
views.ChartOfAccountModelListView.as_view(),
name='coa-list'),
path('<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/inactive/',
views.ChartOfAccountModelListView.as_view(inactive=True),
name='coa-list-inactive'),
path('<slug:dealer_slug>/<slug:entity_slug>/create/',
views.ChartOfAccountModelCreateView.as_view(),
name='coa-create'),
path('<slug:dealer_slug>/<slug:entity_slug>/detail/<slug:coa_slug>/',
views.ChartOfAccountModelListView.as_view(),
name='coa-detail'),
path('<slug:dealer_slug>/<slug:entity_slug>/update/<slug:coa_slug>/',
views.ChartOfAccountModelUpdateView.as_view(),
name='coa-update'),
# ACTIONS....
path('<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-default/',
views.CharOfAccountModelActionView.as_view(action_name='mark_as_default'),
name='coa-action-mark-as-default'),
path('<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-active/',
views.CharOfAccountModelActionView.as_view(action_name='mark_as_active'),
name='coa-action-mark-as-active'),
path('<slug:dealer_slug>/<slug:entity_slug>/action/<slug:coa_slug>/mark-as-inactive/',
views.CharOfAccountModelActionView.as_view(action_name='mark_as_inactive'),
name='coa-action-mark-as-inactive'),
# CASH FLOW STATEMENTS...
# Entities...
path(

View File

@ -1288,18 +1288,24 @@ def get_finance_data(estimate,dealer):
)
discount = extra_info.data.get("discount", 0)
discount = Decimal(discount)
vat_amount = car.marked_price * vat.rate
additional_services = car.get_additional_services()
additional_services = car.get_additional_services()
discounted_price=(Decimal(car.marked_price) - discount)
vat_amount = discounted_price * vat.rate
total_services_vat=sum([ x[1] for x in additional_services.get("services")])
total_vat=vat_amount+total_services_vat
return {
"car": car,
"discounted_price": (Decimal(car.marked_price) - discount) or 0,
"discounted_price": discounted_price or 0,
"price_before_discount": car.marked_price,
"vat_amount": vat_amount,
"vat_rate": vat.rate,
"discount_amount": discount,
"additional_services": additional_services,
"grand_total": (car.marked_price - discount) + vat_amount + additional_services.get("total")
"final_price": discounted_price+ vat_amount,
"total_services_vat":total_services_vat,
"total_vat":total_vat,
"grand_total": discounted_price + vat_amount + additional_services.get("total")
}

View File

@ -17,7 +17,7 @@ from random import randint
from decimal import Decimal
from io import TextIOWrapper
from django.apps import apps
from datetime import datetime, timedelta
from datetime import datetime, timedelta,date
from calendar import month_name
from pyzbar.pyzbar import decode
from urllib.parse import urlparse, urlunparse
@ -152,6 +152,10 @@ from .override import (
BaseBillActionView as BaseBillActionViewBase,
InventoryListView as InventoryListViewBase,
InvoiceModelUpdateView as InvoiceModelUpdateViewBase,
ChartOfAccountModelCreateView as ChartOfAccountModelCreateViewBase,
ChartOfAccountModelListView as ChartOfAccountModelListViewBase,
ChartOfAccountModelUpdateView as ChartOfAccountModelUpdateViewBase,
CharOfAccountModelActionView as CharOfAccountModelActionViewBase,
)
from django_ledger.models import (
@ -168,6 +172,7 @@ from django_ledger.models import (
BillModel,
LedgerModel,
PurchaseOrderModel,
ChartOfAccountModel
)
from django_ledger.views.financial_statement import (
FiscalYearBalanceSheetView,
@ -391,101 +396,164 @@ class TestView(TemplateView):
template_name = "inventory/cars_list_api.html"
class DealerDashboard(LoginRequiredMixin, TemplateView):
"""
ManagerDashboard class is a view handling the dashboard for a manager.
# class DealerDashboard(LoginRequiredMixin, TemplateView):
# """
# ManagerDashboard class is a view handling the dashboard for a manager.
Provides functionality to manage and view various statistics and data specific
to the dealer associated with the authenticated manager. It uses a specific
template and ensures authentication before granting access. The class
aggregates data about cars, leads, financial statistics, and other related
business information for display in the manager's dashboard.
# Provides functionality to manage and view various statistics and data specific
# to the dealer associated with the authenticated manager. It uses a specific
# template and ensures authentication before granting access. The class
# aggregates data about cars, leads, financial statistics, and other related
# business information for display in the manager's dashboard.
:ivar template_name: Path to the template used for rendering the manager's dashboard.
:type template_name: str
"""
# :ivar template_name: Path to the template used for rendering the manager's dashboard.
# :type template_name: str
# """
template_name = "dashboards/dealer_dashbaord.html"
# template_name = "dashboards/dealer_dashbaord.html"
# def dispatch(self, request, *args, **kwargs):
# if not request.user.is_authenticated:
# return redirect("welcome")
# if not getattr(request.user, "dealer", False):
# return HttpResponseForbidden(
# "You are not authorized to view this dashboard."
# )
# return super().dispatch(request, *args, **kwargs)
# # def dispatch(self, request, *args, **kwargs):
# # if not request.user.is_authenticated:
# # return redirect("welcome")
# # if not getattr(request.user, "dealer", False):
# # return HttpResponseForbidden(
# # "You are not authorized to view this dashboard."
# # )
# # return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request)
entity = dealer.entity
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# dealer = get_user_type(self.request)
# entity = dealer.entity
qs = models.Car.objects.filter(dealer=dealer)
total_cars = qs.count()
# qs = models.Car.objects.filter(dealer=dealer)
# total_cars = qs.count()
stats = models.CarFinance.objects.filter(car__dealer=dealer).aggregate(
total_cost_price=Sum("cost_price"),
total_selling_price=Sum("selling_price"),
# # stats = models.CarFinance.objects.filter(car__dealer=dealer).aggregate(
# # total_cost_price=Sum("cost_price"),
# # total_selling_price=Sum("selling_price"),
# # )
# # total_cost_price = stats["total_cost_price"] or 0
# # total_selling_price = stats["total_selling_price"] or 0
# # total_profit = total_selling_price - total_cost_price
# # new_leads = models.Lead.objects.filter(
# # dealer=dealer, status=models.Status.NEW
# # ).count()
# # pending_leads = models.Lead.objects.filter(
# # dealer=dealer, status=models.Status.CONTACTED
# # ).count()
# # canceled_leads = models.Lead.objects.filter(
# # dealer=dealer, status=models.Status.UNQUALIFIED
# # ).count()
# # car_status_qs = qs.values("status").annotate(count=Count("status"))
# # car_status = {status: count for status, count in car_status_qs}
# # car_by_make_qs = qs.values("id_car_make__name").annotate(count=Count("id"))
# # car_by_make = list(car_by_make_qs)
# # context["dealer"] = dealer
# # context["total_activity"] = models.UserActivityLog.objects.filter(
# # user=dealer.user
# # ).count()
# # context["total_cars"] = total_cars
# # context["total_reservations"] = models.CarReservation.objects.filter(
# # reserved_until__gte=timezone.now()
# # ).count()
# # context["total_cost_price"] = total_cost_price
# # context["total_selling_price"] = total_selling_price
# # context["total_profit"] = total_profit
# # context["new_leads"] = new_leads
# # context["pending_leads"] = pending_leads
# # context["canceled_leads"] = canceled_leads
# # context["car"] = json.dumps(car_by_make)
# # context["available_cars"] =qs.filter(status='available').count()
# # context["sold_cars"] = qs.filter(status='sold').count()
# # context["reserved_cars"] = qs.filter(status='reserved').count()
# # context["hold_cars"] =qs.filter(status='hold').count()
# # context["damaged_cars"] = qs.filter(status='damaged').count()
# # context["transfer_cars"] = qs.filter(status='transfer').count()
# # context["present_inventory_count"]=total_cars-context["sold_cars"]-context["damaged_cars"]
# # cars_sold=qs.filter(status='sold')
# # cars_sold.aggregate(total_inventory_value=sum())
# context["customers"] = entity.get_customers().count()
# context["staff"] = models.Staff.objects.filter(dealer=dealer).count()
# context["total_leads"] = models.Lead.objects.filter(dealer=dealer).count()
# context["invoices"] = entity.get_invoices().count()
# context["estimates"] = entity.get_estimates().count()
# context["purchase_orders"] = entity.get_purchase_orders().count()
# return context
def DealerDashboard(request):
dealer = request.dealer
cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
today_local = timezone.localdate()
start_date_str = request.GET.get('start_date')
end_date_str = request.GET.get('end_date')
if not start_date_str:
start_date = today_local - timedelta(days=30)
else:
start_date = timezone.datetime.strptime(start_date_str, '%Y-%m-%d').date()
if not end_date_str:
end_date = today_local
else:
end_date = timezone.datetime.strptime(end_date_str, '%Y-%m-%d').date()
# The database query will automatically be handled in a timezone-aware manner
cars_sold_filtered = cars_sold.filter(
sold_date__date__gte=start_date,
sold_date__date__lte=end_date
)
total_cost_price = stats["total_cost_price"] or 0
total_selling_price = stats["total_selling_price"] or 0
total_profit = total_selling_price - total_cost_price
print(cars_sold_filtered)
# # Calculate summary data for the filtered results
total_cars_sold=cars_sold_filtered.count()
print(total_cars_sold)
total_revenue_from_cars = sum([ car.final_price for car in cars_sold_filtered])
total_cost_of_cars_sold=sum([car.cost_price for car in cars_sold_filtered])
net_profit_from_cars=total_revenue_from_cars-total_cost_of_cars_sold
total_vat_collected_from_cars=sum([car.vat_amount for car in cars_sold_filtered])
total_revenue_from_services=sum([car.get_additional_services()['total'] for car in cars_sold_filtered])
total_vat_collected_from_services=sum([car.get_additional_services()['services_vat'] for car in cars_sold_filtered])
total_vat_collected = total_vat_collected_from_cars+total_vat_collected_from_services
total_revenue_generated=total_revenue_from_cars+total_revenue_from_services
total_discount = sum([car.discount for car in cars_sold_filtered])
new_leads = models.Lead.objects.filter(
dealer=dealer, status=models.Status.NEW
).count()
pending_leads = models.Lead.objects.filter(
dealer=dealer, status=models.Status.CONTACTED
).count()
canceled_leads = models.Lead.objects.filter(
dealer=dealer, status=models.Status.UNQUALIFIED
).count()
context = {
'start_date': start_date,
'end_date': end_date,
'cars_sold': cars_sold_filtered,
'total_cars_sold':total_cars_sold,
'total_cost_of_cars_sold':total_cost_of_cars_sold,
'total_revenue_from_cars':total_revenue_from_cars,
'net_profit_from_cars':net_profit_from_cars,
'total_vat_collected_from_cars': total_vat_collected_from_cars,
'total_discount_on_cars':total_discount,
'total_revenue_from_services':total_revenue_from_services,
'total_vat_collected_from_services': total_vat_collected_from_services,
'total_revenue_generated': total_revenue_generated,
'total_vat_collected':total_vat_collected,
car_status_qs = qs.values("status").annotate(count=Count("status"))
car_status = {status: count for status, count in car_status_qs}
}
car_by_make_qs = qs.values("id_car_make__name").annotate(count=Count("id"))
car_by_make = list(car_by_make_qs)
context["dealer"] = dealer
context["total_activity"] = models.UserActivityLog.objects.filter(
user=dealer.user
).count()
context["total_cars"] = total_cars
context["total_reservations"] = models.CarReservation.objects.filter(
reserved_until__gte=timezone.now()
).count()
context["total_cost_price"] = total_cost_price
context["total_selling_price"] = total_selling_price
context["total_profit"] = total_profit
context["new_leads"] = new_leads
context["pending_leads"] = pending_leads
context["canceled_leads"] = canceled_leads
context["car"] = json.dumps(car_by_make)
context["available_cars"] =qs.filter(status='available').count()
context["sold_cars"] = qs.filter(status='sold').count()
context["reserved_cars"] = qs.filter(status='reserved').count()
context["hold_cars"] =qs.filter(status='hold').count()
context["damaged_cars"] = qs.filter(status='damaged').count()
context["transfer_cars"] = qs.filter(status='transfer').count()
context["present_inventory_count"]=total_cars-context["sold_cars"]-context["damaged_cars"]
cars_sold=qs.filter(status='sold')
# cars_sold.aggregate(total_inventory_value=sum())
context["customers"] = entity.get_customers().count()
context["staff"] = models.Staff.objects.filter(dealer=dealer).count()
context["total_leads"] = models.Lead.objects.filter(dealer=dealer).count()
context["invoices"] = entity.get_invoices().count()
context["estimates"] = entity.get_estimates().count()
context["purchase_orders"] = entity.get_purchase_orders().count()
return render(request, 'dashboards/dealer_dashboard.html', context)
return context
class ManagerDashboard(LoginRequiredMixin, TemplateView):
"""
@ -4333,6 +4401,10 @@ class AccountListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
dealer = get_user_type(self.request)
accounts = dealer.entity.get_all_accounts()
return apply_search_filters(accounts, query)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["url_kwargs"] = self.kwargs
return context
class AccountCreateView(
@ -4398,10 +4470,17 @@ class AccountCreateView(
def get_success_url(self):
return reverse(
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"], "coa_pk": self.kwargs["coa_pk"]}
)
def get_context_data(self,**kwargs):
context = super().get_context_data(**kwargs)
context["url_kwargs"] = self.kwargs
coa_pk = context["url_kwargs"]["coa_pk"]
try:
kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa()
except Exception:
kwargs["coa_model"] = self.request.entity.get_default_coa()
return context
class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
"""
Represents the detailed view for an account with additional context data related to account
@ -4459,6 +4538,7 @@ class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView)
"journal_entry__ledger__billmodel",
"journal_entry__ledger__invoicemodel",
)
context["url_kwargs"] = self.kwargs
return context
@ -4502,13 +4582,21 @@ class AccountUpdateView(
def get_success_url(self):
return reverse_lazy(
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"]}
"account_list", kwargs={"dealer_slug": self.kwargs["dealer_slug"],"coa_pk":self.kwargs["coa_pk"]}
)
def get_context_data(self,**kwargs):
context = super().get_context_data(**kwargs)
context["url_kwargs"] = self.kwargs
coa_pk = context["url_kwargs"]["coa_pk"]
try:
kwargs["coa_model"] = ChartOfAccountModel.objects.get(pk=coa_pk) or self.request.entity.get_default_coa()
except Exception:
kwargs["coa_model"] = self.request.entity.get_default_coa()
return context
@login_required
@permission_required("django_ledger.delete_accountmodel")
def account_delete(request, dealer_slug, pk):
def account_delete(request, dealer_slug,coa_pk, pk):
"""
Handles the deletion of an account object identified by its primary key (pk). Ensures
that the user has the necessary permissions to perform the deletion. Successfully
@ -4527,7 +4615,7 @@ def account_delete(request, dealer_slug, pk):
account.delete()
messages.success(request, _("Account deleted successfully"))
return redirect("account_list", dealer_slug=dealer_slug)
return redirect("account_list", dealer_slug=dealer_slug, coa_pk=coa_pk)
# Sales list
@ -4815,7 +4903,7 @@ def create_estimate(request, dealer_slug, slug=None):
"quantity": 1,
"unit_cost": round(float(i.marked_price)),
"unit_revenue": round(float(i.marked_price)),
"total_amount": round(float(i.total_vat)),# TODO : check later
"total_amount": round(float(i.final_price_plus_vat)),# TODO : check later
}
)
@ -4836,7 +4924,7 @@ def create_estimate(request, dealer_slug, slug=None):
# "unit_cost": instance.cost_price,
# "unit_revenue": instance.marked_price,
# "quantity": Decimal(quantities),
# "total_amount": instance.total_vat * int(quantities),# TODO : check later
# "total_amount": instance.final_price_plus_vat * int(quantities),# TODO : check later
# }
# }
@ -4994,6 +5082,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
# calculator = CarFinanceCalculator(estimate)
# finance_data = calculator.get_finance_data()
finance_data = get_finance_data(estimate,dealer)
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
kwargs["data"] = finance_data
@ -5002,7 +5091,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
car = estimate.get_itemtxs_data()[0].first().item_model.car
selected_items = car.additional_services.filter(dealer=dealer)
form = forms.AdditionalFinancesForm()
form.fields["additional_finances"].queryset = form.fields["additional_finances"].queryset.filter(dealer=dealer) # TODO : check later
form.fields["additional_finances"].queryset = form.fields["additional_finances"].queryset.filter(dealer=dealer) #
form.initial["additional_finances"] = selected_items
kwargs["additionals_form"] = form
except Exception as e:
@ -5010,6 +5099,16 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
return super().get_context_data(**kwargs)
class EstimatePrintView(EstimateDetailView):
"""
A view to render a printer-friendly version of the estimate.
It reuses the data-fetching logic from EstimateDetailView but
uses a dedicated, stripped-down print template.
"""
template_name = "sales/estimates/estimate_preview.html"
@login_required
@permission_required("inventory.add_saleorder", raise_exception=True)
def create_sale_order(request, dealer_slug, pk):
@ -5061,7 +5160,8 @@ def create_sale_order(request, dealer_slug, pk):
f"KeyError: 'car_info' or 'status' key missing when attempting to update status to 'sold' for item.item_model PK: {getattr(item.item_model, 'pk', 'N/A')}."
)
pass
item.item_model.car.sold_date=timezone.now() # to be checked added by faheed
item.item_model.car.save()# to be checked added byfaheed
item.item_model.car.mark_as_sold()
messages.success(request, "Sale Order created successfully")
@ -11028,11 +11128,13 @@ def car_sale_report_view(request, dealer_slug):
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
# Get filter parameters from the request
selected_make = request.GET.get('make')
selected_model = request.GET.get('model')
selected_serie = request.GET.get('serie')
selected_year = request.GET.get('year')
selected_stock_type=request.GET.get('stock_type')
# Apply filters to the queryset
if selected_make:
@ -11043,77 +11145,114 @@ def car_sale_report_view(request, dealer_slug):
cars_sold = cars_sold.filter(id_car_serie__name=selected_serie)
if selected_year:
cars_sold = cars_sold.filter(year=selected_year)
if selected_stock_type:
cars_sold = cars_sold.filter(stock_type=selected_stock_type)
# Get distinct values for filter dropdowns
makes = models.Car.objects.filter(dealer=dealer, status='sold').values_list('id_car_make__name', flat=True).distinct()
models_qs = models.Car.objects.filter(dealer=dealer, status='sold').values_list('id_car_model__name', flat=True).distinct()
series = models.Car.objects.filter(dealer=dealer, status='sold').values_list(
'id_car_serie__name', flat=True).distinct()
series = models.Car.objects.filter(dealer=dealer, status='sold').values_list('id_car_serie__name', flat=True).distinct()
stock_types=models.Car.objects.filter(dealer=dealer, status='sold').values_list('stock_type', flat=True).distinct()
years = models.Car.objects.filter(dealer=dealer, status='sold').values_list('year', flat=True).distinct().order_by('-year')
# # Calculate summary data for the filtered results
total_revenue = cars_sold.aggregate(total_revenue=Sum('finances__marked_price'))['total_revenue'] or 0
# total_vat = cars_sold.aggregate(total_vat=Sum('finances__vat_amount'))['total_vat'] or 0
total_discount = cars_sold.aggregate(total_discount=Sum('finances__discount_amount'))['total_discount'] or 0
# # Calculate summary data for the filtered results
total_cars_sold=cars_sold.count()
total_revenue_from_cars = sum([ car.final_price for car in cars_sold])
total_vat_on_cars=sum([car.vat_amount for car in cars_sold])
total_revenue_from_additonals=sum([car.get_additional_services()['total'] for car in cars_sold])
total_vat_from_additonals=sum([car.get_additional_services()['services_vat'] for car in cars_sold])
total_vat_collected = total_vat_on_cars+total_vat_from_additonals
total_revenue_collected=total_revenue_from_cars+total_revenue_from_additonals
total_discount = sum([car.discount for car in cars_sold])
current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S")
context = {
'cars_sold': cars_sold,
'total_cars_sold':total_cars_sold,
'current_time': current_time,
'dealer': dealer,
'total_revenue': total_revenue,
# 'total_vat': total_vat,
'total_revenue_from_cars': total_revenue_from_cars,
'total_revenue_from_additonals':total_revenue_from_additonals,
'total_revenue_collected': total_revenue_collected,
'total_vat_on_cars':total_vat_on_cars,
'total_vat_from_additonals':total_vat_from_additonals,
'total_vat_collected':total_vat_collected,
'total_discount': total_discount,
'makes': makes,
'models': models_qs,
'series': series,
'years': years,
'stock_types':stock_types,
'selected_make': selected_make,
'selected_model': selected_model,
'selected_serie': selected_serie,
'selected_year': selected_year,
'selected_stock_type':selected_stock_type,
}
return render(request, 'ledger/reports/car_sale_report.html', context)
@login_required
def car_sale_report_csv_export(request, dealer_slug):
response = HttpResponse(content_type='text/csv')
current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S")
current_time = timezone.now().strftime("%Y-%m-%d_%H-%M-%S")
filename = f"sales_report_{dealer_slug}_{current_time}.csv"
response['Content-Disposition'] = f'attachment; filename="{filename}"'
writer = csv.writer(response)
# Define the CSV header based on your HTML table headers
header = [
'Make',
'VIN',
'Model',
'Year',
'Serie',
'Trim',
'Mileage',
'Stock Type',
'Created Date',
'Sold Date',
'Cost Price',
'Marked Price',
'Discount Amount',
'Selling Price',
'Tax Amount',
'Invoice Number',
'VIN', 'Make', 'Model', 'Year', 'Serie', 'Trim', 'Mileage',
'Stock Type', 'Created Date', 'Sold Date', 'Cost Price',
'Marked Price', 'Discount Amount', 'Selling Price',
'VAT on Car', 'Services Price', 'VAT on Services', 'Final Total',
'Invoice Number'
]
writer.writerow(header)
dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
# Apply filters from the request, just like in your HTML view
selected_make = request.GET.get('make')
selected_model = request.GET.get('model')
selected_serie = request.GET.get('serie')
selected_year = request.GET.get('year')
selected_stock_type = request.GET.get('stock_type')
if selected_make:
cars_sold = cars_sold.filter(id_car_make__name=selected_make)
if selected_model:
cars_sold = cars_sold.filter(id_car_model__name=selected_model)
if selected_serie:
cars_sold = cars_sold.filter(id_car_serie__name=selected_serie)
if selected_year:
cars_sold = cars_sold.filter(year=selected_year)
if selected_stock_type:
cars_sold = cars_sold.filter(stock_type=selected_stock_type)
# Write the data for the filtered cars
for car in cars_sold:
# Fetching data for the additional services
additional_services = car.get_additional_services()
services_total_price = additional_services['total']
services_vat_amount = additional_services['services_vat']
# Checking for the invoice number to avoid errors on cars without one
invoice_number = None
sold_date = None
if car.invoice:
invoice_number = car.invoice.invoice_number
sold_date = car.invoice.date_paid
writer.writerow([
car.vin,
car.id_car_make.name,
@ -11124,13 +11263,16 @@ def car_sale_report_csv_export(request,dealer_slug):
car.mileage if car.mileage else '0',
car.stock_type,
car.created_at.strftime("%Y-%m-%d %H:%M:%S") if car.created_at else '',
car.sold_date.strftime("%Y-%m-%d %H:%M:%S") if car.sold_date else '',
sold_date.strftime("%Y-%m-%d %H:%M:%S") if sold_date else '',
car.cost_price,
car.marked_price,
car.discount_amount,
car.selling_price,
car.vat_amount, # TODO : check later
car.item_model.invoicemodel_set.first().invoice_number
car.discount, # Ensure this property returns a number
car.final_price, # Selling Price without VAT
car.vat_amount, # VAT on the car
services_total_price, # Total services without VAT
services_vat_amount, # VAT on services
car.final_price_plus_services_plus_vat,
invoice_number,
])
return response
@ -11383,3 +11525,15 @@ def ticket_update(request, ticket_id):
class ChartOfAccountModelListView(ChartOfAccountModelListViewBase):
template_name = 'chart_of_accounts/coa_list.html'
permission_required = 'django_ledger.view_chartofaccountmodel'
class ChartOfAccountModelCreateView(ChartOfAccountModelCreateViewBase):
template_name = 'chart_of_accounts/coa_create.html'
permission_required = 'django_ledger.add_chartofaccountmodel'
class ChartOfAccountModelListView(ChartOfAccountModelListViewBase):
template_name = 'chart_of_accounts/coa_list.html'
permission_required = 'django_ledger.view_chartofaccountmodel'
class ChartOfAccountModelUpdateView(ChartOfAccountModelUpdateViewBase):
template_name = 'chart_of_accounts/coa_update.html'
permission_required = 'django_ledger.change_chartofaccountmodel'
class CharOfAccountModelActionView(CharOfAccountModelActionViewBase):
permission_required = 'django_ledger.change_chartofaccountmodel'

View File

@ -0,0 +1,54 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load django_ledger %}
{% load widget_tweaks %}
{% block content %}
<div class="container py-5">
<div class="row justify-content-center">
<div class="col-12 text-center mb-4">
<h1 class="display-4">{% trans 'Create Chart of Accounts' %}</h1>
</div>
<div class="col-lg-6 col-md-8">
<div class="card shadow-sm">
<div class="card-body p-4">
<form method="post" id="{{ form.get_form_id }}">
{% csrf_token %}
{# Bootstrap form rendering #}
<div class="mb-3">
{{ form.name.label_tag }}
{{ form.name|add_class:"form-control" }}
{% if form.name.help_text %}
<small class="form-text text-muted">{{ form.name.help_text }}</small>
{% endif %}
{% for error in form.name.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<div class="mb-3">
{{ form.description.label_tag }}
{{ form.description|add_class:"form-control" }}
{% if form.description.help_text %}
<small class="form-text text-muted">{{ form.description.help_text }}</small>
{% endif %}
{% for error in form.description.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<div class="d-grid gap-2 mt-4">
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
<a href="{% url 'coa-list' request.dealer.slug request.entity.slug %}" class="btn btn-outline-dark">
{% trans 'Back' %}
</a>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -10,17 +10,17 @@
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="display-4 mb-0">Chart of Accounts</h1>
<a href="{{ entity_model.get_coa_create_url }}" class="btn btn-success btn-lg">
<a href="{% url 'coa-create' request.dealer.slug request.entity.slug %}" class="btn btn-success btn-lg">
{% icon 'carbon:add-alt' 24 %} Add New
</a>
</div>
{% if not inactive %}
<a class="btn btn-warning mb-4" href="{{ entity_model.get_coa_list_inactive_url }}">
<a class="btn btn-warning mb-4" href="{% url 'coa-list-inactive' request.dealer.slug request.entity.slug %}">
{% trans 'Show Inactive' %}
</a>
{% else %}
<a class="btn btn-warning mb-4" href="{{ entity_model.get_coa_list_url }}">
<a class="btn btn-warning mb-4" href="{% url 'coa-list' request.dealer.slug request.entity.slug %}">
{% trans 'Show Active' %}
</a>
{% endif %}

View File

@ -0,0 +1,49 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load widget_tweaks %}
{% block content %}
<div class="row justify-content-center">
<div class="col-lg-6 col-md-8">
<div class="card shadow-sm">
<div class="card-body">
<form action="{% url 'coa-update' request.dealer.slug request.entity.slug coa_model.slug %}" id="{{ form.form_id }}" method="post">
{% csrf_token %}
<div class="mb-3">
{{ form.name.label_tag }}
{{ form.name|add_class:"form-control" }}
{% if form.name.help_text %}
<small class="form-text text-muted">{{ form.name.help_text }}</small>
{% endif %}
{% for error in form.name.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<div class="mb-3">
{{ form.description.label_tag }}
{{ form.description|add_class:"form-control" }}
{% if form.description.help_text %}
<small class="form-text text-muted">{{ form.description.help_text }}</small>
{% endif %}
{% for error in form.description.errors %}
<div class="invalid-feedback d-block">{{ error }}</div>
{% endfor %}
</div>
<div class="d-grid gap-2 mt-4">
<button class="btn btn-primary" type="submit">
Update
</button>
<a class="btn btn-outline-secondary"
href="{% url 'coa-list' request.dealer.slug request.entity.slug %}">
Back
</a>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -84,30 +84,30 @@
<div class="card-footer bg-transparent border-top-0">
<div class="d-flex flex-wrap gap-2">
<a href="{{ coa_model.get_update_url }}" class="btn btn-sm btn-outline-warning fw-bold">
<a href="{% url 'coa-update' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-warning fw-bold">
<i class="fas fa-edit me-1"></i> {% trans 'Update' %}
</a>
<a href="{{ coa_model.get_account_list_url }}" class="btn btn-sm btn-outline-success fw-bold">
<a href="{% url 'account_list' request.dealer.slug coa_model.pk %}" class="btn btn-sm btn-outline-success fw-bold">
<i class="fas fa-book me-1"></i> {% trans 'Accounts' %}
</a>
<a href="{{ coa_model.get_create_coa_account_url }}" class="btn btn-sm btn-outline-info fw-bold">
<a href="{% url 'account_create' request.dealer.slug coa_model.pk %}" class="btn btn-sm btn-outline-info fw-bold">
<i class="fas fa-plus-circle me-1"></i> {% trans 'Add Account' %}
</a>
{% if coa_model.can_mark_as_default %}
<a href="{{ coa_model.mark_as_default_url }}" class="btn btn-sm btn-outline-danger fw-bold">
<a href="{% url 'coa-action-mark-as-default' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-danger fw-bold">
<i class="fas fa-star me-1"></i> {% trans 'Mark as Default' %}
</a>
{% endif %}
{% if coa_model.can_deactivate %}
<a href="{{ coa_model.mark_as_inactive_url }}" class="btn btn-sm btn-outline-warning fw-bold">
<a href="{% url 'coa-action-mark-as-inactive' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-warning fw-bold">
<i class="fas fa-toggle-off me-1"></i> {% trans 'Mark as Inactive' %}
</a>
{% elif coa_model.can_activate %}
<a href="{{ coa_model.mark_as_active_url }}" class="btn btn-sm btn-outline-success fw-bold">
<a href="{% url 'coa-action-mark-as-active' request.dealer.slug request.entity.slug coa_model.slug %}" class="btn btn-sm btn-outline-success fw-bold">
<i class="fas fa-toggle-on me-1"></i> {% trans 'Mark as Active' %}
</a>
{% endif %}

View File

@ -1,19 +1,30 @@
{% extends 'base.html' %}
{% load i18n %}
{% load tenhal_tag %}
{% block title %}
{{ _("Dealership Dashboard") |capfirst }}
{% endblock title %}
{% block content%}
<div class="main-content flex-grow-1 container-fluid mt-4 mb-3">
<div class="d-flex justify-content-between align-items-center mb-5 pb-3 border-bottom">
<h2 class="h3 fw-bold text-dark mb-0">Business Health Dashboard <i class="fas fa-chart-area text-primary ms-2"></i></h2>
<div class="dropdown">
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Last 30 Days
</button>
<ul class="dropdown-menu dropdown-menu-end shadow">
<li><a class="dropdown-item" href="#">Today</a></li>
<li><a class="dropdown-item" href="#">Last 7 Days</a></li>
<li><a class="dropdown-item" href="#">Last 90 Days</a></li>
</ul>
<div class="d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-5 pb-3 border-bottom">
<h2 class="h3 fw-bold text-dark mb-3 mb-md-0">Business Health Dashboard <i class="fas fa-chart-area text-primary ms-2"></i></h2>
<form method="GET" class="date-filter-form">
<div class="row g-3">
<div class="col-12 col-md-4">
<label for="start-date" class="form-label">Start Date</label>
<input type="date" class="form-control" id="start-date" name="start_date"
value="{{ start_date|date:'Y-m-d' }}" required>
</div>
<div class="col-12 col-md-4">
<label for="end-date" class="form-label">End Date</label>
<input type="date" class="form-control" id="end-date" name="end_date"
value="{{ end_date|date:'Y-m-d' }}" required>
</div>
<div class="col-12 col-md-4 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Apply Filter</button>
</div>
</div>
</form>
</div>
<div class="row g-4 mb-5">
@ -21,8 +32,8 @@
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Revenue</p>
<h4 class="fw-bolder text-primary mb-3">$1.25M</h4>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Cost of Cars Sold</p>
<h4 class="fw-bolder text-secondary mb-3">{{total_cost_of_cars_sold|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
@ -34,8 +45,8 @@
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Net Profit</p>
<h4 class="fw-bolder text-success mb-3">$1.25M</h4>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Revenue from cars</p>
<h4 class="fw-bolder text-primary mb-3">{{total_revenue_from_cars|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
@ -47,8 +58,8 @@
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Gross Profit</p>
<h4 class="fw-bolder text-info mb-3">$1.25M</h4>
<p class="text-uppercase text-muted fw-bold small mb-1">Net Profit From Cars</p>
<h4 class="fw-bolder text-success mb-3">{{net_profit_from_cars|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
@ -56,6 +67,87 @@
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Discount on cars</p>
<h4 class="fw-bolder text-primary mb-3">{{total_discount_on_cars|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total VAT collected from cars</p>
<h4 class="fw-bolder text-primary mb-3">{{total_vat_collected_from_cars|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Revenue from Services</p>
<h4 class="fw-bolder text-primary mb-3">{{total_revenue_from_services|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total VAT collected from Services</p>
<h4 class="fw-bolder text-primary mb-3">{{total_vat_collected_from_services|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">{% trans "Total Revenue Generated" %}</p>
<h4 class="fw-bolder text-primary mb-3">{{total_revenue_generated|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">{% trans "Total VAT Collected" %}</p>
<h4 class="fw-bolder text-primary mb-3">{{total_vat_collected|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
@ -69,12 +161,26 @@
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Gross Profit</p>
<h4 class="fw-bolder text-info mb-3">$1.25M</h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
</span>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total VAT Collected</p>
<h4 class="fw-bolder text-primary mb-3">$1.25M</h4>
<h4 class="fw-bolder text-primary mb-3">{{total_vat_collected|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month
@ -87,7 +193,7 @@
<div class="card-body d-flex flex-column justify-content-between p-4">
<div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Cars Sold</p>
<h4 class="fw-bolder text-success mb-3">{{ sold_cars }}</h4>
<h4 class="fw-bolder text-success mb-3">{{ total_cars_sold }}</h4>
</div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+5 units from last month

View File

@ -123,8 +123,8 @@
<h5 class="fw-bold mb-0 text-dark">Car Models by Make in Inventory</h5>
</div>
<div class="row justify-content-center">
<div class="col-md-6 mb-4">
<label for="carMakeSelect" class="form-label fs-7">Select a Car Make:</label>
<div class="col-md-6 mb-4 mt-3">
<label for="carMakeSelect" class="form-label fs-8 mb-2">Select a Car Make:</label>
<select id="carMakeSelect" class="form-select">
<option value="" disabled selected>-- Choose a make --</option>
</select>

View File

@ -22,7 +22,7 @@
class="btn btn-sm btn-phoenix-secondary"
data-bs-dismiss="modal">{% trans 'No' %}</button>
<div class="btn btn-sm btn-phoenix-danger">
<form action="{% url 'account_delete' request.dealer.slug account.pk %}"
<form action="{% url 'account_delete' request.dealer.slug url_kwargs.coa_pk account.pk %}"
method="post">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-phoenix-danger">{% trans 'Yes' %}</button>
@ -135,7 +135,7 @@
<div class="mt-3 d-flex">
{% if perms.django_ledger.change_chartofaccountmodel %}
<a class="btn btn-sm btn-phoenix-primary me-1"
href="{% url 'account_update' request.dealer.slug account.pk %}">
href="{% url 'account_update' request.dealer.slug url_kwargs.coa_pk account.pk %}">
<!-- <i class="bi bi-pencil-square"></i> -->
<i class="fa-solid fa-pen-to-square"></i> {{ _("Edit") }}
</a>
@ -149,7 +149,7 @@
</a>
{% endif %}
<a class="btn btn-sm btn-phoenix-secondary"
href="{% url 'account_list' request.dealer.slug %}">
href="{% url 'account_list' request.dealer.slug url_kwargs.coa_pk %}">
<!-- <i class="bi bi-arrow-left-square-fill"></i> -->
<i class="fa-regular fa-circle-left"></i> {% trans 'Back to COA List' %}
</a>

View File

@ -44,7 +44,7 @@
<i class="saveBtnIcon fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}
</button>
<a href="{% url 'account_list' request.dealer.slug %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
<a href="{% url 'account_list' request.dealer.slug url_kwargs.coa_pk %}" class="btn btn-lg btn-phoenix-secondary"><i class="fa-solid fa-ban me-1"></i>{% trans "Cancel" %}</a>
</div>
</form>

View File

@ -17,7 +17,7 @@
<div class="d-flex justify-content-between mb-2">
<h3 class=""> {% trans "Accounts" %}<i class="fa-solid fa-book ms-2 text-primary"></i></h3>
{% if perms.django_ledger.add_chartofaccountmodel %}
<a href="{% url 'account_create' request.dealer.slug %}"
<a href="{% url 'account_create' request.dealer.slug url_kwargs.coa_pk %}"
class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Account' %}</a>
{% endif %}
</div>

View File

@ -47,12 +47,12 @@
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a href="{% url 'account_detail' request.dealer.slug account.uuid %}"
<a href="{% url 'account_detail' request.dealer.slug url_kwargs.coa_pk account.uuid %}"
class="dropdown-item text-success-dark">{% trans "View Journal Entries" %}</a>
<div class="dropdown-divider"></div>
<button class="dropdown-item text-danger"
{% comment %} <div class="dropdown-divider"></div> {% endcomment %}
{% comment %} <button class="dropdown-item text-danger"
data-bs-toggle="modal"
data-bs-target="#deleteModal">{% trans "Delete" %}</button>
data-bs-target="#deleteModal">{% trans "Delete" %}</button> {% endcomment %}
</div>
</div>
</td>

View File

@ -51,7 +51,7 @@
<section id="filters" class="mb-5 p-4 rounded border border-primary">
<h2 class="section-heading mb-4">{% trans 'Filters' %} <i class="fas fa-sliders-h ms-2"></i></h2>
<form method="GET" class="row g-3 align-items-end">
<div class="col-md-3">
<div class="col-md-2">
<label for="make-select" class="form-label">{% trans 'Make' %}</label>
<select id="make-select" name="make" class="form-select">
<option value="">{% trans 'All Makes' %}</option>
@ -60,7 +60,7 @@
{% endfor %}
</select>
</div>
<div class="col-md-3">
<div class="col-md-2">
<label for="model-select" class="form-label">{% trans 'Model' %}</label>
<select id="model-select" name="model" class="form-select">
<option value="">{% trans 'All Models' %}</option>
@ -69,7 +69,7 @@
{% endfor %}
</select>
</div>
<div class="col-md-3">
<div class="col-md-2">
<label for="serie-select" class="form-label">{% trans 'Serie' %}</label>
<select id="serie-select" name="serie" class="form-select">
<option value="">{% trans 'All Series' %}</option>
@ -87,36 +87,98 @@
{% endfor %}
</select>
</div>
<div class="col-md-1">
<div class="col-md-2">
<label for="stock_type-select" class="form-label">{% trans 'Stock Types' %}</label>
<select id="stock_type-select" name="stock_type" class="form-select">
<option value="">{% trans 'Stock Types' %}</option>
{% for stock_type in stock_types %}
<option value="{{ stock_type }}" {% if stock_type == selected_stock_type %}selected{% endif %}>{{ stock_type }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-2"></i>{% trans 'Filter' %}</button>
</div>
</form>
</section>
<!---->
{% comment %} 'cars_sold': cars_sold,
'current_time': current_time,
'dealer': dealer,
'total_revenue_from_cars': total_revenue_from_cars,
'total_revenue_from_additonals':total_revenue_from_additonals,
'total_revenue_collected': total_revenue_collected,
'total_vat_on_cars':total_vat_on_cars,
'total_vat_from_additonals':total_vat_from_additonals,
'total_vat_collected':total_vat_collected,
'total_discount': total_discount,
'makes': makes,
'models': models_qs,
'series': series,
'years': years,
'selected_make': selected_make,
'selected_model': selected_model,
'selected_serie': selected_serie,
'selected_year': selected_year, {% endcomment %}
<!---->
<section id="summary" class="mb-5">
<h2 class="section-heading mb-4 border-start border-5 border-primary p-2">{% trans 'Report Summary' %}</h2>
<div class="row g-4">
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total Revenue' %}<span class="icon-saudi_riyal"></span></h5>
<p class="card-text">{{ total_revenue|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
<h5 class="card-title"><span>{% trans 'Total Revenue from Cars' %}<span class="icon-saudi_riyal"></span></span></h5>
<p class="card-text"><span>{{ total_revenue_from_cars|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total VAT Amount' %}<i class="fas fa-percent ms-2"></i></h5>
<p class="card-text">{{ 10000|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
<h5 class="card-title"><span>{% trans 'Total Revenue from Services' %}<span class="icon-saudi_riyal"></span></span></h5>
<p class="card-text"><span>{{ total_revenue_from_additonals|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title"><span>{% trans 'Total Revenue' %}<span class="icon-saudi_riyal"></span></span></h5>
<p class="card-text"><span>{{total_revenue_collected |floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total VAT from Cars' %}<i class="fas fa-percent ms-2"></i></h5>
<p class="card-text"><span>{{ total_vat_on_cars|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total VAT from Services' %}<i class="fas fa-percent ms-2"></i></h5>
<p class="card-text"><span>{{ total_vat_from_additonals|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total VAT' %}<i class="fas fa-percent ms-2"></i></h5>
<p class="card-text"><span>{{ total_vat_collected|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total Discount Amount' %}<i class="fas fa-tag ms-2"></i></h5>
<p class="card-text">{{ total_discount|floatformat:2 }} <span class="icon-saudi_riyal"></span></p>
<p class="card-text"><span>{{ total_discount|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div>
</div>
</div>
@ -124,13 +186,10 @@
<div class="card summary-card">
<div class="card-body">
<h5 class="card-title">{% trans 'Total Cars Sold' %}<i class="fas fa-car ms-2"></i></h5>
<p class="card-text">{{ cars_sold|length }}</p>
<p class="card-text">{{ total_cars_sold }}</p>
</div>
</div>
</div>
</div>
</section>
@ -142,7 +201,7 @@
<i class="bi bi-download me-2"></i>{% trans 'Download as CSV' %}
</a>
</div>
<div class="table-responsive">
<div class="table-responsive table-container">
<table class="table table-striped table-hover table-bordered table-sm">
<thead>
<tr>
@ -160,7 +219,10 @@
<th class="fs-9">{% trans 'Marked Price' %}</th>
<th class="fs-9">{% trans 'Discount Amount' %}</th>
<th class="fs-9">{% trans 'Selling Price' %}</th>
<th class="fs-9">{% trans 'Tax Amount' %}</th>
<th class="fs-9">{% trans 'VAT on Car' %}</th>
<th class="fs-9">{% trans 'Services Price' %}</th>
<th class="fs-9">{% trans 'VAT on Services' %}</th>
<th class="fs-9">{% trans 'Final Total' %}</th>
<th class="fs-9">{% trans 'Invoice Number' %}</th>
</tr>
</thead>
@ -178,12 +240,15 @@
<td class="fs-9">{{ car.stock_type|capfirst }}</td>
<td class="fs-9">{{ car.created_at|date }}</td>
<td class="fs-9">{{ car.invoice.date_paid|date|default_if_none:"-" }}</td>
<td class="fs-9">{{ car.cost_price }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.marked_price }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.total_discount }} <span class="icon-saudi_riyal"></span></td># TODO : check later
<td class="fs-9">{{ car.selling_price }} <span class="icon-saudi_riyal"></span></td>
<td class="fs-9">{{ car.vat_amount }} <span class="icon-saudi_riyal"></span></td># TODO : check later
<td class="fs-9">{{ car.invoice.invoice_number }}</td>
<td class="fs-9"><span>{{ car.cost_price }}<span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.marked_price }} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.discount}} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.final_price}} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.vat_amount|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.get_additional_services.total|floatformat:2}} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.get_additional_services.services_vat|floatformat:2}}<span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.final_price_plus_services_plus_vat|floatformat:2 }}<span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9"><span>{{ car.invoice.invoice_number }}</td>
</tr>
{% endfor %}
</tbody>

View File

@ -17,8 +17,7 @@
<table class="table table-hover table-bordered">
<thead class="">
<tr>
<th style="min-width: 600px"
class="d-flex justify-content-between align-items-center">
<th class="d-flex justify-content-between align-items-center">
{% trans 'Item' %}
{% if po_model.is_draft %}
<button type="button"

View File

@ -112,7 +112,7 @@
onclick="setFormAction('review')"
data-bs-toggle="modal"
data-bs-target="#confirmModal">
<i class="fa-solid fa-check-double me-1"></i><span class="d-none d-sm-inline-block"> {% trans 'Mark As Review' %}</span>
<span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Review' %}</span>
</button>
{% endif %}
{% elif estimate.status == 'in_review' %}
@ -122,46 +122,49 @@
class="btn btn-phoenix-secondary"
data-bs-toggle="modal"
data-bs-target="#confirmModal">
<i class="fa-solid fa-check-double me-1"></i> <span class="d-none d-sm-inline-block">{% trans 'Mark As Approved' %}</span>
<span class="d-none d-sm-inline-block"><i class="fa-solid fa-check-double"></i> {% trans 'Mark As Approved' %}</span>
</button>
{% endif %}
{% if estimate.can_approve and not request.is_manager %}
<button class="btn btn-phoenix-warning" disabled>
<i class="fas fa-hourglass-start me-1"></i><span class="text-warning d-none d-sm-inline-block ">{% trans 'Waiting for Manager Approval' %}</span>
<i class="fas fa-hourglass-start me-2"></i><span class="text-warning">{% trans 'Waiting for Manager Approval' %}</span>
</button>
{% endif %}
{% elif estimate.status == 'approved' %}
{% if perms.django_ledger.change_estimatemodel %}
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-1"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Quotation' %}</span></a>
<a href="{% url 'estimate_print' request.dealer.slug estimate.pk %}" class="btn btn-phoenix-secondary" target="_blank">
<span class="d-none d-sm-inline-block"><i class="fas fa-print me-2"></i>{% trans 'Print' %}</span>
</a>
{% endif %}
{% if estimate.sale_orders.first %}
<!--if sale order exist-->
{% if perms.django_ledger.add_invoicemodel %}
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-primary"><i class="fa-solid fa-receipt me-1"></i><span class="d-none d-sm-inline-block me-1"> {% trans 'Create Invoice' %}</span></a>
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'Create Invoice' %}</span></a>
{% endif %}
{% if perms.inventory.view_saleorder %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}"
class="btn btn-phoenix-primary"><i class="fas fa-shopping-cart me-1"></i><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
{% endif %}
{% else %}
{% if perms.inventory.add_saleorder %}
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}"
class="btn btn-phoenix-primary"><i class="fa-solid fa-file-import me-1"></i><span class="d-none d-sm-inline-block"> {% trans 'Create Sale Order' %}</span></a>
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-file-import"></i> {% trans 'Create Sale Order' %}</span></a>
{% endif %}
{% endif %}
{% elif estimate.status == 'completed' %}
{% if perms.inventory.view_saleorder %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}"
class="btn btn-phoenix-primary"><i class="fas fa-shopping-cart me-1"></i><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{{ _("Preview Sale Order") }}</span></a>
{% endif %}
{% if perms.django_ledger.view_invoicemodel %}
<a href="{% url 'invoice_detail' request.dealer.slug request.entity.slug estimate.invoicemodel_set.first.pk %}"
class="btn btn-phoenix-primary btn-sm"
type="button"><i class="fa-solid fa-receipt me-1"></i>
<span class="d-none d-sm-inline-block">{{ _("View Invoice") }}</span>
</a>
type="button"><i class="fa-solid fa-receipt"></i>
{{ _("View Invoice") }}</a>
{% endif %}
{% endif %}
{% if estimate.can_cancel %}
@ -169,7 +172,7 @@
<button class="btn btn-phoenix-danger"
data-bs-toggle="modal"
data-bs-target="#CancelModal">
<i class="fa-solid fa-ban me-1"></i> <span class="d-none d-sm-inline-block">{% trans "Cancel" %}</span>
<i class="fa-solid fa-ban"></i> {% trans "Cancel" %}
</button>
{% endif %}
{% endif %}
@ -179,31 +182,31 @@
<div class="row">
<div class="col mb-2">
<h6>
<i class="fa-solid fa-hashtag me-1"></i> {% trans 'Quotation Number' %}:
<i class="fa-solid fa-hashtag"></i> {% trans 'Quotation Number' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.estimate_number }}</p>
</div>
<div class="col mb-2">
<h6>
<i class="fa-solid fa-calendar-days me-1"></i> {% trans 'Quotation Date' %}:
<i class="fa-solid fa-calendar-days"></i> {% trans 'Quotation Date' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.created }}</p>
</div>
<div class="col mb-2">
<h6>
<i class="fa-solid fa-user me-1"></i> {% trans 'Customer' %}:
<i class="fa-solid fa-user"></i> {% trans 'Customer' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.customer_name }}</p>
</div>
<div class="col mb-2">
<h6>
<i class="fa-solid fa-envelope me-1"></i> {% trans 'Email' %}:
<i class="fa-solid fa-envelope"></i> {% trans 'Email' %}:
</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.email }}</p>
</div>
<div class="col">
<h6>
<i class="fa-solid fa-list me-1"></i> {% trans "Quotation Status" %}:
<i class="fa-solid fa-list"></i> {% trans "Quotation Status" %}:
</h6>
<div class="fs-9 text-body-secondary fw-semibold mb-0">
{% if estimate.status == 'draft' %}
@ -284,7 +287,7 @@
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-semibold">
{% for service in data.additional_services.services %}
<small><span class="fw-semibold">+ {{ service.name }} - {{ service.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small>
<small><span class="fw-semibold">+ {{ service.0.name }} - {{ service.0.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small>
<br>
{% endfor %}
{% if estimate.is_draft %}

View File

@ -1,11 +1,10 @@
{% load i18n static custom_filters num2words_tags %}
<!DOCTYPE html>
<html lang="ar">
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Invoice</title>
<!-- CSS -->
<title>Quotation</title>
<link href="{% static 'css/theme.min.css' %}"
type="text/css"
rel="stylesheet"
@ -15,70 +14,80 @@
rel="stylesheet"
id="user-style-default">
<link href="{% static 'css/custom.css' %}" type="text/css" rel="stylesheet">
<!-- Google Fonts - Roboto -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
rel="stylesheet">
<!-- Custom CSS -->
<style>
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 10mm;
padding: 0;
background-color: #f8f9fa;
}
.invoice-container {
width: 210mm;
min-height: 297mm;
padding: 10mm;
margin: auto;
margin: 10mm auto;
background: white;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
position: relative;
display: flex;
flex-direction: column;
}
.invoice-content {
flex-grow: 1;
}
.invoice-header {
text-align: center;
border-bottom: 2px solid #dee2e6;
padding-bottom: 10px;
margin-bottom: 20px;
}
.qr-code {
text-align: center;
margin-top: 10px;
}
.qr-code img {
width: 3cm;
height: 3cm;
border-radius: 0.3333333333rem;
}
.invoice-details, .invoice-table {
font-size: 12px;
font-size: 14px;
}
.invoice-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.invoice-total {
text-align: right;
font-size: 13px;
font-size: 16px;
font-weight: 600;
margin-top: 10px;
}
.footer-note {
position: absolute;
bottom: 10mm;
left: 10mm;
right: 10mm;
font-size: 10px;
margin-top: auto;
padding-top: 10mm;
font-size: 13px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 2px solid #dee2e6;
}
.logo-img img {
width: 10mm;
height: 10mm;
}
</style>
</head>
<body>
@ -92,45 +101,42 @@
</div>
<div class="col-8"></div>
</div>
<div class="invoice-container" id="invoice-content">
<div class="invoice-container" id="estimate-content">
<div class="invoice-content">
<div class="invoice-header">
<h5 class="fs-5">
<span>Quotation</span>&nbsp;/&nbsp;<span>عرض سعر</span>
</h5>
</div>
<div class="invoice-details p-1">
<table class="table table-sm table-responsive border-gray-50">
<tr>
<td></td>
<td></td>
<td>
<div class="qr-code">
{% if dealer.logo %}
<img class="rounded-soft"
src="{{ dealer.logo.url|default:'' }}"
<div class="d-flex justify-content-end align-items-end">
<div class="dealer-logo ">
{% if request.dealer.logo %}
<img class="rounded-soft" style="max-width:200px; max-height:200px;"
src="{{ request.dealer.logo.url|default:'' }}"
alt="Dealer Logo" />
{% endif %}
</div>
</td>
</tr>
</div>
<table class="table table-sm table-responsive border-gray-50">
<tr>
<td class="ps-1">
<strong>Customer Name</strong>
<strong>Dealership Name</strong>
</td>
<td class="text-center">
{{ dealer.arabic_name }}
<br>
{{ dealer.name }}
{{ request.dealer.name }}
</td>
<td class="text-end">
<strong>{{ dealer.arabic_name }}</strong>
<strong>اسم الوكالة</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Address</strong>
<strong>Dealership Address</strong>
</td>
<td class="text-center">{{ dealer.address }}</td>
<td class="text-center">{{ request.dealer.address }}</td>
<td class="text-end">
<strong>العنوان</strong>
</td>
@ -139,7 +145,7 @@
<td class="ps-1">
<strong>Phone</strong>
</td>
<td class="text-center">{{ dealer.phone_number }}</td>
<td class="text-center">{{ request.dealer.phone_number }}</td>
<td class="text-end">
<strong>جوال</strong>
</td>
@ -148,7 +154,7 @@
<td>
<strong>VAT Number</strong>
</td>
<td>{{ dealer.vrn }}</td>
<td class="text-center">{{ request.dealer.vrn }}</td>
<td class="text-end">
<strong>الرقم الضريبي</strong>
</td>
@ -175,22 +181,14 @@
</tr>
<tr>
<td class="ps-1">
<strong>Customer</strong>
<strong>Customer Name</strong>
</td>
<td class="text-center">{{ estimate.customer.customer_name }}</td>
<td class="text-end p-1">
<strong>العميل</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>VAT&nbsp;ID</strong>
</td>
<td class="text-center">{{ estimate.customer.vrn|default:"-" }}</td>
<td class="text-end p-1">
<strong>الرقم الضريبي</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Email</strong>
@ -225,6 +223,9 @@
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Model</span> / <span class="fs-10">الموديل</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Series</span> / <span class="fs-10">السلسلة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Trim</span> / <span class="fs-10">الفئة</span>
</th>
@ -232,7 +233,7 @@
<span class="fs-10">Year</span> / <span class="fs-10">السنة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">VIN</span> / <span class="fs-10">الهيكل</span>
<span class="fs-10">VIN</span> / <span class="fs-10">رقم الهيكل</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Quantity</span> / <span class="fs-10">الكمية</span>
@ -241,26 +242,29 @@
<span class="fs-10">Unit Price</span> / <span class="fs-10">سعر الوحدة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Including VAT</span> / <span class="fs-10">شامل الضريبة</span>
<span class="fs-10">Discount</span> / <span class="fs-10">الخصم</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">VAT</span> / <span class="fs-10">الضريبة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
</th>
</tr>
</thead>
<tbody>
{% for item in data.cars %}
<tr>
<td class="ps-1 fs-10 align-content-center" colspan="3">{{ item.make }} - {{ item.model }} - {{ item.trim }}</td>
<td class="text-center fs-10 align-content-center">{{ item.year }}</td>
<td class="ps-1 fs-10 align-content-center">{{ item.vin }}</td>
<td class="text-center fs-10 align-content-center">{{ item.quantity|floatformat:-1 }}</td>
<td class="text-center fs-10 align-content-center">{{ item.unit_price|floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ item.total_vat|floatformat:2 }}</td>
</tr>
{% endfor %}
<tr>
<td class="ps-1 fs-10 align-content-center" colspan="5"></td>
<td class="text-center fs-10 align-content-center">{{ data.quantity|floatformat:-1 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.total_price_before_discount|floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.grand_total|floatformat:2 }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_make.name }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_model.name }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_serie.name }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_trim.name }}</td>
<td class="text-center fs-10 align-content-center">{{ data.car.year }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.vin }}</td>
<td class="text-center fs-10 align-content-center">1</td>
<td class="text-center fs-10 align-content-center">{{ data.car.marked_price |floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{  data.discount_amount |floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.vat_amount|floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.final_price|floatformat:2 }}</td>
</tr>
</tbody>
</table>
@ -269,24 +273,26 @@
<span class="fs-9 fw-thin">Additional&nbsp;Services</span>
<span class="fs-9 fw-thin">الخدمات&nbsp;الإضافية</span>
</div>
{% if data.additionals %}
{% if data.additional_services %}
<div class="invoice-table p-1">
<table class="table table-sm table-bordered m-1">
<thead>
<tr>
<th class="text-center fs-10 align-content-center">Type&nbsp;/&nbsp;النوع</th>
<th class="text-center fs-10 align-content-center">Price&nbsp;/&nbsp;القيمة</th>
<th class="text-center fs-10 align-content-center">VAT&nbsp;/&nbsp;ضريبة الخدمة</th>
<th class="text-center fs-10 align-content-center">
<span class="fs-10">Including VAT</span> / <span class="fs-10">شامل الضريبة</span>
<span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
</th>
</tr>
</thead>
<tbody>
{% for item in data.additionals %}
{% for service in data.additional_services.services %}
<tr>
<td class="ps-1 text-start fs-10 align-content-center">{{ item.name }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ item.price|floatformat }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ item.price_|floatformat }}</td>
<td class="ps-1 text-start fs-10 align-content-center">{{ service.0.name }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price|floatformat }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ service.1|floatformat }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price_|floatformat }}</td>
</tr>
{% endfor %}
</tbody>
@ -298,18 +304,18 @@
<table class="table table-sm table-responsive">
<tr>
<td class="text-start ps-1">
<strong class="fs-9">VAT</strong>
<strong class="fs-9">Total VAT</strong>
</td>
<td class="text-center">
<span class="fs-9">{{ data.total_vat_amount|floatformat }} <span class="icon-saudi_riyal"></span></span>
<span class="fs-9">{{ data.total_vat|floatformat }} <span class="icon-saudi_riyal"></span></span>
</td>
<td class="text-end">
<strong class="fs-9">ضريبة&nbsp;القيمة&nbsp;المضافة</strong>
<strong class="fs-9">إجمالي&nbsp;ضريبة&nbsp;القيمة&nbsp;المضافة</strong>
</td>
</tr>
<tr>
<td class="text-start ps-1">
<strong class="fs-9">Total</strong>
<strong class="fs-9">Grand Total</strong>
</td>
<td class="text-center">
<span class="fs-9">{{ data.grand_total|floatformat }}&nbsp;<span class="icon-saudi_riyal"></span></span>
@ -326,33 +332,31 @@
</table>
</div>
</div>
<br>
<br>
<br>
<br>
<br>
<br>
</div>
<div class="footer-note">
<div class="logo-img text-center">
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
<p class="fs-11 fw-bold">
<p class="fs-9 fw-bold">
<span>Haikal</span>&nbsp;|&nbsp;<span>هيكل</span>
</p>
</div>
<p class="fs-11">
<span class="fw-thin">Powered&nbsp;by&nbsp;</span><a class="text-decoration-none"
<span class="fw-thin">Powered&nbsp;by&nbsp;</span>
<a class="text-decoration-none fs-9"
href="https://tenhal.sa"
style="color: #112e40"><span>TENHAL</span>&nbsp;|&nbsp;<span>تنحل</span></a>
style="color: #112e40;"><span>TENHAL</span>&nbsp;|&nbsp;<span>تنحل</span></a>
</p>
</div>
</div>
<script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script>
<script src="{% static 'js/html2pdf.bundle.min.js' %}"></script>
<script>
document.getElementById('download-pdf').addEventListener('click', function () {
html2pdf().from(document.getElementById('invoice-content')).set({
html2pdf().from(document.getElementById('estimate-content')).set({
margin: 0,
filename: "{{ invoice.invoice_number }}_{{ invoice.customer.customer_name }}_{{ invoice.date_in_review|date:'Y-m-d' }}.pdf",
filename: "{{ estimate.estimate_number }}_{{ estimate.customer.customer_name  }}_{{estimate.date_approved|date:'Y-m-d' }}.pdf",
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 3 },
jsPDF: { unit: 'mm', format: 'a3', orientation: 'portrait' }

View File

@ -358,7 +358,7 @@
<td class="align-middle ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-bold">
{% for service in data.additional_services.services %}
<small><span class="fw-bold">+ {{ service.name }} - {{ service.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small>
<small><span class="fw-bold">+ {{ service.0.name }} - {{ service.0.price_|floatformat }}<span class="icon-saudi_riyal"></span></span></small>
<br>
{% endfor %}
</td>

View File

@ -1,11 +1,10 @@
{% load i18n static custom_filters num2words_tags %}
<!DOCTYPE html>
<html lang="ar">
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Invoice</title>
<!-- CSS -->
<link href="{% static 'css/theme.min.css' %}"
type="text/css"
rel="stylesheet"
@ -15,75 +14,80 @@
rel="stylesheet"
id="user-style-default">
<link href="{% static 'css/custom.css' %}" type="text/css" rel="stylesheet">
<!-- Google Fonts - Roboto -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
rel="stylesheet">
<!-- Custom CSS -->
<style>
body {
font-family: 'Roboto', sans-serif;
margin: 0;
padding: 10mm;
padding: 0;
background-color: #f8f9fa;
}
.invoice-container {
width: 210mm;
min-height: 297mm;
padding: 10mm;
margin: auto;
margin: 10mm auto;
background: white;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
position: relative;
display: flex;
flex-direction: column;
}
.invoice-content {
flex-grow: 1;
}
.invoice-header {
text-align: center;
border-bottom: 2px solid #dee2e6;
padding-bottom: 10px;
margin-bottom: 20px;
}
.qr-code {
text-align: center;
margin-top: 10px;
}
.qr-code img {
width: 3cm;
height: 3cm;
border-radius: 0.3333333333rem;
}
.dealer-logo img {
width: 3cm;
height: 1cm;
position: relative;
}
.invoice-details, .invoice-table {
font-size: 12px;
font-size: 14px;
}
.invoice-table th {
background-color: #f8f9fa;
font-weight: 600;
}
.invoice-total {
text-align: right;
font-size: 13px;
font-size: 16px;
font-weight: 600;
margin-top: 10px;
}
.footer-note {
position: absolute;
bottom: 10mm;
left: 10mm;
right: 10mm;
font-size: 10px;
margin-top: auto;
padding-top: 10mm;
font-size: 13px;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 2px solid #dee2e6; /* Add a top border to separate from content */
}
.logo-img img {
width: 10mm;
height: 10mm;
}
</style>
</head>
<body>
@ -97,63 +101,67 @@
</div>
<div class="col-8"></div>
</div>
<div class="invoice-container" id="invoice-content">
<div class="invoice-content">
<div class="invoice-header">
<h5 class="fs-5">Tax&nbsp;Invoice&nbsp;&nbsp;/&nbsp;&nbsp;فاتورة&nbsp;ضريبية</h5>
<h5 class="fs-5">
<span>Invoice</span>&nbsp;/&nbsp;<span>فاتورة</span>
</h5>
</div>
<div class="invoice-details p-1">
<div class="d-flex justify-content-center align-items-center">
<div class="d-flex justify-content-around align-items-end">
<div class="d-flex justify-content-start align-items-center">
<div class="qr-code">
<img src="{% static 'qr_code/Marwan_qr.png' %}" alt="QR Code">
</div>
</div>
<div class="d-flex justify-content-end align-items-end">
<div class="dealer-logo ">
{% if dealer.logo %}
<img class="rounded-soft"
src="{{ dealer.logo.url|default:'' }}"
{% if request.dealer.logo %}
<img class="rounded-soft" style="max-width:150px; max-height:150px;"
src="{{ request.dealer.logo.url|default:'' }}"
alt="Dealer Logo" />
{% endif %}
</div>
</div>
<table class="table table-sm table-bordered border-gray-50">
<table class="table table-sm table-responsive border-gray-50">
<tr>
<td class="ps-1">
<strong>Customer Name</strong>
<strong>Dealership Name</strong>
</td>
<td class="text-center">
{{ dealer.arabic_name }}
<br>
{{ dealer.name }}
{{ request.dealer.name }}
</td>
<td class="text-end">
<strong>اسم&nbsp;العميل</strong>
<strong>اسم الوكالة</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Address</strong>
<strong>Dealership Address</strong>
</td>
<td class="text-center">{{ dealer.address }}</td>
<td class="text-center">{{ request.dealer.address }}</td>
<td class="text-end">
<strong>العنوان</strong>
<strong>عنوان الوكالة</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Phone</strong>
</td>
<td class="text-center">{{ dealer.phone_number }}</td>
<td class="text-center">{{ request.dealer.phone_number }}</td>
<td class="text-end">
<strong>جوال</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<td>
<strong>VAT Number</strong>
</td>
<td class="text-center">{{ dealer.vrn }}</td>
<td class="text-end p-1">
<td class="text-center">{{ request.dealer.vrn }}</td>
<td class="text-end">
<strong>الرقم الضريبي</strong>
</td>
</tr>
@ -165,43 +173,35 @@
</td>
<td class="text-center">{{ invoice.invoice_number }}</td>
<td class="text-end p-1">
<strong>رقم&nbsp;الفاتورة</strong>
<strong>رقم الفاتورة</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Date</strong>
</td>
<td class="text-center">{{ invoice.date_in_review| date:"Y/m/d" }}</td>
<td class="text-center">{{ invoice.date_approved| date:"Y/m/d" }}</td>
<td class="text-end p-1">
<strong>التاريخ</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Customer</strong>
<strong>Customer Name</strong>
</td>
<td class="text-center">{{ invoice.customer.customer_name }}</td>
<td class="text-end p-1">
<strong>العميل</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>VAT&nbsp;ID</strong>
</td>
<td class="text-center">{{ invoice.customer.vrn|default:"-" }}</td>
<td class="text-end p-1">
<strong>الرقم&nbsp;الضريبي</strong>
<strong>اسم العميل</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Email</strong>
</td>
<td class="text-center">{{ invoice.customer.email |default:"N/A" }}</td>
<td class="text-end p-1">
<strong>البريد&nbsp;الالكتروني</strong>
<strong>البريد الإلكتروني</strong>
</td>
</tr>
<tr>
@ -210,14 +210,14 @@
</td>
<td class="text-center">{{ invoice.get_terms_display }}</td>
<td class="text-end p-1">
<strong>طريقة&nbsp;الدفع</strong>
<strong>شروط الدفع</strong>
</td>
</tr>
</table>
</div>
<div class="d-flex justify-content-between">
<span class="fs-9 fw-thin">Car&nbsp;Details</span>
<span class="fs-9 fw-thin">تفاصيل&nbsp;السيارة</span>
<span class="fs-9 fw-thin">Car Details</span>
<span class="fs-9 fw-thin">تفاصيل السيارة</span>
</div>
<div class="invoice-table p-1">
<table class="table table-sm table-bordered m-1">
@ -229,6 +229,9 @@
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Model</span> / <span class="fs-10">الموديل</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Series</span> / <span class="fs-10">السلسلة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Trim</span> / <span class="fs-10">الفئة</span>
</th>
@ -236,7 +239,7 @@
<span class="fs-10">Year</span> / <span class="fs-10">السنة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">VIN</span> / <span class="fs-10">الهيكل</span>
<span class="fs-10">VIN</span> / <span class="fs-10">رقم الهيكل</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Quantity</span> / <span class="fs-10">الكمية</span>
@ -245,26 +248,30 @@
<span class="fs-10">Unit Price</span> / <span class="fs-10">سعر الوحدة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Including VAT</span> / <span class="fs-10">شامل الضريبة</span>
<span class="fs-10">Discount</span> / <span class="fs-10">الخصم</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">VAT</span> / <span class="fs-10">الضريبة</span>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
</th>
</tr>
</thead>
<tbody>
{% for item in data.cars %}
<tr>
<td class="ps-1 fs-10 align-content-center" colspan="3">{{ item.make }} - {{ item.model }} - {{ item.trim }}</td>
<td class="text-center fs-10 align-content-center">{{ item.year }}</td>
<td class="ps-1 fs-10 align-content-center">{{ item.vin }}</td>
<td class="text-center fs-10 align-content-center">{{ item.quantity|floatformat }}</td>
<td class="text-center fs-10 align-content-center">{{ item.unit_price|floatformat }}</td>
<td class="text-center fs-10 align-content-center">{{ item.total_vat|floatformat }}</td>
</tr>
{% endfor %}
<tr>
<td class="ps-1 fs-10 align-content-center" colspan="5"></td>
<td class="text-center fs-10 align-content-center">{{ data.quantity|floatformat }}</td>
<td class="text-center fs-10 align-content-center">{{ data.total_price_before_discount|floatformat }}</td>
<td class="text-center fs-10 align-content-center">{{ data.grand_total|floatformat }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_make.name }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_model.name }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_serie.name }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_trim.name }}</td>
<td class="text-center fs-10 align-content-center">{{ data.car.year }}</td>
<td class="ps-1 fs-10 align-content-center">{{ data.car.vin }}</td>
<td class="text-center fs-10 align-content-center">1</td>
<td class="text-center fs-10 align-content-center">{{ data.car.marked_price |floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.discount_amount |floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.vat_amount|floatformat:2 }}</td>
<td class="text-center fs-10 align-content-center">{{ data.final_price|floatformat:2 }}</td>
</tr>
</tbody>
</table>
@ -273,24 +280,26 @@
<span class="fs-9 fw-thin">Additional&nbsp;Services</span>
<span class="fs-9 fw-thin">الخدمات&nbsp;الإضافية</span>
</div>
{% if data.additionals %}
{% if data.additional_services %}
<div class="invoice-table p-1">
<table class="table table-sm table-bordered m-1">
<thead>
<tr>
<th class="text-center fs-10 align-content-center">Type&nbsp;/&nbsp;النوع</th>
<th class="text-center fs-10 align-content-center">Price&nbsp;/&nbsp;القيمة</th>
<th class="text-center fs-10 align-content-center">Price&nbsp;/&nbsp;السعر</th>
<th class="text-center fs-10 align-content-center">Service VAT&nbsp;/&nbsp;ضريبة الخدمة</th>
<th class="text-center fs-10 align-content-center">
<span class="fs-10">Including VAT</span> / <span class="fs-10">شامل الضريبة</span>
<span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
</th>
</tr>
</thead>
<tbody>
{% for item in data.additionals %}
{% for service in data.additional_services.services %}
<tr>
<td class="ps-1 text-start fs-10 align-content-center">{{ item.name }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ item.price|floatformat }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ item.price_|floatformat }}</td>
<td class="ps-1 text-start fs-10 align-content-center">{{ service.0.name }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price|floatformat }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ service.1|floatformat }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price_|floatformat }}</td>
</tr>
{% endfor %}
</tbody>
@ -302,24 +311,24 @@
<table class="table table-sm table-responsive">
<tr>
<td class="text-start ps-1">
<strong class="fs-9">VAT</strong>
<strong class="fs-9">Total VAT</strong>
</td>
<td class="text-center">
<span class="fs-9">{{ data.total_vat_amount|floatformat }} <span class="icon-saudi_riyal"></span></span>
<span class="fs-9">{{ data.total_vat|floatformat }} <span class="icon-saudi_riyal"></span></span>
</td>
<td class="text-end">
<strong class="fs-9">ضريبة&nbsp;القيمة&nbsp;المضافة</strong>
<strong class="fs-9">إجمالي&nbsp;ضريبة&nbsp;القيمة&nbsp;المضافة</strong>
</td>
</tr>
<tr>
<td class="text-start ps-1">
<strong class="fs-9">Total</strong>
<strong class="fs-9">Grand Total</strong>
</td>
<td class="text-center">
<span class="fs-9">{{ data.grand_total|floatformat }}&nbsp;<span class="icon-saudi_riyal"></span></span>
</td>
<td class="text-end">
<strong class="fs-9">الإجمالي</strong>
<strong class="fs-9">الإجمالي&nbsp;الكلي</strong>
</td>
</tr>
<tr>
@ -330,36 +339,34 @@
</table>
</div>
</div>
<br>
<br>
<br>
<br>
<br>
<br>
</div>
<div class="footer-note">
<div class="logo-img text-center">
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" />
<p class="fs-11 fw-bold">
<p class="fs-9 fw-bold">
<span>Haikal</span>&nbsp;|&nbsp;<span>هيكل</span>
</p>
</div>
<p class="fs-11">
<span class="fw-thin">Powered&nbsp;by&nbsp;</span><a class="text-decoration-none"
<span class="fw-thin">Powered&nbsp;by&nbsp;</span>
<a class="text-decoration-none fs-9"
href="https://tenhal.sa"
style="color: #112e40"><span>TENHAL</span>&nbsp;|&nbsp;<span>تنحل</span></a>
style="color: #112e40;"><span>TENHAL</span>&nbsp;|&nbsp;<span>تنحل</span></a>
</p>
</div>
</div>
<script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script>
<script src="{% static 'js/html2pdf.bundle.min.js' %}"></script>
<script>
document.getElementById('download-pdf').addEventListener('click', function () {
html2pdf().from(document.getElementById('invoice-content')).set({
margin: 0,
filename: "{{ invoice.invoice_number }}_{{ invoice.customer.customer_name }}_{{ invoice.date_in_review|date:'Y-m-d' }}.pdf",
filename: "{{ invoice.invoice_number }}_{{ invoice.customer.customer_name  }}_{{invoice.date_approved|date:'Y-m-d' }}.pdf",
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 3 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
jsPDF: { unit: 'mm', format: 'a3', orientation: 'portrait' }
}).save();
});
</script>