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_), "price_": str(self.price_),
"taxable": self.taxable, "taxable": self.taxable,
"uom": self.uom, "uom": self.uom,
"service_tax":str(self.service_tax)
} }
@property @property
@ -593,6 +594,13 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
if self.taxable if self.taxable
else self.price 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: class Meta:
verbose_name = _("Additional Services") verbose_name = _("Additional Services")
@ -865,19 +873,64 @@ class Car(Base):
# #
@property @property
def get_additional_services_amount(self): 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()]) 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): 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 @property
def final_price(self):
return Decimal(self.marked_price -self.discount)
@property
def vat_amount(self): def vat_amount(self):
vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first() 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 @property
def total_vat(self): def total_services_and_car_vat(self):
return Decimal(self.marked_price) + Decimal(self.vat_amount) 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): # def get_discount_amount(self,estimate,user):
# try: # try:
# instance = models.ExtraInfo.objects.get( # 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.urls import reverse
from django_ledger.models import ItemTransactionModel,InvoiceModel,LedgerModel,EntityModel from django_ledger.models import ItemTransactionModel,InvoiceModel,LedgerModel,EntityModel
from django.views.generic.detail import DetailView 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 ( from django_ledger.forms.purchase_order import (
ApprovedPurchaseOrderModelUpdateForm, ApprovedPurchaseOrderModelUpdateForm,
BasePurchaseOrderModelUpdateForm, BasePurchaseOrderModelUpdateForm,
@ -30,7 +35,7 @@ from django_ledger.forms.purchase_order import (
get_po_itemtxs_formset_class, get_po_itemtxs_formset_class,
) )
from django_ledger.views.purchase_order import PurchaseOrderModelModelViewQuerySetMixIn 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.detail import SingleObjectMixin
from django.views.generic.edit import UpdateView from django.views.generic.edit import UpdateView
from django.views.generic.base import RedirectView from django.views.generic.base import RedirectView
@ -973,3 +978,112 @@ class InvoiceModelUpdateView(LoginRequiredMixin, PermissionRequiredMixin, Update
# if not valid, return formset with errors... # if not valid, return formset with errors...
return self.render_to_response(context=self.get_context_data(itemtxs_formset=itemtxs_formset)) return self.render_to_response(context=self.get_context_data(itemtxs_formset=itemtxs_formset))
return super(InvoiceModelUpdateView, self).post(request, **kwargs) 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 #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/manager/", views.ManagerDashboard.as_view(),name="manager_dashboard"),
path("dashboards/sales/", views.SalesDashboard.as_view(), name="sales_dashboard"), path("dashboards/sales/", views.SalesDashboard.as_view(), name="sales_dashboard"),
path("dashboards/accountant/", views.AccountantDashboard.as_view(), name="accountant_dashboard"), path("dashboards/accountant/", views.AccountantDashboard.as_view(), name="accountant_dashboard"),
@ -738,27 +738,27 @@ urlpatterns = [
name="bank_account_delete", name="bank_account_delete",
), ),
path( path(
"<slug:dealer_slug>/coa_accounts/", "<slug:dealer_slug>/coa_accounts/<coa_pk>/",
views.AccountListView.as_view(), views.AccountListView.as_view(),
name="account_list", name="account_list",
), ),
path( path(
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/", "<slug:dealer_slug>/coa_accounts/<coa_pk>/<uuid:pk>/",
views.AccountDetailView.as_view(), views.AccountDetailView.as_view(),
name="account_detail", name="account_detail",
), ),
path( path(
"<slug:dealer_slug>/coa_accounts/create/", "<slug:dealer_slug>/coa_accounts/<coa_pk>/create/",
views.AccountCreateView.as_view(), views.AccountCreateView.as_view(),
name="account_create", name="account_create",
), ),
path( path(
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/update/", "<slug:dealer_slug>/coa_accounts/<coa_pk>/<uuid:pk>/update/",
views.AccountUpdateView.as_view(), views.AccountUpdateView.as_view(),
name="account_update", name="account_update",
), ),
path( path(
"<slug:dealer_slug>/coa_accounts/<uuid:pk>/delete/", "<slug:dealer_slug>/coa_accounts/<coa_pk>/<uuid:pk>/delete/",
views.account_delete, views.account_delete,
name="account_delete", name="account_delete",
), ),
@ -775,6 +775,7 @@ urlpatterns = [
views.EstimateDetailView.as_view(), views.EstimateDetailView.as_view(),
name="estimate_detail", name="estimate_detail",
), ),
path('<slug:dealer_slug>/sales/estimates/print/<uuid:pk>/', views.EstimatePrintView.as_view(), name='estimate_print'),
path( path(
"<slug:dealer_slug>/sales/estimates/create/", "<slug:dealer_slug>/sales/estimates/create/",
views.create_estimate, views.create_estimate,
@ -1093,6 +1094,29 @@ urlpatterns = [
path('<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/', path('<slug:dealer_slug>/chart-of-accounts/<slug:entity_slug>/list/',
views.ChartOfAccountModelListView.as_view(), views.ChartOfAccountModelListView.as_view(),
name='coa-list'), 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... # CASH FLOW STATEMENTS...
# Entities... # Entities...
path( path(

View File

@ -1288,18 +1288,24 @@ def get_finance_data(estimate,dealer):
) )
discount = extra_info.data.get("discount", 0) discount = extra_info.data.get("discount", 0)
discount = Decimal(discount) 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 { return {
"car": car, "car": car,
"discounted_price": (Decimal(car.marked_price) - discount) or 0, "discounted_price": discounted_price or 0,
"price_before_discount": car.marked_price, "price_before_discount": car.marked_price,
"vat_amount": vat_amount, "vat_amount": vat_amount,
"vat_rate": vat.rate, "vat_rate": vat.rate,
"discount_amount": discount, "discount_amount": discount,
"additional_services": additional_services, "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 decimal import Decimal
from io import TextIOWrapper from io import TextIOWrapper
from django.apps import apps from django.apps import apps
from datetime import datetime, timedelta from datetime import datetime, timedelta,date
from calendar import month_name from calendar import month_name
from pyzbar.pyzbar import decode from pyzbar.pyzbar import decode
from urllib.parse import urlparse, urlunparse from urllib.parse import urlparse, urlunparse
@ -152,6 +152,10 @@ from .override import (
BaseBillActionView as BaseBillActionViewBase, BaseBillActionView as BaseBillActionViewBase,
InventoryListView as InventoryListViewBase, InventoryListView as InventoryListViewBase,
InvoiceModelUpdateView as InvoiceModelUpdateViewBase, InvoiceModelUpdateView as InvoiceModelUpdateViewBase,
ChartOfAccountModelCreateView as ChartOfAccountModelCreateViewBase,
ChartOfAccountModelListView as ChartOfAccountModelListViewBase,
ChartOfAccountModelUpdateView as ChartOfAccountModelUpdateViewBase,
CharOfAccountModelActionView as CharOfAccountModelActionViewBase,
) )
from django_ledger.models import ( from django_ledger.models import (
@ -168,6 +172,7 @@ from django_ledger.models import (
BillModel, BillModel,
LedgerModel, LedgerModel,
PurchaseOrderModel, PurchaseOrderModel,
ChartOfAccountModel
) )
from django_ledger.views.financial_statement import ( from django_ledger.views.financial_statement import (
FiscalYearBalanceSheetView, FiscalYearBalanceSheetView,
@ -391,101 +396,164 @@ class TestView(TemplateView):
template_name = "inventory/cars_list_api.html" template_name = "inventory/cars_list_api.html"
class DealerDashboard(LoginRequiredMixin, TemplateView): # class DealerDashboard(LoginRequiredMixin, TemplateView):
""" # """
ManagerDashboard class is a view handling the dashboard for a manager. # ManagerDashboard class is a view handling the dashboard for a manager.
Provides functionality to manage and view various statistics and data specific # Provides functionality to manage and view various statistics and data specific
to the dealer associated with the authenticated manager. It uses a specific # to the dealer associated with the authenticated manager. It uses a specific
template and ensures authentication before granting access. The class # template and ensures authentication before granting access. The class
aggregates data about cars, leads, financial statistics, and other related # aggregates data about cars, leads, financial statistics, and other related
business information for display in the manager's dashboard. # business information for display in the manager's dashboard.
:ivar template_name: Path to the template used for rendering the manager's dashboard. # :ivar template_name: Path to the template used for rendering the manager's dashboard.
:type template_name: str # :type template_name: str
""" # """
template_name = "dashboards/dealer_dashbaord.html" # template_name = "dashboards/dealer_dashbaord.html"
# def dispatch(self, request, *args, **kwargs): # # def dispatch(self, request, *args, **kwargs):
# if not request.user.is_authenticated: # # if not request.user.is_authenticated:
# return redirect("welcome") # # return redirect("welcome")
# if not getattr(request.user, "dealer", False): # # if not getattr(request.user, "dealer", False):
# return HttpResponseForbidden( # # return HttpResponseForbidden(
# "You are not authorized to view this dashboard." # # "You are not authorized to view this dashboard."
# ) # # )
# return super().dispatch(request, *args, **kwargs) # # return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs): # def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) # context = super().get_context_data(**kwargs)
dealer = get_user_type(self.request) # dealer = get_user_type(self.request)
entity = dealer.entity # entity = dealer.entity
qs = models.Car.objects.filter(dealer=dealer) # qs = models.Car.objects.filter(dealer=dealer)
total_cars = qs.count() # total_cars = qs.count()
stats = models.CarFinance.objects.filter(car__dealer=dealer).aggregate( # # stats = models.CarFinance.objects.filter(car__dealer=dealer).aggregate(
total_cost_price=Sum("cost_price"), # # total_cost_price=Sum("cost_price"),
total_selling_price=Sum("selling_price"), # # total_selling_price=Sum("selling_price"),
) # # )
total_cost_price = stats["total_cost_price"] or 0 # # total_cost_price = stats["total_cost_price"] or 0
total_selling_price = stats["total_selling_price"] or 0 # # total_selling_price = stats["total_selling_price"] or 0
total_profit = total_selling_price - total_cost_price # # total_profit = total_selling_price - total_cost_price
new_leads = models.Lead.objects.filter( # # new_leads = models.Lead.objects.filter(
dealer=dealer, status=models.Status.NEW # # dealer=dealer, status=models.Status.NEW
).count() # # ).count()
pending_leads = models.Lead.objects.filter( # # pending_leads = models.Lead.objects.filter(
dealer=dealer, status=models.Status.CONTACTED # # dealer=dealer, status=models.Status.CONTACTED
).count() # # ).count()
canceled_leads = models.Lead.objects.filter( # # canceled_leads = models.Lead.objects.filter(
dealer=dealer, status=models.Status.UNQUALIFIED # # dealer=dealer, status=models.Status.UNQUALIFIED
).count() # # ).count()
car_status_qs = qs.values("status").annotate(count=Count("status")) # # car_status_qs = qs.values("status").annotate(count=Count("status"))
car_status = {status: count for status, count in car_status_qs} # # 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_qs = qs.values("id_car_make__name").annotate(count=Count("id"))
car_by_make = list(car_by_make_qs) # # car_by_make = list(car_by_make_qs)
context["dealer"] = dealer # # context["dealer"] = dealer
context["total_activity"] = models.UserActivityLog.objects.filter( # # context["total_activity"] = models.UserActivityLog.objects.filter(
user=dealer.user # # user=dealer.user
).count() # # ).count()
context["total_cars"] = total_cars # # context["total_cars"] = total_cars
context["total_reservations"] = models.CarReservation.objects.filter( # # context["total_reservations"] = models.CarReservation.objects.filter(
reserved_until__gte=timezone.now() # # reserved_until__gte=timezone.now()
).count() # # ).count()
context["total_cost_price"] = total_cost_price # # context["total_cost_price"] = total_cost_price
context["total_selling_price"] = total_selling_price # # context["total_selling_price"] = total_selling_price
context["total_profit"] = total_profit # # context["total_profit"] = total_profit
context["new_leads"] = new_leads # # context["new_leads"] = new_leads
context["pending_leads"] = pending_leads # # context["pending_leads"] = pending_leads
context["canceled_leads"] = canceled_leads # # context["canceled_leads"] = canceled_leads
context["car"] = json.dumps(car_by_make) # # context["car"] = json.dumps(car_by_make)
context["available_cars"] =qs.filter(status='available').count() # # context["available_cars"] =qs.filter(status='available').count()
context["sold_cars"] = qs.filter(status='sold').count() # # context["sold_cars"] = qs.filter(status='sold').count()
context["reserved_cars"] = qs.filter(status='reserved').count() # # context["reserved_cars"] = qs.filter(status='reserved').count()
context["hold_cars"] =qs.filter(status='hold').count() # # context["hold_cars"] =qs.filter(status='hold').count()
context["damaged_cars"] = qs.filter(status='damaged').count() # # context["damaged_cars"] = qs.filter(status='damaged').count()
context["transfer_cars"] = qs.filter(status='transfer').count() # # context["transfer_cars"] = qs.filter(status='transfer').count()
context["present_inventory_count"]=total_cars-context["sold_cars"]-context["damaged_cars"] # # context["present_inventory_count"]=total_cars-context["sold_cars"]-context["damaged_cars"]
cars_sold=qs.filter(status='sold') # # cars_sold=qs.filter(status='sold')
# cars_sold.aggregate(total_inventory_value=sum()) # # cars_sold.aggregate(total_inventory_value=sum())
context["customers"] = entity.get_customers().count() # context["customers"] = entity.get_customers().count()
context["staff"] = models.Staff.objects.filter(dealer=dealer).count() # context["staff"] = models.Staff.objects.filter(dealer=dealer).count()
context["total_leads"] = models.Lead.objects.filter(dealer=dealer).count() # context["total_leads"] = models.Lead.objects.filter(dealer=dealer).count()
context["invoices"] = entity.get_invoices().count() # context["invoices"] = entity.get_invoices().count()
context["estimates"] = entity.get_estimates().count() # context["estimates"] = entity.get_estimates().count()
context["purchase_orders"] = entity.get_purchase_orders().count() # context["purchase_orders"] = entity.get_purchase_orders().count()
return context # 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
)
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])
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,
}
return render(request, 'dashboards/dealer_dashboard.html', context)
class ManagerDashboard(LoginRequiredMixin, TemplateView): class ManagerDashboard(LoginRequiredMixin, TemplateView):
""" """
@ -4333,6 +4401,10 @@ class AccountListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
dealer = get_user_type(self.request) dealer = get_user_type(self.request)
accounts = dealer.entity.get_all_accounts() accounts = dealer.entity.get_all_accounts()
return apply_search_filters(accounts, query) 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( class AccountCreateView(
@ -4398,10 +4470,17 @@ class AccountCreateView(
def get_success_url(self): def get_success_url(self):
return reverse( 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): class AccountDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
""" """
Represents the detailed view for an account with additional context data related to account 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__billmodel",
"journal_entry__ledger__invoicemodel", "journal_entry__ledger__invoicemodel",
) )
context["url_kwargs"] = self.kwargs
return context return context
@ -4502,13 +4582,21 @@ class AccountUpdateView(
def get_success_url(self): def get_success_url(self):
return reverse_lazy( 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 @login_required
@permission_required("django_ledger.delete_accountmodel") @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 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 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() account.delete()
messages.success(request, _("Account deleted successfully")) 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 # Sales list
@ -4815,7 +4903,7 @@ def create_estimate(request, dealer_slug, slug=None):
"quantity": 1, "quantity": 1,
"unit_cost": round(float(i.marked_price)), "unit_cost": round(float(i.marked_price)),
"unit_revenue": 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_cost": instance.cost_price,
# "unit_revenue": instance.marked_price, # "unit_revenue": instance.marked_price,
# "quantity": Decimal(quantities), # "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) # calculator = CarFinanceCalculator(estimate)
# finance_data = calculator.get_finance_data() # finance_data = calculator.get_finance_data()
finance_data = get_finance_data(estimate,dealer) finance_data = get_finance_data(estimate,dealer)
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first() invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
kwargs["data"] = finance_data kwargs["data"] = finance_data
@ -5002,7 +5091,7 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
car = estimate.get_itemtxs_data()[0].first().item_model.car car = estimate.get_itemtxs_data()[0].first().item_model.car
selected_items = car.additional_services.filter(dealer=dealer) selected_items = car.additional_services.filter(dealer=dealer)
form = forms.AdditionalFinancesForm() 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 form.initial["additional_finances"] = selected_items
kwargs["additionals_form"] = form kwargs["additionals_form"] = form
except Exception as e: except Exception as e:
@ -5010,6 +5099,16 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
return super().get_context_data(**kwargs) 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 @login_required
@permission_required("inventory.add_saleorder", raise_exception=True) @permission_required("inventory.add_saleorder", raise_exception=True)
def create_sale_order(request, dealer_slug, pk): 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')}." 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 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() item.item_model.car.mark_as_sold()
messages.success(request, "Sale Order created successfully") messages.success(request, "Sale Order created successfully")
@ -11027,12 +11127,14 @@ def purchase_report_csv_export(request,dealer_slug):
def car_sale_report_view(request, dealer_slug): def car_sale_report_view(request, dealer_slug):
dealer = get_object_or_404(models.Dealer, slug=dealer_slug) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
cars_sold = models.Car.objects.filter(dealer=dealer, status='sold') cars_sold = models.Car.objects.filter(dealer=dealer, status='sold')
# Get filter parameters from the request # Get filter parameters from the request
selected_make = request.GET.get('make') selected_make = request.GET.get('make')
selected_model = request.GET.get('model') selected_model = request.GET.get('model')
selected_serie = request.GET.get('serie') selected_serie = request.GET.get('serie')
selected_year = request.GET.get('year') selected_year = request.GET.get('year')
selected_stock_type=request.GET.get('stock_type')
# Apply filters to the queryset # Apply filters to the queryset
if selected_make: if selected_make:
@ -11043,78 +11145,115 @@ def car_sale_report_view(request, dealer_slug):
cars_sold = cars_sold.filter(id_car_serie__name=selected_serie) cars_sold = cars_sold.filter(id_car_serie__name=selected_serie)
if selected_year: if selected_year:
cars_sold = cars_sold.filter(year=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 # Get distinct values for filter dropdowns
makes = models.Car.objects.filter(dealer=dealer, status='sold').values_list('id_car_make__name', flat=True).distinct() 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() 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') 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 # # 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 = cars_sold.aggregate(total_revenue=Sum('finances__marked_price'))['total_revenue'] or 0 total_revenue_from_additonals=sum([car.get_additional_services()['total'] for car in cars_sold])
# total_vat = cars_sold.aggregate(total_vat=Sum('finances__vat_amount'))['total_vat'] or 0 total_vat_from_additonals=sum([car.get_additional_services()['services_vat'] for car in cars_sold])
total_discount = cars_sold.aggregate(total_discount=Sum('finances__discount_amount'))['total_discount'] or 0 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") current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S")
context = { context = {
'cars_sold': cars_sold, 'cars_sold': cars_sold,
'total_cars_sold':total_cars_sold,
'current_time': current_time, 'current_time': current_time,
'dealer': dealer, 'dealer': dealer,
'total_revenue': total_revenue, 'total_revenue_from_cars': total_revenue_from_cars,
# 'total_vat': total_vat, '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, 'total_discount': total_discount,
'makes': makes, 'makes': makes,
'models': models_qs, 'models': models_qs,
'series': series, 'series': series,
'years': years, 'years': years,
'stock_types':stock_types,
'selected_make': selected_make, 'selected_make': selected_make,
'selected_model': selected_model, 'selected_model': selected_model,
'selected_serie': selected_serie, 'selected_serie': selected_serie,
'selected_year': selected_year, 'selected_year': selected_year,
'selected_stock_type':selected_stock_type,
} }
return render(request, 'ledger/reports/car_sale_report.html', context) return render(request, 'ledger/reports/car_sale_report.html', context)
def car_sale_report_csv_export(request,dealer_slug): @login_required
def car_sale_report_csv_export(request, dealer_slug):
response = HttpResponse(content_type='text/csv') 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" filename = f"sales_report_{dealer_slug}_{current_time}.csv"
response['Content-Disposition'] = f'attachment; filename="{filename}"' response['Content-Disposition'] = f'attachment; filename="{filename}"'
writer = csv.writer(response) writer = csv.writer(response)
header=[ # Define the CSV header based on your HTML table headers
'Make', header = [
'VIN', 'VIN', 'Make', 'Model', 'Year', 'Serie', 'Trim', 'Mileage',
'Model', 'Stock Type', 'Created Date', 'Sold Date', 'Cost Price',
'Year', 'Marked Price', 'Discount Amount', 'Selling Price',
'Serie', 'VAT on Car', 'Services Price', 'VAT on Services', 'Final Total',
'Trim', 'Invoice Number'
'Mileage',
'Stock Type',
'Created Date',
'Sold Date',
'Cost Price',
'Marked Price',
'Discount Amount',
'Selling Price',
'Tax Amount',
'Invoice Number',
] ]
writer.writerow(header) writer.writerow(header)
dealer=get_object_or_404(models.Dealer,slug=dealer_slug) dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
cars_sold=models.Car.objects.filter(dealer=dealer,status='sold') 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: for car in cars_sold:
writer.writerow([ # 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.vin,
car.id_car_make.name, car.id_car_make.name,
car.id_car_model.name, car.id_car_model.name,
@ -11124,13 +11263,16 @@ def car_sale_report_csv_export(request,dealer_slug):
car.mileage if car.mileage else '0', car.mileage if car.mileage else '0',
car.stock_type, car.stock_type,
car.created_at.strftime("%Y-%m-%d %H:%M:%S") if car.created_at else '', 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.cost_price,
car.marked_price, car.marked_price,
car.discount_amount, car.discount, # Ensure this property returns a number
car.selling_price, car.final_price, # Selling Price without VAT
car.vat_amount, # TODO : check later car.vat_amount, # VAT on the car
car.item_model.invoicemodel_set.first().invoice_number services_total_price, # Total services without VAT
services_vat_amount, # VAT on services
car.final_price_plus_services_plus_vat,
invoice_number,
]) ])
return response return response
@ -11382,4 +11524,16 @@ def ticket_update(request, ticket_id):
class ChartOfAccountModelListView(ChartOfAccountModelListViewBase): class ChartOfAccountModelListView(ChartOfAccountModelListViewBase):
template_name = 'chart_of_accounts/coa_list.html' 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="col-12">
<div class="d-flex justify-content-between align-items-center mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<h1 class="display-4 mb-0">Chart of Accounts</h1> <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 {% icon 'carbon:add-alt' 24 %} Add New
</a> </a>
</div> </div>
{% if not inactive %} {% 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' %} {% trans 'Show Inactive' %}
</a> </a>
{% else %} {% 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' %} {% trans 'Show Active' %}
</a> </a>
{% endif %} {% 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="card-footer bg-transparent border-top-0">
<div class="d-flex flex-wrap gap-2"> <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' %} <i class="fas fa-edit me-1"></i> {% trans 'Update' %}
</a> </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' %} <i class="fas fa-book me-1"></i> {% trans 'Accounts' %}
</a> </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' %} <i class="fas fa-plus-circle me-1"></i> {% trans 'Add Account' %}
</a> </a>
{% if coa_model.can_mark_as_default %} {% 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' %} <i class="fas fa-star me-1"></i> {% trans 'Mark as Default' %}
</a> </a>
{% endif %} {% endif %}
{% if coa_model.can_deactivate %} {% 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' %} <i class="fas fa-toggle-off me-1"></i> {% trans 'Mark as Inactive' %}
</a> </a>
{% elif coa_model.can_activate %} {% 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' %} <i class="fas fa-toggle-on me-1"></i> {% trans 'Mark as Active' %}
</a> </a>
{% endif %} {% endif %}

View File

@ -1,28 +1,39 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block content %} {% 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="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"> <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-0">Business Health Dashboard <i class="fas fa-chart-area text-primary ms-2"></i></h2> <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>
<div class="dropdown"> <form method="GET" class="date-filter-form">
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <div class="row g-3">
Last 30 Days <div class="col-12 col-md-4">
</button> <label for="start-date" class="form-label">Start Date</label>
<ul class="dropdown-menu dropdown-menu-end shadow"> <input type="date" class="form-control" id="start-date" name="start_date"
<li><a class="dropdown-item" href="#">Today</a></li> value="{{ start_date|date:'Y-m-d' }}" required>
<li><a class="dropdown-item" href="#">Last 7 Days</a></li> </div>
<li><a class="dropdown-item" href="#">Last 90 Days</a></li> <div class="col-12 col-md-4">
</ul> <label for="end-date" class="form-label">End Date</label>
</div> <input type="date" class="form-control" id="end-date" name="end_date"
</div> 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"> <div class="row g-4 mb-5">
<div class="col-sm-6 col-md-4 col-lg-3"> <div class="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0"> <div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4"> <div class="card-body d-flex flex-column justify-content-between p-4">
<div> <div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Revenue</p> <p class="text-uppercase text-muted fw-bold small mb-1">Total Cost of Cars Sold</p>
<h4 class="fw-bolder text-primary mb-3">$1.25M</h4> <h4 class="fw-bolder text-secondary mb-3">{{total_cost_of_cars_sold|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div> </div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start"> <span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month +8% from last month
@ -34,8 +45,8 @@
<div class="card h-100 shadow-sm border-0"> <div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4"> <div class="card-body d-flex flex-column justify-content-between p-4">
<div> <div>
<p class="text-uppercase text-muted fw-bold small mb-1">Net Profit</p> <p class="text-uppercase text-muted fw-bold small mb-1">Total Revenue from cars</p>
<h4 class="fw-bolder text-success mb-3">$1.25M</h4> <h4 class="fw-bolder text-primary mb-3">{{total_revenue_from_cars|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div> </div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start"> <span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month +8% from last month
@ -47,8 +58,8 @@
<div class="card h-100 shadow-sm border-0"> <div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4"> <div class="card-body d-flex flex-column justify-content-between p-4">
<div> <div>
<p class="text-uppercase text-muted fw-bold small mb-1">Gross Profit</p> <p class="text-uppercase text-muted fw-bold small mb-1">Net Profit From Cars</p>
<h4 class="fw-bolder text-info mb-3">$1.25M</h4> <h4 class="fw-bolder text-success mb-3">{{net_profit_from_cars|floatformat:2}}<span class="icon-saudi_riyal"></span></h4>
</div> </div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start"> <span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month +8% from last month
@ -56,6 +67,87 @@
</div> </div>
</div> </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="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0"> <div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4"> <div class="card-body d-flex flex-column justify-content-between p-4">
@ -69,12 +161,26 @@
</div> </div>
</div> </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="col-sm-6 col-md-4 col-lg-3">
<div class="card h-100 shadow-sm border-0"> <div class="card h-100 shadow-sm border-0">
<div class="card-body d-flex flex-column justify-content-between p-4"> <div class="card-body d-flex flex-column justify-content-between p-4">
<div> <div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total VAT Collected</p> <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> </div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start"> <span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start">
+8% from last month +8% from last month
@ -87,7 +193,7 @@
<div class="card-body d-flex flex-column justify-content-between p-4"> <div class="card-body d-flex flex-column justify-content-between p-4">
<div> <div>
<p class="text-uppercase text-muted fw-bold small mb-1">Total Cars Sold</p> <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> </div>
<span class="badge bg-success-subtle text-success fw-bold p-2 rounded-pill d-inline-flex align-self-start"> <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 +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> <h5 class="fw-bold mb-0 text-dark">Car Models by Make in Inventory</h5>
</div> </div>
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6 mb-4"> <div class="col-md-6 mb-4 mt-3">
<label for="carMakeSelect" class="form-label fs-7">Select a Car Make:</label> <label for="carMakeSelect" class="form-label fs-8 mb-2">Select a Car Make:</label>
<select id="carMakeSelect" class="form-select"> <select id="carMakeSelect" class="form-select">
<option value="" disabled selected>-- Choose a make --</option> <option value="" disabled selected>-- Choose a make --</option>
</select> </select>

View File

@ -22,7 +22,7 @@
class="btn btn-sm btn-phoenix-secondary" class="btn btn-sm btn-phoenix-secondary"
data-bs-dismiss="modal">{% trans 'No' %}</button> data-bs-dismiss="modal">{% trans 'No' %}</button>
<div class="btn btn-sm btn-phoenix-danger"> <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"> method="post">
{% csrf_token %} {% csrf_token %}
<button type="submit" class="btn btn-sm btn-phoenix-danger">{% trans 'Yes' %}</button> <button type="submit" class="btn btn-sm btn-phoenix-danger">{% trans 'Yes' %}</button>
@ -135,7 +135,7 @@
<div class="mt-3 d-flex"> <div class="mt-3 d-flex">
{% if perms.django_ledger.change_chartofaccountmodel %} {% if perms.django_ledger.change_chartofaccountmodel %}
<a class="btn btn-sm btn-phoenix-primary me-1" <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="bi bi-pencil-square"></i> -->
<i class="fa-solid fa-pen-to-square"></i> {{ _("Edit") }} <i class="fa-solid fa-pen-to-square"></i> {{ _("Edit") }}
</a> </a>
@ -149,7 +149,7 @@
</a> </a>
{% endif %} {% endif %}
<a class="btn btn-sm btn-phoenix-secondary" <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="bi bi-arrow-left-square-fill"></i> -->
<i class="fa-regular fa-circle-left"></i> {% trans 'Back to COA List' %} <i class="fa-regular fa-circle-left"></i> {% trans 'Back to COA List' %}
</a> </a>

View File

@ -24,7 +24,7 @@
{{ _("Add Account") }} {{ _("Add Account") }}
{% endif %} {% endif %}
<i class="fa-solid fa-book ms-2 text-primary"></i> <i class="fa-solid fa-book ms-2 text-primary"></i>
</h3> </h3>
</div> </div>
<div class="card-body bg-light-subtle"> <div class="card-body bg-light-subtle">
@ -44,7 +44,7 @@
<i class="saveBtnIcon fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }} <i class="saveBtnIcon fa-solid fa-floppy-disk me-1"></i>{{ _("Save") }}
</button> </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> </div>
</form> </form>

View File

@ -17,7 +17,7 @@
<div class="d-flex justify-content-between mb-2"> <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> <h3 class=""> {% trans "Accounts" %}<i class="fa-solid fa-book ms-2 text-primary"></i></h3>
{% if perms.django_ledger.add_chartofaccountmodel %} {% 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> class="btn btn-md btn-phoenix-primary"><i class="fa fa-plus me-2"></i>{% trans 'New Account' %}</a>
{% endif %} {% endif %}
</div> </div>
@ -204,7 +204,7 @@
{% url "account_create" request.dealer.slug as create_account_url %} {% url "account_create" request.dealer.slug as create_account_url %}
{% include "empty-illustration-page.html" with value="account" url=create_account_url %} {% include "empty-illustration-page.html" with value="account" url=create_account_url %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block customerJS %} {% block customerJS %}
<script> <script>

View File

@ -47,12 +47,12 @@
<span class="fas fa-ellipsis-h fs-10"></span> <span class="fas fa-ellipsis-h fs-10"></span>
</button> </button>
<div class="dropdown-menu dropdown-menu-end py-2"> <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> class="dropdown-item text-success-dark">{% trans "View Journal Entries" %}</a>
<div class="dropdown-divider"></div> {% comment %} <div class="dropdown-divider"></div> {% endcomment %}
<button class="dropdown-item text-danger" {% comment %} <button class="dropdown-item text-danger"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#deleteModal">{% trans "Delete" %}</button> data-bs-target="#deleteModal">{% trans "Delete" %}</button> {% endcomment %}
</div> </div>
</div> </div>
</td> </td>

View File

@ -51,7 +51,7 @@
<section id="filters" class="mb-5 p-4 rounded border border-primary"> <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> <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"> <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> <label for="make-select" class="form-label">{% trans 'Make' %}</label>
<select id="make-select" name="make" class="form-select"> <select id="make-select" name="make" class="form-select">
<option value="">{% trans 'All Makes' %}</option> <option value="">{% trans 'All Makes' %}</option>
@ -60,7 +60,7 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
<label for="model-select" class="form-label">{% trans 'Model' %}</label> <label for="model-select" class="form-label">{% trans 'Model' %}</label>
<select id="model-select" name="model" class="form-select"> <select id="model-select" name="model" class="form-select">
<option value="">{% trans 'All Models' %}</option> <option value="">{% trans 'All Models' %}</option>
@ -69,7 +69,7 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
<div class="col-md-3"> <div class="col-md-2">
<label for="serie-select" class="form-label">{% trans 'Serie' %}</label> <label for="serie-select" class="form-label">{% trans 'Serie' %}</label>
<select id="serie-select" name="serie" class="form-select"> <select id="serie-select" name="serie" class="form-select">
<option value="">{% trans 'All Series' %}</option> <option value="">{% trans 'All Series' %}</option>
@ -87,36 +87,98 @@
{% endfor %} {% endfor %}
</select> </select>
</div> </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> <button type="submit" class="btn btn-primary w-100"><i class="fas fa-filter me-2"></i>{% trans 'Filter' %}</button>
</div> </div>
</form> </form>
</section> </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"> <section id="summary" class="mb-5">
<h2 class="section-heading mb-4 border-start border-5 border-primary p-2">{% trans 'Report Summary' %}</h2> <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="row g-4">
<div class="col-md-6 col-lg-3"> <div class="col-md-6 col-lg-3">
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total Revenue' %}<span class="icon-saudi_riyal"></span></h5> <h5 class="card-title"><span>{% trans 'Total Revenue from Cars' %}<span class="icon-saudi_riyal"></span></span></h5>
<p class="card-text">{{ total_revenue|floatformat:2 }} <span class="icon-saudi_riyal"></span></p> <p class="card-text"><span>{{ total_revenue_from_cars|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-6 col-lg-3"> <div class="col-md-6 col-lg-3">
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total VAT Amount' %}<i class="fas fa-percent ms-2"></i></h5> <h5 class="card-title"><span>{% trans 'Total Revenue from Services' %}<span class="icon-saudi_riyal"></span></span></h5>
<p class="card-text">{{ 10000|floatformat:2 }} <span class="icon-saudi_riyal"></span></p> <p class="card-text"><span>{{ total_revenue_from_additonals|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></p>
</div> </div>
</div> </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="col-md-6 col-lg-3">
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total Discount Amount' %}<i class="fas fa-tag ms-2"></i></h5> <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> </div>
</div> </div>
@ -124,13 +186,10 @@
<div class="card summary-card"> <div class="card summary-card">
<div class="card-body"> <div class="card-body">
<h5 class="card-title">{% trans 'Total Cars Sold' %}<i class="fas fa-car ms-2"></i></h5> <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>
</div> </div>
</div> </div>
</section> </section>
@ -142,7 +201,7 @@
<i class="bi bi-download me-2"></i>{% trans 'Download as CSV' %} <i class="bi bi-download me-2"></i>{% trans 'Download as CSV' %}
</a> </a>
</div> </div>
<div class="table-responsive"> <div class="table-responsive table-container">
<table class="table table-striped table-hover table-bordered table-sm"> <table class="table table-striped table-hover table-bordered table-sm">
<thead> <thead>
<tr> <tr>
@ -160,7 +219,10 @@
<th class="fs-9">{% trans 'Marked Price' %}</th> <th class="fs-9">{% trans 'Marked Price' %}</th>
<th class="fs-9">{% trans 'Discount Amount' %}</th> <th class="fs-9">{% trans 'Discount Amount' %}</th>
<th class="fs-9">{% trans 'Selling Price' %}</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> <th class="fs-9">{% trans 'Invoice Number' %}</th>
</tr> </tr>
</thead> </thead>
@ -178,12 +240,15 @@
<td class="fs-9">{{ car.stock_type|capfirst }}</td> <td class="fs-9">{{ car.stock_type|capfirst }}</td>
<td class="fs-9">{{ car.created_at|date }}</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.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"><span>{{ car.cost_price }}<span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9">{{ car.marked_price }} <span class="icon-saudi_riyal"></span></td> <td class="fs-9"><span>{{ car.marked_price }} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9">{{ car.total_discount }} <span class="icon-saudi_riyal"></span></td># TODO : check later <td class="fs-9"><span>{{ car.discount}} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9">{{ car.selling_price }} <span class="icon-saudi_riyal"></span></td> <td class="fs-9"><span>{{ car.final_price}} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9">{{ car.vat_amount }} <span class="icon-saudi_riyal"></span></td># TODO : check later <td class="fs-9"><span>{{ car.vat_amount|floatformat:2 }} <span class="icon-saudi_riyal"></span></span></td>
<td class="fs-9">{{ car.invoice.invoice_number }}</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> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View File

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

View File

@ -112,7 +112,7 @@
onclick="setFormAction('review')" onclick="setFormAction('review')"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#confirmModal"> 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> </button>
{% endif %} {% endif %}
{% elif estimate.status == 'in_review' %} {% elif estimate.status == 'in_review' %}
@ -122,46 +122,49 @@
class="btn btn-phoenix-secondary" class="btn btn-phoenix-secondary"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#confirmModal"> 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> </button>
{% endif %} {% endif %}
{% if estimate.can_approve and not request.is_manager %} {% if estimate.can_approve and not request.is_manager %}
<button class="btn btn-phoenix-warning" disabled> <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> </button>
{% endif %} {% endif %}
{% elif estimate.status == 'approved' %} {% elif estimate.status == 'approved' %}
{% if perms.django_ledger.change_estimatemodel %} {% if perms.django_ledger.change_estimatemodel %}
<a href="{% url 'send_email' request.dealer.slug estimate.pk %}" <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 %} {% endif %}
{% if estimate.sale_orders.first %} {% if estimate.sale_orders.first %}
<!--if sale order exist--> <!--if sale order exist-->
{% if perms.django_ledger.add_invoicemodel %} {% if perms.django_ledger.add_invoicemodel %}
<a href="{% url 'invoice_create' request.dealer.slug estimate.pk %}" <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 %} {% endif %}
{% if perms.inventory.view_saleorder %} {% if perms.inventory.view_saleorder %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" <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 %} {% endif %}
{% else %} {% else %}
{% if perms.inventory.add_saleorder %} {% if perms.inventory.add_saleorder %}
<a href="{% url 'create_sale_order' request.dealer.slug estimate.pk %}" <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 %}
{% endif %} {% endif %}
{% elif estimate.status == 'completed' %} {% elif estimate.status == 'completed' %}
{% if perms.inventory.view_saleorder %} {% if perms.inventory.view_saleorder %}
<a href="{% url 'order_detail' request.dealer.slug estimate.sale_orders.first.pk %}" <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 %} {% endif %}
{% if perms.django_ledger.view_invoicemodel %} {% if perms.django_ledger.view_invoicemodel %}
<a href="{% url 'invoice_detail' request.dealer.slug request.entity.slug estimate.invoicemodel_set.first.pk %}" <a href="{% url 'invoice_detail' request.dealer.slug request.entity.slug estimate.invoicemodel_set.first.pk %}"
class="btn btn-phoenix-primary btn-sm" class="btn btn-phoenix-primary btn-sm"
type="button"><i class="fa-solid fa-receipt me-1"></i> type="button"><i class="fa-solid fa-receipt"></i>
<span class="d-none d-sm-inline-block">{{ _("View Invoice") }}</span> {{ _("View Invoice") }}</a>
</a>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if estimate.can_cancel %} {% if estimate.can_cancel %}
@ -169,7 +172,7 @@
<button class="btn btn-phoenix-danger" <button class="btn btn-phoenix-danger"
data-bs-toggle="modal" data-bs-toggle="modal"
data-bs-target="#CancelModal"> 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> </button>
{% endif %} {% endif %}
{% endif %} {% endif %}
@ -179,31 +182,31 @@
<div class="row"> <div class="row">
<div class="col mb-2"> <div class="col mb-2">
<h6> <h6>
<i class="fa-solid fa-hashtag me-1"></i> {% trans 'Quotation Number' %}: <i class="fa-solid fa-hashtag"></i> {% trans 'Quotation Number' %}:
</h6> </h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.estimate_number }}</p> <p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.estimate_number }}</p>
</div> </div>
<div class="col mb-2"> <div class="col mb-2">
<h6> <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> </h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.created }}</p> <p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.created }}</p>
</div> </div>
<div class="col mb-2"> <div class="col mb-2">
<h6> <h6>
<i class="fa-solid fa-user me-1"></i> {% trans 'Customer' %}: <i class="fa-solid fa-user"></i> {% trans 'Customer' %}:
</h6> </h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.customer_name }}</p> <p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.customer_name }}</p>
</div> </div>
<div class="col mb-2"> <div class="col mb-2">
<h6> <h6>
<i class="fa-solid fa-envelope me-1"></i> {% trans 'Email' %}: <i class="fa-solid fa-envelope"></i> {% trans 'Email' %}:
</h6> </h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.email }}</p> <p class="fs-9 text-body-secondary fw-semibold mb-0">{{ estimate.customer.email }}</p>
</div> </div>
<div class="col"> <div class="col">
<h6> <h6>
<i class="fa-solid fa-list me-1"></i> {% trans "Quotation Status" %}: <i class="fa-solid fa-list"></i> {% trans "Quotation Status" %}:
</h6> </h6>
<div class="fs-9 text-body-secondary fw-semibold mb-0"> <div class="fs-9 text-body-secondary fw-semibold mb-0">
{% if estimate.status == 'draft' %} {% 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 ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-semibold"> <td class="align-middle text-start fw-semibold">
{% for service in data.additional_services.services %} {% 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> <br>
{% endfor %} {% endfor %}
{% if estimate.is_draft %} {% if estimate.is_draft %}

View File

@ -1,11 +1,10 @@
{% load i18n static custom_filters num2words_tags %} {% load i18n static custom_filters num2words_tags %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ar"> <html lang="ar" dir="rtl">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Invoice</title> <title>Quotation</title>
<!-- CSS -->
<link href="{% static 'css/theme.min.css' %}" <link href="{% static 'css/theme.min.css' %}"
type="text/css" type="text/css"
rel="stylesheet" rel="stylesheet"
@ -15,70 +14,80 @@
rel="stylesheet" rel="stylesheet"
id="user-style-default"> id="user-style-default">
<link href="{% static 'css/custom.css' %}" type="text/css" rel="stylesheet"> <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" <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
rel="stylesheet"> rel="stylesheet">
<!-- Custom CSS -->
<style> <style>
body { body {
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
margin: 0; margin: 0;
padding: 10mm; padding: 0;
background-color: #f8f9fa; background-color: #f8f9fa;
} }
.invoice-container { .invoice-container {
width: 210mm; width: 210mm;
min-height: 297mm; min-height: 297mm;
padding: 10mm; padding: 10mm;
margin: auto; margin: 10mm auto;
background: white; background: white;
border-radius: 5px; border-radius: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); 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 { .invoice-header {
text-align: center; text-align: center;
border-bottom: 2px solid #dee2e6; border-bottom: 2px solid #dee2e6;
padding-bottom: 10px; padding-bottom: 10px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.qr-code { .qr-code {
text-align: center; text-align: center;
margin-top: 10px; margin-top: 10px;
} }
.qr-code img { .qr-code img {
width: 3cm; width: 3cm;
height: 3cm; height: 3cm;
border-radius: 0.3333333333rem; border-radius: 0.3333333333rem;
} }
.invoice-details, .invoice-table { .invoice-details, .invoice-table {
font-size: 12px; font-size: 14px;
} }
.invoice-table th { .invoice-table th {
background-color: #f8f9fa; background-color: #f8f9fa;
font-weight: 600; font-weight: 600;
} }
.invoice-total { .invoice-total {
text-align: right; text-align: right;
font-size: 13px; font-size: 16px;
font-weight: 600; font-weight: 600;
margin-top: 10px; margin-top: 10px;
} }
.footer-note { .footer-note {
position: absolute; margin-top: auto;
bottom: 10mm; padding-top: 10mm;
left: 10mm; font-size: 13px;
right: 10mm;
font-size: 10px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
border-top: 2px solid #dee2e6;
} }
.logo-img img { .logo-img img {
width: 10mm; width: 10mm;
height: 10mm; height: 10mm;
} }
</style> </style>
</head> </head>
<body> <body>
@ -92,267 +101,262 @@
</div> </div>
<div class="col-8"></div> <div class="col-8"></div>
</div> </div>
<div class="invoice-container" id="invoice-content">
<div class="invoice-header"> <div class="invoice-container" id="estimate-content">
<h5 class="fs-5"> <div class="invoice-content">
<span>Quotation</span>&nbsp;/&nbsp;<span>عرض سعر</span> <div class="invoice-header">
</h5> <h5 class="fs-5">
</div> <span>Quotation</span>&nbsp;/&nbsp;<span>عرض سعر</span>
<div class="invoice-details p-1"> </h5>
<table class="table table-sm table-responsive border-gray-50"> </div>
<tr> <div class="invoice-details p-1">
<td></td> <div class="d-flex justify-content-end align-items-end">
<td></td> <div class="dealer-logo ">
<td> {% if request.dealer.logo %}
<div class="qr-code"> <img class="rounded-soft" style="max-width:200px; max-height:200px;"
{% if dealer.logo %} src="{{ request.dealer.logo.url|default:'' }}"
<img class="rounded-soft" alt="Dealer Logo" />
src="{{ dealer.logo.url|default:'' }}" {% endif %}
alt="Dealer Logo" /> </div>
{% endif %} </div>
</div>
</td> <table class="table table-sm table-responsive border-gray-50">
</tr>
<tr>
<td class="ps-1">
<strong>Customer Name</strong>
</td>
<td class="text-center">
{{ dealer.arabic_name }}
<br>
{{ dealer.name }}
</td>
<td class="text-end">
<strong>{{ dealer.arabic_name }}</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Address</strong>
</td>
<td class="text-center">{{ dealer.address }}</td>
<td class="text-end">
<strong>العنوان</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Phone</strong>
</td>
<td class="text-center">{{ dealer.phone_number }}</td>
<td class="text-end">
<strong>جوال</strong>
</td>
</tr>
<tr>
<td>
<strong>VAT Number</strong>
</td>
<td>{{ dealer.vrn }}</td>
<td class="text-end">
<strong>الرقم الضريبي</strong>
</td>
</tr>
</table>
<table class="table table-sm table-bordered border-gray-50">
<tr>
<td class="ps-1">
<strong>Quotation&nbsp;Number</strong>
</td>
<td class="text-center">{{ estimate.estimate_number }}</td>
<td class="text-end p-1">
<strong>رقم عرض السعر</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Date</strong>
</td>
<td class="text-center">{{ estimate.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>
</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>
</td>
<td class="text-center">{{ estimate.customer.email |default:"N/A" }}</td>
<td class="text-end p-1">
<strong>البريد الإلكتروني</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Terms</strong>
</td>
<td class="text-center">{{ estimate.get_terms_display }}</td>
<td class="text-end p-1">
<strong>طريقة&nbsp;الدفع</strong>
</td>
</tr>
</table>
</div>
<div class="d-flex justify-content-between">
<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">
<thead>
<tr> <tr>
<th class="text-wrap text-center align-content-center"> <td class="ps-1">
<span class="fs-10">Make</span> / <span class="fs-10">الصانع</span> <strong>Dealership Name</strong>
</th> </td>
<th class="text-wrap text-center align-content-center"> <td class="text-center">
<span class="fs-10">Model</span> / <span class="fs-10">الموديل</span> {{ request.dealer.name }}
</th> </td>
<th class="text-wrap text-center align-content-center"> <td class="text-end">
<span class="fs-10">Trim</span> / <span class="fs-10">الفئة</span> <strong>اسم الوكالة</strong>
</th> </td>
<th class="text-wrap text-center align-content-center">
<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>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Quantity</span> / <span class="fs-10">الكمية</span>
</th>
<th class="text-wrap text-center align-content-center">
<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>
</th>
</tr> </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> <tr>
<td class="ps-1 fs-10 align-content-center" colspan="5"></td> <td class="ps-1">
<td class="text-center fs-10 align-content-center">{{ data.quantity|floatformat:-1 }}</td> <strong>Dealership Address</strong>
<td class="text-center fs-10 align-content-center">{{ data.total_price_before_discount|floatformat:2 }}</td> </td>
<td class="text-center fs-10 align-content-center">{{ data.grand_total|floatformat:2 }}</td> <td class="text-center">{{ request.dealer.address }}</td>
<td class="text-end">
<strong>العنوان</strong>
</td>
</tr> </tr>
</tbody> <tr>
</table> <td class="ps-1">
</div> <strong>Phone</strong>
<div class="d-flex justify-content-between"> </td>
<span class="fs-9 fw-thin">Additional&nbsp;Services</span> <td class="text-center">{{ request.dealer.phone_number }}</td>
<span class="fs-9 fw-thin">الخدمات&nbsp;الإضافية</span> <td class="text-end">
</div> <strong>جوال</strong>
{% if data.additionals %} </td>
</tr>
<tr>
<td>
<strong>VAT Number</strong>
</td>
<td class="text-center">{{ request.dealer.vrn }}</td>
<td class="text-end">
<strong>الرقم الضريبي</strong>
</td>
</tr>
</table>
<table class="table table-sm table-bordered border-gray-50 ">
<tr>
<td class="ps-1">
<strong>Quotation&nbsp;Number</strong>
</td>
<td class="text-center">{{ estimate.estimate_number }}</td>
<td class="text-end p-1">
<strong>رقم عرض السعر</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Date</strong>
</td>
<td class="text-center">{{ estimate.date_approved| date:"Y/m/d" }}</td>
<td class="text-end p-1">
<strong>التاريخ</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<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>Email</strong>
</td>
<td class="text-center">{{ estimate.customer.email |default:"N/A" }}</td>
<td class="text-end p-1">
<strong>البريد الإلكتروني</strong>
</td>
</tr>
<tr>
<td class="ps-1">
<strong>Terms</strong>
</td>
<td class="text-center">{{ estimate.get_terms_display }}</td>
<td class="text-end p-1">
<strong>طريقة&nbsp;الدفع</strong>
</td>
</tr>
</table>
</div>
<div class="d-flex justify-content-between">
<span class="fs-9 fw-thin">Car Details</span>
<span class="fs-9 fw-thin">تفاصيل السيارة</span>
</div>
<div class="invoice-table p-1"> <div class="invoice-table p-1">
<table class="table table-sm table-bordered m-1"> <table class="table table-sm table-bordered m-1">
<thead> <thead>
<tr> <tr>
<th class="text-center fs-10 align-content-center">Type&nbsp;/&nbsp;النوع</th> <th class="text-wrap text-center align-content-center">
<th class="text-center fs-10 align-content-center">Price&nbsp;/&nbsp;القيمة</th> <span class="fs-10">Make</span> / <span class="fs-10">الصانع</span>
<th class="text-center fs-10 align-content-center"> </th>
<span class="fs-10">Including VAT</span> / <span class="fs-10">شامل الضريبة</span> <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>
<th class="text-wrap text-center align-content-center">
<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>
</th>
<th class="text-wrap text-center align-content-center">
<span class="fs-10">Quantity</span> / <span class="fs-10">الكمية</span>
</th>
<th class="text-wrap text-center align-content-center">
<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">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> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for item in data.additionals %} <tr>
<tr> <td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_make.name }}</td>
<td class="ps-1 text-start fs-10 align-content-center">{{ item.name }}</td> <td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_model.name }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ item.price|floatformat }}</td> <td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_serie.name }}</td>
<td class="ps-1 text-center fs-10 align-content-center">{{ item.price_|floatformat }}</td> <td class="ps-1 fs-10 align-content-center">{{ data.car.id_car_trim.name }}</td>
</tr> <td class="text-center fs-10 align-content-center">{{ data.car.year }}</td>
{% endfor %} <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> </tbody>
</table> </table>
</div> </div>
{% endif %} <div class="d-flex justify-content-between">
<div class="invoice-total d-flex justify-content-end"> <span class="fs-9 fw-thin">Additional&nbsp;Services</span>
<div class="table-responsive"> <span class="fs-9 fw-thin">الخدمات&nbsp;الإضافية</span>
<table class="table table-sm table-responsive"> </div>
<tr> {% if data.additional_services %}
<td class="text-start ps-1"> <div class="invoice-table p-1">
<strong class="fs-9">VAT</strong> <table class="table table-sm table-bordered m-1">
</td> <thead>
<td class="text-center"> <tr>
<span class="fs-9">{{ data.total_vat_amount|floatformat }} <span class="icon-saudi_riyal"></span></span> <th class="text-center fs-10 align-content-center">Type&nbsp;/&nbsp;النوع</th>
</td> <th class="text-center fs-10 align-content-center">Price&nbsp;/&nbsp;القيمة</th>
<td class="text-end"> <th class="text-center fs-10 align-content-center">VAT&nbsp;/&nbsp;ضريبة الخدمة</th>
<strong class="fs-9">ضريبة&nbsp;القيمة&nbsp;المضافة</strong> <th class="text-center fs-10 align-content-center">
</td> <span class="fs-10">Total</span> / <span class="fs-10">الإجمالي</span>
</tr> </th>
<tr> </tr>
<td class="text-start ps-1"> </thead>
<strong class="fs-9">Total</strong> <tbody>
</td> {% for service in data.additional_services.services %}
<td class="text-center"> <tr>
<span class="fs-9">{{ data.grand_total|floatformat }}&nbsp;<span class="icon-saudi_riyal"></span></span> <td class="ps-1 text-start fs-10 align-content-center">{{ service.0.name }}</td>
</td> <td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price|floatformat }}</td>
<td class="text-end"> <td class="ps-1 text-center fs-10 align-content-center">{{ service.1|floatformat }}</td>
<strong class="fs-9">الإجمالي</strong> <td class="ps-1 text-center fs-10 align-content-center">{{ service.0.price_|floatformat }}</td>
</td> </tr>
</tr> {% endfor %}
<tr> </tbody>
<td class="text-end" colspan="3"> </table>
<span class="fs-9 fw-bold">كتابةً:&nbsp;</span><span class="fs-9">{{ data.grand_total|num_to_words }}&nbsp;<span class="icon-saudi_riyal"></span></span> </div>
</td> {% endif %}
</tr> <div class="invoice-total d-flex justify-content-end">
</table> <div class="table-responsive">
<table class="table table-sm table-responsive">
<tr>
<td class="text-start ps-1">
<strong class="fs-9">Total VAT</strong>
</td>
<td class="text-center">
<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;القيمة&nbsp;المضافة</strong>
</td>
</tr>
<tr>
<td class="text-start ps-1">
<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>
</td>
</tr>
<tr>
<td class="text-end" colspan="3">
<span class="fs-9 fw-bold">كتابةً:&nbsp;</span><span class="fs-9">{{ data.grand_total|num_to_words }}&nbsp;<span class="icon-saudi_riyal"></span></span>
</td>
</tr>
</table>
</div>
</div> </div>
</div> </div>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="footer-note"> <div class="footer-note">
<div class="logo-img text-center"> <div class="logo-img text-center">
<img src="{% static 'images/logos/logo-d-pdf.png' %}" alt="Logo" /> <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> <span>Haikal</span>&nbsp;|&nbsp;<span>هيكل</span>
</p> </p>
</div> </div>
<p class="fs-11"> <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>
href="https://tenhal.sa" <a class="text-decoration-none fs-9"
style="color: #112e40"><span>TENHAL</span>&nbsp;|&nbsp;<span>تنحل</span></a> href="https://tenhal.sa"
style="color: #112e40;"><span>TENHAL</span>&nbsp;|&nbsp;<span>تنحل</span></a>
</p> </p>
</div> </div>
</div> </div>
<script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script> <script src="{% static 'vendors/bootstrap/bootstrap.min.js' %}"></script>
<script src="{% static 'js/html2pdf.bundle.min.js' %}"></script> <script src="{% static 'js/html2pdf.bundle.min.js' %}"></script>
<script> <script>
document.getElementById('download-pdf').addEventListener('click', function () { document.getElementById('download-pdf').addEventListener('click', function () {
html2pdf().from(document.getElementById('invoice-content')).set({ html2pdf().from(document.getElementById('estimate-content')).set({
margin: 0, 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 }, image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 3 }, html2canvas: { scale: 3 },
jsPDF: { unit: 'mm', format: 'a3', orientation: 'portrait' } jsPDF: { unit: 'mm', format: 'a3', orientation: 'portrait' }
@ -360,4 +364,4 @@
}); });
</script> </script>
</body> </body>
</html> </html>

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 ps-4 fw-semibold text-body-highlight" colspan="7">{% trans "Additional Services" %}</td>
<td class="align-middle text-start fw-bold"> <td class="align-middle text-start fw-bold">
{% for service in data.additional_services.services %} {% 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> <br>
{% endfor %} {% endfor %}
</td> </td>

View File

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