From 543d8702f3e0f8442d510b1b75263959a45f57ae Mon Sep 17 00:00:00 2001
From: ismail
Date: Tue, 12 Aug 2025 12:02:21 +0300
Subject: [PATCH] update the car calculator class
---
inventory/admin.py | 2 +-
inventory/forms.py | 4 +-
inventory/models.py | 260 ++++++----
inventory/signals.py | 443 +++++++++---------
inventory/urls.py | 13 +-
inventory/utils.py | 415 +++++++++++-----
inventory/views.py | 270 ++++-------
templates/chart_of_accounts/coa_list.html | 38 ++
.../chart_of_accounts/includes/coa_card.html | 116 +++++
.../crm/opportunities/opportunity_detail.html | 4 +-
.../opportunities/opportunity_list copy.html | 4 +-
templates/header.html | 32 +-
templates/inventory/car_detail.html | 16 +-
templates/inventory/transfer_details.html | 4 +-
templates/inventory/transfer_preview.html | 6 +-
templates/ledger/reports/car_sale_report.html | 10 +-
.../sales/estimates/estimate_detail.html | 31 +-
.../estimates/payment_request_detail.html | 2 +-
templates/sales/invoices/invoice_detail.html | 28 +-
19 files changed, 1007 insertions(+), 691 deletions(-)
create mode 100644 templates/chart_of_accounts/coa_list.html
create mode 100644 templates/chart_of_accounts/includes/coa_card.html
diff --git a/inventory/admin.py b/inventory/admin.py
index 87c571a3..1bd2956f 100644
--- a/inventory/admin.py
+++ b/inventory/admin.py
@@ -38,7 +38,7 @@ admin.site.register(models.DealerSettings)
# admin.site.register(models.SaleQuotationCar)
admin.site.register(models.SaleOrder)
admin.site.register(models.CustomGroup)
-admin.site.register(models.CarFinance)
+# admin.site.register(models.CarFinance)
admin.site.register(models.CarColors)
admin.site.register(models.CarRegistration)
admin.site.register(models.CustomCard)
diff --git a/inventory/forms.py b/inventory/forms.py
index 4bdd23c6..b01426ea 100644
--- a/inventory/forms.py
+++ b/inventory/forms.py
@@ -32,7 +32,7 @@ from .models import (
Car,
VatRate,
CarTransfer,
- CarFinance,
+ # CarFinance,
CustomCard,
CarRegistration,
CarColors,
@@ -444,7 +444,7 @@ class CarFinanceForm(forms.ModelForm):
return cleaned_data
class Meta:
- model = CarFinance
+ model = Car
fields = ["cost_price","marked_price"]
diff --git a/inventory/models.py b/inventory/models.py
index 53dee7df..ab589f82 100644
--- a/inventory/models.py
+++ b/inventory/models.py
@@ -603,7 +603,6 @@ class AdditionalServices(models.Model, LocalizedNameMixin):
class Car(Base):
-
item_model = models.OneToOneField(
ItemModel,
models.DO_NOTHING,
@@ -668,6 +667,32 @@ class Car(Base):
default=CarStockTypeChoices.NEW,
verbose_name=_("Stock Type"),
)
+ #
+ additional_services = models.ManyToManyField(
+ AdditionalServices, related_name="additionals", blank=True,null=True
+ )
+ cost_price = models.DecimalField(
+ max_digits=14, decimal_places=2, verbose_name=_("Cost Price"),default=Decimal("0.00")
+ )
+ selling_price = models.DecimalField(
+ max_digits=14,
+ decimal_places=2,
+ verbose_name=_("Selling Price"),
+ default=Decimal("0.00"),
+ )
+ marked_price = models.DecimalField(
+ max_digits=14,
+ decimal_places=2,
+ verbose_name=_("Marked Price"),
+ default=Decimal("0.00"),
+ )
+ discount_amount = models.DecimalField(
+ max_digits=14,
+ decimal_places=2,
+ verbose_name=_("Discount Amount"),
+ default=Decimal("0.00"),
+ )
+ #
remarks = models.TextField(blank=True, null=True, verbose_name=_("Remarks"))
mileage = models.IntegerField(blank=True, null=True, verbose_name=_("Mileage"))
receiving_date = models.DateTimeField(verbose_name=_("Receiving Date"))
@@ -734,20 +759,16 @@ class Car(Base):
@property
def logo(self):
return getattr(self.id_car_make, "logo", "")
- @property
- def additional_services(self):
- return self.finances.additional_services.all()
- @property
- def total_additional_services(self):
- return sum([service.price_ for service in self.additional_services])
+ # @property
+ # def additional_services(self):
+ # return self.additional_services.all()
@property
def ready(self):
try:
return all(
[
self.colors,
- self.finances,
- self.finances.marked_price > 0,
+ self.marked_price > 0,
]
)
except Exception:
@@ -838,10 +859,51 @@ class Car(Base):
car=self, exterior=exterior, interior=interior
)
self.save()
-
@property
def logo(self):
return self.id_car_make.logo.url if self.id_car_make.logo else None
+ #
+ @property
+ def get_additional_services_amount(self):
+ return sum([Decimal(x.price_) for x in self.additional_services.all()])
+
+ def get_additional_services(self):
+ return {"services": [x for x in self.additional_services.all()],"total":self.get_additional_services_amount}
+
+ @property
+ def vat_amount(self):
+ vat = VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
+ return Decimal(self.marked_price) * (vat.rate / 100)
+
+ @property
+ def total_vat(self):
+ return Decimal(self.marked_price) + Decimal(self.vat_amount)
+ # def get_discount_amount(self,estimate,user):
+ # try:
+ # instance = models.ExtraInfo.objects.get(
+ # dealer=self.dealer,
+ # content_object=estimate,
+ # related_object=user
+ # )
+ # if instance:
+ # return instance.data.get("discount",0)
+ # return 0
+ # except Exception:
+ # print("Error getting discount amount")
+ # return 0
+ # @property
+ # def total_discount(self):
+ # if self.discount_amount > 0:
+ # return self.marked_price - self.discount_amount
+ # return self.marked_price
+
+ # @property
+ # def total_vat(self):
+ # return round(self.total_discount + self.vat_amount + self.total_additionals, 2)
+
+
+
+
class CarTransfer(models.Model):
@@ -880,7 +942,7 @@ class CarTransfer(models.Model):
@property
def total_price(self):
- return self.quantity * self.car.finances.total_vat
+ return self.quantity * self.car.total_vat # TODO : check later
class Meta:
verbose_name = _("Car Transfer Log")
@@ -924,105 +986,105 @@ class CarReservation(models.Model):
# Car Finance Model
-class CarFinance(models.Model):
- additional_services = models.ManyToManyField(
- AdditionalServices, related_name="additional_finances", blank=True
- )
- car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name="finances")
- cost_price = models.DecimalField(
- max_digits=14, decimal_places=2, verbose_name=_("Cost Price")
- )
- selling_price = models.DecimalField(
- max_digits=14,
- decimal_places=2,
- verbose_name=_("Selling Price"),
- default=Decimal("0.00"),
- )
- marked_price = models.DecimalField(
- max_digits=14,
- decimal_places=2,
- verbose_name=_("Marked Price"),
- default=Decimal("0.00"),
- )
- discount_amount = models.DecimalField(
- max_digits=14,
- decimal_places=2,
- verbose_name=_("Discount Amount"),
- default=Decimal("0.00"),
- )
- # is_sold = models.BooleanField(default=False)
+# class CarFinance(models.Model):
+# additional_services = models.ManyToManyField(
+# AdditionalServices, related_name="additional_finances", blank=True
+# )
+# car = models.OneToOneField(Car, on_delete=models.CASCADE, related_name="finances")
+# cost_price = models.DecimalField(
+# max_digits=14, decimal_places=2, verbose_name=_("Cost Price")
+# )
+# selling_price = models.DecimalField(
+# max_digits=14,
+# decimal_places=2,
+# verbose_name=_("Selling Price"),
+# default=Decimal("0.00"),
+# )
+# marked_price = models.DecimalField(
+# max_digits=14,
+# decimal_places=2,
+# verbose_name=_("Marked Price"),
+# default=Decimal("0.00"),
+# )
+# discount_amount = models.DecimalField(
+# max_digits=14,
+# decimal_places=2,
+# verbose_name=_("Discount Amount"),
+# default=Decimal("0.00"),
+# )
+# # is_sold = models.BooleanField(default=False)
- @property
- def total(self):
- return self.marked_price
+# @property
+# def total(self):
+# return self.marked_price
- @property
- def total_additionals_no_vat(self):
- return sum(x.price for x in self.additional_services.all())
+# @property
+# def total_additionals_no_vat(self):
+# return sum(x.price for x in self.additional_services.all())
- @property
- def total_additionals(self):
- return sum(x.price_ for x in self.additional_services.all())
+# @property
+# def total_additionals(self):
+# return sum(x.price_ for x in self.additional_services.all())
- @property
- def total_discount(self):
- if self.discount_amount > 0:
- return self.marked_price - self.discount_amount
- return self.marked_price
+# @property
+# def total_discount(self):
+# if self.discount_amount > 0:
+# return self.marked_price - self.discount_amount
+# return self.marked_price
- @property
- def total_vat(self):
- return round(self.total_discount + self.vat_amount + self.total_additionals, 2)
+# @property
+# def total_vat(self):
+# return round(self.total_discount + self.vat_amount + self.total_additionals, 2)
- @property
- def vat_amount(self):
- vat = VatRate.objects.filter(dealer=self.car.dealer, is_active=True).first()
- if vat:
- return (self.total_discount * Decimal(vat.rate)).quantize(Decimal("0.01"))
- return Decimal("0.00")
+# @property
+# def vat_amount(self):
+# vat = VatRate.objects.filter(dealer=self.car.dealer, is_active=True).first()
+# if vat:
+# return (self.total_discount * Decimal(vat.rate)).quantize(Decimal("0.01"))
+# return Decimal("0.00")
- @property
- def revenue(self):
- return self.marked_price - self.cost_price
+# @property
+# def revenue(self):
+# return self.marked_price - self.cost_price
- def to_dict(self):
- return {
- "cost_price": str(self.cost_price),
- "selling_price": str(self.selling_price),
- "marked_price": str(self.marked_price),
- "discount_amount": str(self.discount_amount),
- "total": str(self.total),
- "total_discount": str(self.total_discount),
- "total_vat": str(self.total_vat),
- "vat_amount": str(self.vat_amount),
- }
+# def to_dict(self):
+# return {
+# "cost_price": str(self.cost_price),
+# "selling_price": str(self.selling_price),
+# "marked_price": str(self.marked_price),
+# "discount_amount": str(self.discount_amount),
+# "total": str(self.total),
+# "total_discount": str(self.total_discount),
+# "total_vat": str(self.total_vat),
+# "vat_amount": str(self.vat_amount),
+# }
- def __str__(self):
- return f"Car: {self.car}, Marked Price: {self.marked_price}"
+# def __str__(self):
+# return f"Car: {self.car}, Marked Price: {self.marked_price}"
- # def save(self, *args, **kwargs):
- # self.full_clean()
- # try:
- # price_after_discount = self.selling_price - self.discount_amount
- # self.profit_margin = price_after_discount - self.cost_price
- # self.vat_amount = settings.VAT_RATE
- # except InvalidOperation as e:
- # raise ValidationError(_("Invalid decimal operation: %s") % str(e))
- # super().save(*args, **kwargs)
+# # def save(self, *args, **kwargs):
+# # self.full_clean()
+# # try:
+# # price_after_discount = self.selling_price - self.discount_amount
+# # self.profit_margin = price_after_discount - self.cost_price
+# # self.vat_amount = settings.VAT_RATE
+# # except InvalidOperation as e:
+# # raise ValidationError(_("Invalid decimal operation: %s") % str(e))
+# # super().save(*args, **kwargs)
- class Meta:
- verbose_name = _("Car Financial Details")
- verbose_name_plural = _("Car Financial Details")
- indexes = [
- models.Index(fields=["car"], name="car_finance_car_idx"),
- models.Index(fields=["cost_price"], name="car_finance_cost_price_idx"),
- models.Index(
- fields=["selling_price"], name="car_finance_selling_price_idx"
- ),
- models.Index(fields=["marked_price"], name="car_finance_marked_price_idx"),
- models.Index(fields=["discount_amount"], name="car_finance_discount_idx"),
- ]
+# class Meta:
+# verbose_name = _("Car Financial Details")
+# verbose_name_plural = _("Car Financial Details")
+# indexes = [
+# models.Index(fields=["car"], name="car_finance_car_idx"),
+# models.Index(fields=["cost_price"], name="car_finance_cost_price_idx"),
+# models.Index(
+# fields=["selling_price"], name="car_finance_selling_price_idx"
+# ),
+# models.Index(fields=["marked_price"], name="car_finance_marked_price_idx"),
+# models.Index(fields=["discount_amount"], name="car_finance_discount_idx"),
+# ]
class ExteriorColors(models.Model, LocalizedNameMixin):
@@ -2875,7 +2937,7 @@ class SaleOrder(models.Model):
@property
def price(self):
- return self.car.finances.marked_price
+ return self.car.marked_price
@property
def items(self):
diff --git a/inventory/signals.py b/inventory/signals.py
index 21947d35..aa3dbf5e 100644
--- a/inventory/signals.py
+++ b/inventory/signals.py
@@ -270,6 +270,9 @@ def create_item_model(sender, instance, created, **kwargs):
)
instance.item_model = inventory
inventory.save()
+ else:
+ instance.item_model.default_amount = instance.marked_price
+
# inventory = entity.create_item_inventory(
# name=instance.vin,
# uom_model=uom,
@@ -284,108 +287,108 @@ def create_item_model(sender, instance, created, **kwargs):
# # update price - CarFinance
-@receiver(post_save, sender=models.CarFinance)
-def update_item_model_cost(sender, instance, created, **kwargs):
- """
- Signal handler for updating an inventory item's cost and additional information
- when a CarFinance instance is saved. This function updates the corresponding
- inventory item of the car dealer's entity associated with the car's VIN by
- modifying its default amount and updating additional data fields.
+# @receiver(post_save, sender=models.CarFinance)
+# def update_item_model_cost(sender, instance, created, **kwargs):
+# """
+# Signal handler for updating an inventory item's cost and additional information
+# when a CarFinance instance is saved. This function updates the corresponding
+# inventory item of the car dealer's entity associated with the car's VIN by
+# modifying its default amount and updating additional data fields.
- :param sender: The model class that triggered the signal.
- :param instance: The instance of the CarFinance that was saved.
- :param created: A boolean indicating whether the model instance was newly created.
- :param kwargs: Additional keyword arguments passed during the signal invocation.
- :return: None
- """
- # if created and not instance.is_sold:
- # if created:
- # entity = instance.car.dealer.entity
- # coa = entity.get_default_coa()
- # inventory_account = (
- # entity.get_all_accounts()
- # .filter(name=f"Inventory:{instance.car.id_car_make.name}")
- # .first()
- # )
- # if not inventory_account:
- # inventory_account = create_make_accounts(
- # entity,
- # coa,
- # [instance.car.id_car_make],
- # "Inventory",
- # roles.ASSET_CA_INVENTORY,
- # "debit",
- # )
+# :param sender: The model class that triggered the signal.
+# :param instance: The instance of the CarFinance that was saved.
+# :param created: A boolean indicating whether the model instance was newly created.
+# :param kwargs: Additional keyword arguments passed during the signal invocation.
+# :return: None
+# """
+# # if created and not instance.is_sold:
+# # if created:
+# # entity = instance.car.dealer.entity
+# # coa = entity.get_default_coa()
+# # inventory_account = (
+# # entity.get_all_accounts()
+# # .filter(name=f"Inventory:{instance.car.id_car_make.name}")
+# # .first()
+# # )
+# # if not inventory_account:
+# # inventory_account = create_make_accounts(
+# # entity,
+# # coa,
+# # [instance.car.id_car_make],
+# # "Inventory",
+# # roles.ASSET_CA_INVENTORY,
+# # "debit",
+# # )
- # cogs = (
- # entity.get_all_accounts()
- # .filter(name=f"Cogs:{instance.car.id_car_make.name}")
- # .first()
- # )
- # if not cogs:
- # cogs = create_make_accounts(
- # entity, coa, [instance.car.id_car_make], "Cogs", roles.COGS, "debit"
- # )
- # revenue = (
- # entity.get_all_accounts()
- # .filter(name=f"Revenue:{instance.car.id_car_make.name}")
- # .first()
- # )
- # if not revenue:
- # revenue = create_make_accounts(
- # entity,
- # coa,
- # [instance.car.id_car_make],
- # "Revenue",
- # roles.ASSET_CA_RECEIVABLES,
- # "credit",
- # )
+# # cogs = (
+# # entity.get_all_accounts()
+# # .filter(name=f"Cogs:{instance.car.id_car_make.name}")
+# # .first()
+# # )
+# # if not cogs:
+# # cogs = create_make_accounts(
+# # entity, coa, [instance.car.id_car_make], "Cogs", roles.COGS, "debit"
+# # )
+# # revenue = (
+# # entity.get_all_accounts()
+# # .filter(name=f"Revenue:{instance.car.id_car_make.name}")
+# # .first()
+# # )
+# # if not revenue:
+# # revenue = create_make_accounts(
+# # entity,
+# # coa,
+# # [instance.car.id_car_make],
+# # "Revenue",
+# # roles.ASSET_CA_RECEIVABLES,
+# # "credit",
+# # )
- # cash_account = (
- # # entity.get_all_accounts()
- # # .filter(name="Cash", role=roles.ASSET_CA_CASH)
- # # .first()
- # entity.get_all_accounts()
- # .filter(role=roles.ASSET_CA_CASH, role_default=True)
- # .first()
- # )
+# # cash_account = (
+# # # entity.get_all_accounts()
+# # # .filter(name="Cash", role=roles.ASSET_CA_CASH)
+# # # .first()
+# # entity.get_all_accounts()
+# # .filter(role=roles.ASSET_CA_CASH, role_default=True)
+# # .first()
+# # )
- # ledger = LedgerModel.objects.create(
- # entity=entity, name=f"Inventory Purchase - {instance.car}"
- # )
- # je = JournalEntryModel.objects.create(
- # ledger=ledger,
- # description=f"Acquired {instance.car} for inventory",
- # )
- # TransactionModel.objects.create(
- # journal_entry=je,
- # account=inventory_account,
- # amount=Decimal(instance.cost_price),
- # tx_type="debit",
- # description="",
- # )
+# # ledger = LedgerModel.objects.create(
+# # entity=entity, name=f"Inventory Purchase - {instance.car}"
+# # )
+# # je = JournalEntryModel.objects.create(
+# # ledger=ledger,
+# # description=f"Acquired {instance.car} for inventory",
+# # )
+# # TransactionModel.objects.create(
+# # journal_entry=je,
+# # account=inventory_account,
+# # amount=Decimal(instance.cost_price),
+# # tx_type="debit",
+# # description="",
+# # )
- # TransactionModel.objects.create(
- # journal_entry=je,
- # account=cash_account,
- # amount=Decimal(instance.cost_price),
- # tx_type="credit",
- # description="",
- # )
+# # TransactionModel.objects.create(
+# # journal_entry=je,
+# # account=cash_account,
+# # amount=Decimal(instance.cost_price),
+# # tx_type="credit",
+# # description="",
+# # )
- instance.car.item_model.default_amount = instance.marked_price
- # if not isinstance(instance.car.item_model.additional_info, dict):
- # instance.car.item_model.additional_info = {}
- # instance.car.item_model.additional_info.update({"car_finance": instance.to_dict()})
- # instance.car.item_model.additional_info.update(
- # {
- # "additional_services": [
- # service.to_dict() for service in instance.additional_services.all()
- # ]
- # }
- # )
- instance.car.item_model.save()
- print(f"Inventory item updated with CarFinance data for Car: {instance.car}")
+# instance.car.item_model.default_amount = instance.marked_price
+# # if not isinstance(instance.car.item_model.additional_info, dict):
+# # instance.car.item_model.additional_info = {}
+# # instance.car.item_model.additional_info.update({"car_finance": instance.to_dict()})
+# # instance.car.item_model.additional_info.update(
+# # {
+# # "additional_services": [
+# # service.to_dict() for service in instance.additional_services.all()
+# # ]
+# # }
+# # )
+# instance.car.item_model.save()
+# print(f"Inventory item updated with CarFinance data for Car: {instance.car}")
# @receiver(pre_save, sender=models.SaleQuotation)
@@ -803,144 +806,144 @@ def create_dealer_settings(sender, instance, created, **kwargs):
# )
-def save_journal(car_finance, ledger, vendor):
- """
- Saves a journal entry pertaining to a car finance transaction for a specific ledger and vendor.
+# def save_journal(car_finance, ledger, vendor):
+# """
+# Saves a journal entry pertaining to a car finance transaction for a specific ledger and vendor.
- This function ensures that relevant accounts are updated to record financial transactions. It handles
- debiting of the inventory account and crediting of the vendor account to maintain accurate bookkeeping.
- Additionally, it creates vendor accounts dynamically if required and ties the created journal entry to
- the ledger passed as a parameter. All transactions adhere to the ledger's entity-specific Chart of
- Accounts (COA) configuration.
+# This function ensures that relevant accounts are updated to record financial transactions. It handles
+# debiting of the inventory account and crediting of the vendor account to maintain accurate bookkeeping.
+# Additionally, it creates vendor accounts dynamically if required and ties the created journal entry to
+# the ledger passed as a parameter. All transactions adhere to the ledger's entity-specific Chart of
+# Accounts (COA) configuration.
- :param car_finance: Instance of the car finance object containing details about the financed car
- and its associated costs.
- :type car_finance: `CarFinance` object
- :param ledger: Ledger instance to which the journal entry is tied. This ledger must provide
- entity-specific details, including its COA and related accounts.
- :type ledger: `Ledger` object
- :param vendor: Vendor instance representing the supplier or vendor related to the car finance
- transaction. This vendor is used to derive or create the vendor account in COA.
- :type vendor: `Vendor` object
+# :param car_finance: Instance of the car finance object containing details about the financed car
+# and its associated costs.
+# :type car_finance: `CarFinance` object
+# :param ledger: Ledger instance to which the journal entry is tied. This ledger must provide
+# entity-specific details, including its COA and related accounts.
+# :type ledger: `Ledger` object
+# :param vendor: Vendor instance representing the supplier or vendor related to the car finance
+# transaction. This vendor is used to derive or create the vendor account in COA.
+# :type vendor: `Vendor` object
- :return: None
- """
- entity = ledger.entity
- coa = entity.get_default_coa()
- journal = JournalEntryModel.objects.create(
- posted=False,
- description=f"Finances of Car:{car_finance.car.vin} for Vendor:{car_finance.car.vendor.name}",
- ledger=ledger,
- locked=False,
- origin="Payment",
- )
- ledger.additional_info["je_number"] = journal.je_number
- ledger.save()
+# :return: None
+# """
+# entity = ledger.entity
+# coa = entity.get_default_coa()
+# journal = JournalEntryModel.objects.create(
+# posted=False,
+# description=f"Finances of Car:{car_finance.car.vin} for Vendor:{car_finance.car.vendor.name}",
+# ledger=ledger,
+# locked=False,
+# origin="Payment",
+# )
+# ledger.additional_info["je_number"] = journal.je_number
+# ledger.save()
- inventory_account = (
- entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_INVENTORY).first()
- )
- vendor_account = entity.get_default_coa_accounts().filter(name=vendor.name).first()
+# inventory_account = (
+# entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_INVENTORY).first()
+# )
+# vendor_account = entity.get_default_coa_accounts().filter(name=vendor.name).first()
- if not vendor_account:
- last_account = (
- entity.get_all_accounts()
- .filter(role=roles.LIABILITY_CL_ACC_PAYABLE)
- .order_by("-created")
- .first()
- )
- if len(last_account.code) == 4:
- code = f"{int(last_account.code)}{1:03d}"
- elif len(last_account.code) > 4:
- code = f"{int(last_account.code) + 1}"
+# if not vendor_account:
+# last_account = (
+# entity.get_all_accounts()
+# .filter(role=roles.LIABILITY_CL_ACC_PAYABLE)
+# .order_by("-created")
+# .first()
+# )
+# if len(last_account.code) == 4:
+# code = f"{int(last_account.code)}{1:03d}"
+# elif len(last_account.code) > 4:
+# code = f"{int(last_account.code) + 1}"
- vendor_account = entity.create_account(
- name=vendor.name,
- code=code,
- role=roles.LIABILITY_CL_ACC_PAYABLE,
- coa_model=coa,
- balance_type="credit",
- active=True,
- )
- additional_services_account = (
- entity.get_default_coa_accounts()
- .filter(name="Additional Services", role=roles.COGS)
- .first()
- )
+# vendor_account = entity.create_account(
+# name=vendor.name,
+# code=code,
+# role=roles.LIABILITY_CL_ACC_PAYABLE,
+# coa_model=coa,
+# balance_type="credit",
+# active=True,
+# )
+# additional_services_account = (
+# entity.get_default_coa_accounts()
+# .filter(name="Additional Services", role=roles.COGS)
+# .first()
+# )
- # Debit Inventory Account
- TransactionModel.objects.create(
- journal_entry=journal,
- account=inventory_account,
- amount=car_finance.cost_price,
- tx_type="debit",
- )
+# # Debit Inventory Account
+# TransactionModel.objects.create(
+# journal_entry=journal,
+# account=inventory_account,
+# amount=car_finance.cost_price,
+# tx_type="debit",
+# )
- # Credit Vendor Account
- TransactionModel.objects.create(
- journal_entry=journal,
- account=vendor_account,
- amount=car_finance.cost_price,
- tx_type="credit",
- )
+# # Credit Vendor Account
+# TransactionModel.objects.create(
+# journal_entry=journal,
+# account=vendor_account,
+# amount=car_finance.cost_price,
+# tx_type="credit",
+# )
-@receiver(post_save, sender=models.CarFinance)
-def update_finance_cost(sender, instance, created, **kwargs):
- """
- Signal to handle `post_save` functionality for the `CarFinance` model. This function
- creates or updates financial records related to a car's finance details in the ledger
- associated with the car's vendor and dealer. For newly created instances, a ledger is
- created or retrieved, and the `save_journal` function is executed to log the financial
- transactions.
+# @receiver(post_save, sender=models.CarFinance)
+# def update_finance_cost(sender, instance, created, **kwargs):
+# """
+# Signal to handle `post_save` functionality for the `CarFinance` model. This function
+# creates or updates financial records related to a car's finance details in the ledger
+# associated with the car's vendor and dealer. For newly created instances, a ledger is
+# created or retrieved, and the `save_journal` function is executed to log the financial
+# transactions.
- This function also has commented-out logic to handle updates for already created
- instances, including journal updates or adjustments to existing financial transactions.
+# This function also has commented-out logic to handle updates for already created
+# instances, including journal updates or adjustments to existing financial transactions.
- :param sender: Model class that triggered the signal
- :type sender: Model
- :param instance: Instance of the `CarFinance` model passed to the signal
- :type instance: CarFinance
- :param created: Boolean value indicating if the instance was created (`True`) or updated (`False`)
- :type created: bool
- :param kwargs: Arbitrary keyword arguments passed to the signal
- :type kwargs: dict
- :return: None
- """
- if created:
- entity = instance.car.dealer.entity
- vendor = instance.car.vendor
- vin = instance.car.vin if instance.car.vin else ""
- make = instance.car.id_car_make.name if instance.car.id_car_make else ""
- model = instance.car.id_car_model.name if instance.car.id_car_model else ""
- year = instance.car.year
- vendor_name = vendor.name if vendor else ""
+# :param sender: Model class that triggered the signal
+# :type sender: Model
+# :param instance: Instance of the `CarFinance` model passed to the signal
+# :type instance: CarFinance
+# :param created: Boolean value indicating if the instance was created (`True`) or updated (`False`)
+# :type created: bool
+# :param kwargs: Arbitrary keyword arguments passed to the signal
+# :type kwargs: dict
+# :return: None
+# """
+# if created:
+# entity = instance.car.dealer.entity
+# vendor = instance.car.vendor
+# vin = instance.car.vin if instance.car.vin else ""
+# make = instance.car.id_car_make.name if instance.car.id_car_make else ""
+# model = instance.car.id_car_model.name if instance.car.id_car_model else ""
+# year = instance.car.year
+# vendor_name = vendor.name if vendor else ""
- name = f"{vin}-{make}-{model}-{year}-{vendor_name}"
- ledger, _ = LedgerModel.objects.get_or_create(name=name, entity=entity)
- save_journal(instance, ledger, vendor)
+# name = f"{vin}-{make}-{model}-{year}-{vendor_name}"
+# ledger, _ = LedgerModel.objects.get_or_create(name=name, entity=entity)
+# save_journal(instance, ledger, vendor)
- # if not created:
- # if ledger.additional_info.get("je_number"):
- # journal = JournalEntryModel.objects.filter(je_number=ledger.additional_info.get("je_number")).first()
- # journal.description = f"Finances of Car:{instance.car.vin} for Vendor:{instance.car.vendor.vendor_name}"
- # journal.save()
- # debit = journal.get_transaction_queryset().filter(tx_type='debit').first()
- # credit = journal.get_transaction_queryset().filter(tx_type='credit').first()
- # if debit and credit:
- # if journal.is_locked():
- # journal.mark_as_unlocked()
- # journal.save()
- # debit.amount = instance.cost_price
- # credit.amount = instance.cost_price
- # debit.save()
- # credit.save()
- # else:
- # save_journal(instance,ledger,vendor,journal=journal)
- # else:
- # save_journal(instance,ledger,vendor)
- # else:
- # save_journal(instance,ledger,vendor)
+# # if not created:
+# # if ledger.additional_info.get("je_number"):
+# # journal = JournalEntryModel.objects.filter(je_number=ledger.additional_info.get("je_number")).first()
+# # journal.description = f"Finances of Car:{instance.car.vin} for Vendor:{instance.car.vendor.vendor_name}"
+# # journal.save()
+# # debit = journal.get_transaction_queryset().filter(tx_type='debit').first()
+# # credit = journal.get_transaction_queryset().filter(tx_type='credit').first()
+# # if debit and credit:
+# # if journal.is_locked():
+# # journal.mark_as_unlocked()
+# # journal.save()
+# # debit.amount = instance.cost_price
+# # credit.amount = instance.cost_price
+# # debit.save()
+# # credit.save()
+# # else:
+# # save_journal(instance,ledger,vendor,journal=journal)
+# # else:
+# # save_journal(instance,ledger,vendor)
+# # else:
+# # save_journal(instance,ledger,vendor)
@receiver(post_save, sender=PurchaseOrderModel)
diff --git a/inventory/urls.py b/inventory/urls.py
index cca5ab0a..4c788df5 100644
--- a/inventory/urls.py
+++ b/inventory/urls.py
@@ -345,13 +345,8 @@ urlpatterns = [
name="car_delete",
),
path(
- "/cars//finance/create/",
- views.CarFinanceCreateView.as_view(),
- name="car_finance_create",
- ),
- path(
- "/cars/finance//update/",
- views.CarFinanceUpdateView.as_view(),
+ "/cars//finance/update/",
+ views.CarFinanceUpdateView,
name="car_finance_update",
),
path(
@@ -1091,6 +1086,10 @@ urlpatterns = [
views.MonthlyIncomeStatementView.as_view(),
name="entity-ic-date",
),
+ # Chart of Accounts...
+ path('/chart-of-accounts//list/',
+ views.ChartOfAccountModelListView.as_view(),
+ name='coa-list'),
# CASH FLOW STATEMENTS...
# Entities...
path(
diff --git a/inventory/utils.py b/inventory/utils.py
index 164d93f7..e21b9274 100644
--- a/inventory/utils.py
+++ b/inventory/utils.py
@@ -779,7 +779,6 @@ class CarTransfer:
)
self.bill.additional_info = {}
self.bill.additional_info.update({"car_info": self.car.to_dict()})
- self.bill.additional_info.update({"car_finance": self.car.finances.to_dict()})
self.bill.mark_as_review()
self.bill.mark_as_approved(
@@ -791,14 +790,14 @@ class CarTransfer:
self.car.dealer = self.to_dealer
self.car.vendor = self.vendor
self.car.receiving_date = datetime.datetime.now()
- self.car.finances.additional_services.clear()
+ self.car.additional_services.clear()
if hasattr(self.car, "custom_cards"):
self.car.custom_cards.delete()
- self.car.finances.cost_price = self.transfer.total_price
- self.car.finances.marked_price = 0
- self.car.finances.discount_amount = 0
- self.car.finances.save()
+ self.car.cost_price = self.transfer.total_price
+ self.car.marked_price = 0
+ self.car.discount_amount = 0
+ self.car.save()
self.car.location.owner = self.to_dealer
self.car.location.showroom = self.to_dealer
self.car.location.description = ""
@@ -920,7 +919,7 @@ class CarTransfer:
# )
# bill.additional_info.update({"car_info": car.to_dict()})
-# bill.additional_info.update({"car_finance": car.finances.to_dict()})
+# bill.additional_info.update({"car_finance": car.to_dict()})
# bill.mark_as_review()
# bill.mark_as_approved(to_dealer.entity.slug, to_dealer.entity.admin)
@@ -929,14 +928,14 @@ class CarTransfer:
# car.dealer = to_dealer
# car.vendor = vendor
# car.receiving_date = datetime.datetime.now()
-# car.finances.additional_services.clear()
+# car.additional_services.clear()
# if hasattr(car, "custom_cards"):
# car.custom_cards.delete()
-# car.finances.cost_price = transfer.total_price
-# car.finances.selling_price = 0
-# car.finances.discount_amount = 0
-# car.finances.save()
+# car.cost_price = transfer.total_price
+# car.selling_price = 0
+# car.discount_amount = 0
+# car.save()
# car.location.owner = to_dealer
# car.location.showroom = to_dealer
# car.location.description = ""
@@ -980,6 +979,153 @@ def to_dict(obj):
return obj_dict
+class CarFinanceCalculator1:
+ """
+ Class responsible for calculating car financing details.
+
+ This class provides methods and attributes required for calculating various
+ aspects related to car financing, such as VAT calculation, pricing, discounts,
+ and additional services. It processes data about cars, computes totals (e.g.,
+ price, VAT, discounts), and aggregates the financial data for reporting or
+ further processing.
+
+ :ivar model: The data model passed to the calculator for retrieving transaction data.
+ :type model: Any
+ :ivar vat_rate: The current active VAT rate retrieved from the database.
+ :type vat_rate: Decimal
+ :ivar item_transactions: A collection of item transactions retrieved from the model.
+ :type item_transactions: list
+ :ivar additional_services: A list of additional services with details (e.g., name, price, taxable status).
+ :type additional_services: list
+ """
+
+ VAT_OBJ_NAME = "vat_rate"
+ CAR_FINANCE_KEY = "car_finance"
+ CAR_INFO_KEY = "car_info"
+ ADDITIONAL_SERVICES_KEY = "additional_services"
+
+ def __init__(self, model):
+ if isinstance(model, InvoiceModel):
+ self.dealer = models.Dealer.objects.get(entity=model.ce_model.entity)
+ self.extra_info = models.ExtraInfo.objects.get(
+ dealer=self.dealer,
+ content_type=ContentType.objects.get_for_model(model.ce_model),
+ object_id=model.ce_model.pk,
+ )
+ elif isinstance(model, EstimateModel):
+ self.dealer = models.Dealer.objects.get(entity=model.entity)
+ self.extra_info = models.ExtraInfo.objects.get(
+ dealer=self.dealer,
+ content_type=ContentType.objects.get_for_model(model),
+ object_id=model.pk,
+ )
+ self.model = model
+ self.vat_rate = self._get_vat_rate()
+ self.item_transactions = self._get_item_transactions()
+ # self.additional_services = self._get_additional_services()
+
+
+ def _get_vat_rate(self):
+ vat = models.VatRate.objects.filter(dealer=self.dealer,is_active=True).first()
+ if not vat:
+ raise ObjectDoesNotExist("No active VAT rate found")
+ return vat.rate
+
+ def _get_additional_services(self):
+ return [x for item in self.item_transactions
+ for x in item.item_model.car.additional_services
+ ]
+ def _get_item_transactions(self):
+ return self.model.get_itemtxs_data()[0].all()
+
+ def get_items(self):
+ return self._get_item_transactions()
+ @staticmethod
+ def _get_quantity(item):
+ return item.ce_quantity or item.quantity
+
+ # def _get_nested_value(self, item, *keys):
+ # current = item.item_model.additional_info
+ # for key in keys:
+ # current = current.get(key, {})
+ # return current
+
+ def _get_car_data(self, item):
+ quantity = self._get_quantity(item)
+ car = item.item_model.car
+ unit_price = Decimal(car.marked_price)
+ discount = self.extra_info.data.get("discount",0)
+ sell_price = unit_price - Decimal(discount)
+ return {
+ "item_number": item.item_model.item_number,
+ "vin": car.vin, #car_info.get("vin"),
+ "make": car.id_car_make ,#car_info.get("make"),
+ "model": car.id_car_model ,#car_info.get("model"),
+ "year": car.year ,# car_info.get("year"),
+ "logo": car.logo, # getattr(car.id_car_make, "logo", ""),
+ "trim": car.id_car_trim ,# car_info.get("trim"),
+ "mileage": car.mileage ,# car_info.get("mileage"),
+ "cost_price": car.cost_price,
+ "selling_price": car.selling_price,
+ "marked_price": car.marked_price,
+ "discount": car.discount_amount,
+ "quantity": quantity,
+ "unit_price": unit_price,
+ "sell_price": sell_price,
+ "total": unit_price,
+ "total_vat": sell_price * self.vat_rate,
+ "total_discount": discount,
+ "final_price": sell_price + (sell_price * self.vat_rate),
+ "total_additionals": car.total_additional_services,
+ "grand_total": sell_price + (sell_price * self.vat_rate) + car.total_additional_services,
+ "additional_services": car.additional_services,# self._get_nested_value(
+ #item, self.ADDITIONAL_SERVICES_KEY
+ #),
+ }
+
+ def calculate_totals(self):
+ total_price = sum(
+ Decimal(item.item_model.car.marked_price)
+ for item in self.item_transactions
+ )
+ total_additionals = sum(
+ Decimal(item.price_) for item in self._get_additional_services())
+
+ total_discount = self.extra_info.data.get("discount",0)
+ total_price_discounted = total_price
+ if total_discount:
+ total_price_discounted = total_price - Decimal(total_discount)
+ print(total_price_discounted)
+ total_vat_amount = total_price_discounted * self.vat_rate
+
+ return {
+ "total_price_discounted":total_price_discounted,
+ "total_price_before_discount":total_price,
+ "total_price": total_price_discounted,
+ "total_vat_amount": total_vat_amount,
+ "total_discount": Decimal(total_discount),
+ "total_additionals": total_additionals,
+ "grand_total":total_price_discounted + total_vat_amount + total_additionals,
+ }
+
+ def get_finance_data(self):
+ totals = self.calculate_totals()
+ return {
+ "cars": [self._get_car_data(item) for item in self.item_transactions],
+ "quantity": sum(
+ self._get_quantity(item) for item in self.item_transactions
+ ),
+ "total_price": round(totals["total_price"], 2),
+ "total_price_discounted": round(totals["total_price_discounted"], 2),
+ "total_price_before_discount": round(totals["total_price_before_discount"], 2),
+ "total_vat": round(totals["total_vat_amount"] + totals["total_price"], 2),
+ "total_vat_amount": round(totals["total_vat_amount"], 2),
+ "total_discount": round(totals["total_discount"], 2),
+ "total_additionals": round(totals["total_additionals"], 2),
+ "grand_total": round(totals["grand_total"], 2),
+ "additionals": self._get_additional_services(),
+ "vat": round(self.vat_rate, 2),
+ }
class CarFinanceCalculator:
"""
Class responsible for calculating car financing details.
@@ -1054,7 +1200,7 @@ class CarFinanceCalculator:
def _get_car_data(self, item):
quantity = self._get_quantity(item)
car = item.item_model.car
- unit_price = Decimal(car.finances.marked_price)
+ unit_price = Decimal(car.marked_price)
discount = self.extra_info.data.get("discount",0)
sell_price = unit_price - Decimal(discount)
return {
@@ -1066,10 +1212,10 @@ class CarFinanceCalculator:
"logo": car.logo, # getattr(car.id_car_make, "logo", ""),
"trim": car.id_car_trim ,# car_info.get("trim"),
"mileage": car.mileage ,# car_info.get("mileage"),
- "cost_price": car.finances.cost_price,
- "selling_price": car.finances.selling_price,
- "marked_price": car.finances.marked_price,
- "discount": car.finances.discount_amount,
+ "cost_price": car.cost_price,
+ "selling_price": car.selling_price,
+ "marked_price": car.marked_price,
+ "discount": car.discount_amount,
"quantity": quantity,
"unit_price": unit_price,
"sell_price": sell_price,
@@ -1086,7 +1232,7 @@ class CarFinanceCalculator:
def calculate_totals(self):
total_price = sum(
- Decimal(item.item_model.car.finances.marked_price)
+ Decimal(item.item_model.car.marked_price)
for item in self.item_transactions
)
total_additionals = sum(
@@ -1112,7 +1258,7 @@ class CarFinanceCalculator:
def get_finance_data(self):
totals = self.calculate_totals()
return {
- "cars": [self._get_car_data(item) for item in self.item_transactions],
+ "car": [self._get_car_data(item) for item in self.item_transactions],
"quantity": sum(
self._get_quantity(item) for item in self.item_transactions
),
@@ -1127,6 +1273,53 @@ class CarFinanceCalculator:
"additionals": self._get_additional_services(),
"vat": round(self.vat_rate, 2),
}
+
+def get_finance_data(estimate,dealer):
+ vat = models.VatRate.objects.filter(dealer=dealer,is_active=True).first()
+ item = estimate.get_itemtxs_data()[0].first()
+ car = item.item_model.car
+ if isinstance(estimate,InvoiceModel) and hasattr(estimate, "ce_model"):
+ estimate = estimate.ce_model
+
+ extra_info = models.ExtraInfo.objects.get(
+ dealer=dealer,
+ content_type=ContentType.objects.get_for_model(EstimateModel),
+ object_id=estimate.pk,
+ )
+ discount = extra_info.data.get("discount", 0)
+ discount = Decimal(discount)
+ vat_amount = car.marked_price * vat.rate
+ additional_services = car.get_additional_services()
+
+ return {
+ "car": car,
+ "discounted_price": (Decimal(car.marked_price) - discount) or 0,
+ "price_before_discount": car.marked_price,
+ "vat_amount": vat_amount,
+ "vat_rate": vat.rate,
+ "discount_amount": discount,
+ "additional_services": additional_services,
+ "grand_total": (car.marked_price - discount) + vat_amount + additional_services.get("total")
+ }
+
+
+ # totals = self.calculate_totals()
+ # return {
+ # "car": [self._get_car_data(item) for item in self.item_transactions],
+ # "quantity": sum(
+ # self._get_quantity(item) for item in self.item_transactions
+ # ),
+ # "total_price": round(totals["total_price"], 2),
+ # "total_price_discounted": round(totals["total_price_discounted"], 2),
+ # "total_price_before_discount": round(totals["total_price_before_discount"], 2),
+ # "total_vat": round(totals["total_vat_amount"] + totals["total_price"], 2),
+ # "total_vat_amount": round(totals["total_vat_amount"], 2),
+ # "total_discount": round(totals["total_discount"], 2),
+ # "total_additionals": round(totals["total_additionals"], 2),
+ # "grand_total": round(totals["grand_total"], 2),
+ # "additionals": self._get_additional_services(),
+ # "vat": round(self.vat_rate, 2),
+ # }
# class CarFinanceCalculator:
# """
# Class responsible for calculating car financing details.
@@ -1360,9 +1553,9 @@ def _post_sale_and_cogs(invoice, dealer):
2) COGS / Inventory journal
"""
entity = invoice.ledger.entity
- calc = CarFinanceCalculator(invoice)
- data = calc.get_finance_data()
-
+ # calc = CarFinanceCalculator(invoice)
+ data = get_finance_data(invoice,dealer)
+ car = data.get("car")
cash_acc = entity.get_all_accounts().filter(role_default=True, role=roles.ASSET_CA_CASH).first()
ar_acc = entity.get_all_accounts().filter(role_default=True, role=roles.ASSET_CA_RECEIVABLES).first()
vat_acc = entity.get_all_accounts().filter(role_default=True, role=roles.LIABILITY_CL_TAXES_PAYABLE).first()
@@ -1371,105 +1564,105 @@ def _post_sale_and_cogs(invoice, dealer):
cogs_acc = entity.get_all_accounts().filter(role_default=True, role=roles.COGS).first()
inv_acc = entity.get_all_accounts().filter(role_default=True, role=roles.ASSET_CA_INVENTORY).first()
- for car_data in data['cars']:
- car = invoice.get_itemtxs_data()[0].filter(
- item_model__car__vin=car_data['vin']
- ).first().item_model.car
- qty = Decimal(car_data['quantity'])
+ # for car_data in data['cars']:
+ # car = invoice.get_itemtxs_data()[0].filter(
+ # item_model__car__vin=car_data['vin']
+ # ).first().item_model.car
+ # qty = Decimal(car_data['quantity'])
- net_car_price = Decimal(car_data['total']) - Decimal(car_data['total_discount'])
- net_additionals_price = Decimal(data['total_additionals'])
- vat_amount = Decimal(data['total_vat_amount']) * qty
- grand_total = net_car_price + net_additionals_price + vat_amount
- cost_total = Decimal(car_data['cost_price']) * qty
+ net_car_price = Decimal(data['discounted_price'])
+ net_additionals_price = Decimal(data['additional_services']['total'])
+ vat_amount = Decimal(data['vat_amount'])
+ grand_total = net_car_price + net_additionals_price + vat_amount
+ cost_total = Decimal(car.cost_price)
- # ------------------------------------------------------------------
- # 2A. Journal: Cash / A-R / VAT / Sales
- # ------------------------------------------------------------------
+ # ------------------------------------------------------------------
+ # 2A. Journal: Cash / A-R / VAT / Sales
+ # ------------------------------------------------------------------
- je_sale = JournalEntryModel.objects.create(
- ledger=invoice.ledger,
- description=f"Sale {car.vin}",
- origin=f"Invoice {invoice.invoice_number}",
- locked=False,
- posted=False
- )
- # Dr Cash (what the customer paid)
+ je_sale = JournalEntryModel.objects.create(
+ ledger=invoice.ledger,
+ description=f"Sale {car.vin}",
+ origin=f"Invoice {invoice.invoice_number}",
+ locked=False,
+ posted=False
+ )
+ # Dr Cash (what the customer paid)
+ TransactionModel.objects.create(
+ journal_entry=je_sale,
+ account=cash_acc,
+ amount=grand_total,
+ tx_type='debit'
+ )
+
+ # # Cr A/R (clear the receivable)
+ # TransactionModel.objects.create(
+ # journal_entry=je_sale,
+ # account=ar_acc,
+ # amount=grand_total,
+ # tx_type='credit'
+ # )
+
+ # Cr VAT Payable
+ TransactionModel.objects.create(
+ journal_entry=je_sale,
+ account=vat_acc,
+ amount=vat_amount,
+ tx_type='credit'
+ )
+
+ # Cr Sales – Car
+ TransactionModel.objects.create(
+ journal_entry=je_sale,
+ account=car_rev,
+ amount=net_car_price,
+ tx_type='credit'
+ )
+
+ if net_additionals_price > 0:
+ # Cr Sales – Additional Services
TransactionModel.objects.create(
journal_entry=je_sale,
- account=cash_acc,
- amount=grand_total,
- tx_type='debit'
- )
-
- # # Cr A/R (clear the receivable)
- # TransactionModel.objects.create(
- # journal_entry=je_sale,
- # account=ar_acc,
- # amount=grand_total,
- # tx_type='credit'
- # )
-
- # Cr VAT Payable
- TransactionModel.objects.create(
- journal_entry=je_sale,
- account=vat_acc,
- amount=vat_amount,
+ account=add_rev,
+ amount=net_additionals_price,
tx_type='credit'
)
- # Cr Sales – Car
- TransactionModel.objects.create(
- journal_entry=je_sale,
- account=car_rev,
- amount=net_car_price,
- tx_type='credit'
- )
+ # ------------------------------------------------------------------
+ # 2B. Journal: COGS / Inventory reduction
+ # ------------------------------------------------------------------
+ je_cogs = JournalEntryModel.objects.create(
+ ledger=invoice.ledger,
+ description=f"COGS {car.vin}",
+ origin=f"Invoice {invoice.invoice_number}",
+ locked=False,
+ posted=False
+ )
- if net_additionals_price > 0:
- # Cr Sales – Additional Services
- TransactionModel.objects.create(
- journal_entry=je_sale,
- account=add_rev,
- amount=net_additionals_price,
- tx_type='credit'
- )
+ # Dr COGS
+ TransactionModel.objects.create(
+ journal_entry=je_cogs,
+ account=cogs_acc,
+ amount=cost_total,
+ tx_type='debit'
+ )
- # ------------------------------------------------------------------
- # 2B. Journal: COGS / Inventory reduction
- # ------------------------------------------------------------------
- je_cogs = JournalEntryModel.objects.create(
- ledger=invoice.ledger,
- description=f"COGS {car.vin}",
- origin=f"Invoice {invoice.invoice_number}",
- locked=False,
- posted=False
- )
-
- # Dr COGS
- TransactionModel.objects.create(
- journal_entry=je_cogs,
- account=cogs_acc,
- amount=cost_total,
- tx_type='debit'
- )
-
- # Cr Inventory
- TransactionModel.objects.create(
- journal_entry=je_cogs,
- account=inv_acc,
- amount=cost_total,
- tx_type='credit'
- )
- # ------------------------------------------------------------------
- # 2C. Update car state flags inside the same transaction
- # ------------------------------------------------------------------
- entity.get_items_inventory().filter(name=car.vin).update(for_inventory=False)
- # car.item_model.for_inventory = False
- # car.item_model.save(update_fields=['for_inventory'])
- car.finances.selling_price = grand_total
- car.finances.is_sold = True
- car.finances.save()
+ # Cr Inventory
+ TransactionModel.objects.create(
+ journal_entry=je_cogs,
+ account=inv_acc,
+ amount=cost_total,
+ tx_type='credit'
+ )
+ # ------------------------------------------------------------------
+ # 2C. Update car state flags inside the same transaction
+ # ------------------------------------------------------------------
+ entity.get_items_inventory().filter(name=car.vin).update(for_inventory=False)
+ # car.item_model.for_inventory = False
+ # car.item_model.save(update_fields=['for_inventory'])
+ car.selling_price = grand_total
+ # car.is_sold = True
+ car.save()
# def handle_account_process(invoice, amount, finance_data):
# """
# Processes accounting transactions based on an invoice, financial data,
diff --git a/inventory/views.py b/inventory/views.py
index 212dcad3..da7b99ce 100644
--- a/inventory/views.py
+++ b/inventory/views.py
@@ -105,6 +105,9 @@ from django_ledger.forms.bank_account import (
BankAccountCreateForm,
BankAccountUpdateForm,
)
+from django_ledger.views.chart_of_accounts import (
+ ChartOfAccountModelListView as ChartOfAccountModelListViewBase
+)
from django_ledger.views.bill import (
BillModelCreateView,
BillModelDetailView,
@@ -126,6 +129,7 @@ from django_ledger.forms.invoice import (
from django_ledger.forms.item import (
InventoryItemCreateForm,
)
+
from django_ledger.forms.purchase_order import (
PurchaseOrderModelCreateForm,
BasePurchaseOrderModelUpdateForm,
@@ -195,6 +199,7 @@ from .services import (
from .utils import (
CarFinanceCalculator,
get_car_finance_data,
+ get_finance_data,
get_item_transactions,
handle_payment,
reserve_car,
@@ -421,10 +426,10 @@ class ManagerDashboard(LoginRequiredMixin, TemplateView):
qs = models.Car.objects.filter(dealer=dealer)
total_cars = qs.count()
- stats = models.CarFinance.objects.filter(car__dealer=dealer).aggregate(
- total_cost_price=Sum("cost_price"),
- total_selling_price=Sum("selling_price"),
- )
+ stats = 0 # models.CarFinance.objects.filter(car__dealer=dealer).aggregate( #TODO:update_finance
+ # total_cost_price=Sum("cost_price"),
+ # total_selling_price=Sum("selling_price"),
+ # )
total_cost_price = stats["total_cost_price"] or 0
total_selling_price = stats["total_selling_price"] or 0
total_profit = total_selling_price - total_cost_price
@@ -1459,124 +1464,21 @@ class CarDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
permission_required = ["inventory.view_car"]
-class CarFinanceCreateView(LoginRequiredMixin, PermissionRequiredMixin,SuccessMessageMixin, CreateView):
- """
- Handles the creation of car finance records within the inventory system.
+def CarFinanceUpdateView(request,dealer_slug,slug):
+ car = get_object_or_404(models.Car, slug=slug)
+ dealer = get_object_or_404(models.Dealer, slug=dealer_slug)
- This view provides functionality to create car finance records tied to a
- specific car in the inventory. It enforces that the user is logged in and
- has the required permissions to add a car finance record. It also customizes
- form behavior and context data to associate the finance record with the
- corresponding car and populate additional services based on the user's type.
-
- :ivar model: The database model associated with the view.
- :type model: models.CarFinance
- :ivar form_class: The form class used to create car finance records.
- :type form_class: forms.CarFinanceForm
- :ivar template_name: The template used to render the car finance creation page.
- :type template_name: str
- :ivar permission_required: The list of permissions required to access this view.
- :type permission_required: list
- """
-
- model = models.CarFinance
- form_class = forms.CarFinanceForm
- template_name = "inventory/car_finance_form.html"
- permission_required = ["inventory.add_carfinance"]
-
- def dispatch(self, request, *args, **kwargs):
- self.car = get_object_or_404(models.Car, slug=self.kwargs["slug"])
- return super().dispatch(request, *args, **kwargs)
-
- def form_valid(self, form):
- form.instance.car = self.car
- messages.success(self.request, _("Car finance details saved successfully"))
- return super().form_valid(form)
-
- def get_success_url(self):
- return reverse(
- "car_detail",
- kwargs={"dealer_slug": self.request.dealer.slug, "slug": self.car.slug},
- )
-
- def get_context_data(self, **kwargs):
- context = super().get_context_data(**kwargs)
- context["car"] = self.car
- return context
-
- # def get_form(self, form_class=None):
- # form = super().get_form(form_class)
- # dealer = get_user_type(self.request)
- # form.fields[
- # "additional_finances"
- # ].queryset = models.AdditionalServices.objects.filter(dealer=dealer)
- # return form
-
-
-class CarFinanceUpdateView(
- LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, UpdateView
-):
- """
- Manages the update of car finance details.
-
- This class-based view provides functionality for updating car finance
- information in the system. It enforces login and specific permissions for
- access, and it leverages mixins to provide success messages upon completing
- updates. It is designed to interact with car finance data, update form
- handling, and enforce related business logic.
-
- :ivar model: The model associated with the view.
- :type model: models.CarFinance
- :ivar form_class: The form class used by the view.
- :type form_class: forms.CarFinanceForm
- :ivar template_name: The template used for rendering the form.
- :type template_name: str
- :ivar success_message: The success message displayed after an update.
- :type success_message: str
- :ivar permission_required: List of permissions required to access the view.
- :type permission_required: list
- """
-
- model = models.CarFinance
- form_class = forms.CarFinanceForm
- template_name = "inventory/car_finance_form.html"
- success_message = _("Car finance details updated successfully")
- permission_required = ["inventory.change_carfinance"]
-
- def get_success_url(self):
- return reverse(
- "car_detail",
- kwargs={
- "dealer_slug": self.request.dealer.slug,
- "slug": self.object.car.slug,
- },
- )
-
- def get_form_kwargs(self):
- kwargs = super().get_form_kwargs()
- kwargs["instance"] = self.get_object()
- return kwargs
-
- def get_context_data(self , **kwargs):
- context = super().get_context_data(**kwargs)
- context["car"] = self.object.car
- return context
- # def get_initial(self):
- # initial = super().get_initial()
- # instance = self.get_object()
- # dealer = get_user_type(self.request)
- # selected_items = instance.additional_services.filter(dealer=dealer)
- # initial["additional_finances"] = selected_items
- # return initial
-
- # def get_form(self, form_class=None):
- # form = super().get_form(form_class)
- # dealer = get_user_type(self.request)
- # form.fields[
- # "additional_finances"
- # ].queryset = models.AdditionalServices.objects.filter(dealer=dealer)
- # return form
+ if request.method == "POST":
+ form = forms.CarFinanceForm(request.POST, instance=car)
+ if form.is_valid():
+ form.save()
+ return redirect("car_detail", dealer_slug=dealer.slug, slug=car.slug)
+ else:
+ messages.error(request, "Please correct the errors below.")
+ else:
+ form = forms.CarFinanceForm(instance=car)
+ return render(request, "inventory/car_finance_form.html", {"car": car, "dealer": dealer, "form": form})
class CarUpdateView(
LoginRequiredMixin, PermissionRequiredMixin, SuccessMessageMixin, UpdateView
@@ -3064,7 +2966,7 @@ def GroupPermissionView(request, dealer_slug, pk):
# Define ALL permissions you want to manage
MODEL_LIST = [
("inventory", "car"),
- ("inventory", "carfinance"),
+ # ("inventory", "carfinance"),
("inventory", "carlocation"),
("inventory", "customcard"),
("inventory", "cartransfer"),
@@ -3955,7 +3857,7 @@ class BankAccountListView(LoginRequiredMixin, PermissionRequiredMixin, ListView)
def get_queryset(self):
query = self.request.GET.get("q")
- dealer = get_user_type(self.request)
+ dealer = self.request.dealer
bank_accounts = BankAccountModel.objects.filter(entity_model=dealer.entity)
return apply_search_filters(bank_accounts, query)
@@ -4659,8 +4561,7 @@ def create_estimate(request, dealer_slug, slug=None):
hash=item.get("item_id"),
# finances__is_sold=False,
colors__isnull=False,
- finances__isnull=False,
- finances__marked_price__gt=1,
+ marked_price__gt=1,
status="available",
).all()
@@ -4670,9 +4571,9 @@ def create_estimate(request, dealer_slug, slug=None):
{
"item_number": i.item_model.item_number,
"quantity": 1,
- "unit_cost": round(float(i.finances.marked_price)),
- "unit_revenue": round(float(i.finances.marked_price)),
- "total_amount": round(float(i.finances.total_vat)),
+ "unit_cost": round(float(i.marked_price)),
+ "unit_revenue": round(float(i.marked_price)),
+ "total_amount": round(float(i.total_vat)),# TODO : check later
}
)
@@ -4690,10 +4591,10 @@ def create_estimate(request, dealer_slug, slug=None):
# instance = models.Car.objects.get(vin=item.name)
# estimate_itemtxs = {
# item.item_number: {
- # "unit_cost": instance.finances.cost_price,
- # "unit_revenue": instance.finances.marked_price,
+ # "unit_cost": instance.cost_price,
+ # "unit_revenue": instance.marked_price,
# "quantity": Decimal(quantities),
- # "total_amount": instance.finances.total_vat * int(quantities),
+ # "total_amount": instance.total_vat * int(quantities),# TODO : check later
# }
# }
@@ -4773,8 +4674,7 @@ def create_estimate(request, dealer_slug, slug=None):
models.Car.objects.filter(
dealer=dealer,
colors__isnull=False,
- finances__isnull=False,
- finances__marked_price__gt=1,
+ marked_price__gt=1,
status="available",
)
.annotate(
@@ -4849,17 +4749,18 @@ class EstimateDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
estimate = kwargs.get("object")
if estimate.get_itemtxs_data():
- calculator = CarFinanceCalculator(estimate)
- finance_data = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(estimate)
+ # finance_data = calculator.get_finance_data()
+ finance_data = get_finance_data(estimate,dealer)
invoice_obj = InvoiceModel.objects.all().filter(ce_model=estimate).first()
kwargs["data"] = finance_data
kwargs["invoice"] = invoice_obj
try:
- car_finances = estimate.get_itemtxs_data()[0].first().item_model.car.finances
- selected_items = car_finances.additional_services.filter(dealer=dealer)
+ car = estimate.get_itemtxs_data()[0].first().item_model.car
+ selected_items = car.additional_services.filter(dealer=dealer)
form = forms.AdditionalFinancesForm()
- form.fields["additional_finances"].queryset = form.fields["additional_finances"].queryset.filter(dealer=dealer)
+ form.fields["additional_finances"].queryset = form.fields["additional_finances"].queryset.filter(dealer=dealer) # TODO : check later
form.initial["additional_finances"] = selected_items
kwargs["additionals_form"] = form
except Exception as e:
@@ -4938,8 +4839,8 @@ def create_sale_order(request, dealer_slug, pk):
# else:
# form.fields["opportunity"].widget = HiddenInput()
- calculator = CarFinanceCalculator(estimate)
- finance_data = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(estimate)
+ finance_data = get_finance_data(estimate,dealer)
return render(
request,
"sales/estimates/sale_order_form.html",
@@ -4957,15 +4858,16 @@ def update_estimate_discount(request, dealer_slug, pk):
content_type=ContentType.objects.get_for_model(EstimateModel),
object_id=estimate.pk,
)
+ # calculator = CarFinanceCalculator(estimate)
+ # finance_data = calculator.get_finance_data()
discount_amount = request.POST.get("discount_amount", 0)
- calculator = CarFinanceCalculator(estimate)
- finance_data = calculator.get_finance_data()
- if Decimal(discount_amount) >= finance_data.get('cars')[0]['marked_price']:
+ finance_data = get_finance_data(estimate,dealer)
+ car = finance_data.get('car')
+ if Decimal(discount_amount) >= car.marked_price:
messages.error(request, _("Discount amount cannot be greater than marked price"))
return redirect("estimate_detail", dealer_slug=dealer_slug, pk=pk)
- print(finance_data.get('cars')[0]['marked_price'] * Decimal('0.5'))
- if Decimal(discount_amount) > finance_data.get('cars')[0]['marked_price'] * Decimal('0.5'):
+ if Decimal(discount_amount) > car.marked_price * Decimal('0.5'):
messages.warning(request, _("Discount amount is greater than 50% of the marked price, proceed with caution."))
else:
messages.success(request, _("Discount updated successfully"))
@@ -4983,10 +4885,10 @@ def update_estimate_additionals(request, dealer_slug, pk):
if form.is_valid():
estimate = get_object_or_404(EstimateModel, pk=pk)
car = estimate.get_itemtxs_data()[0].first().item_model.car
- car.finances.additional_services.set(
+ car.additional_services.set(
form.cleaned_data["additional_finances"]
)
- car.finances.save()
+ car.save()
messages.success(request, "Additional Finances updated successfully")
return redirect("estimate_detail", dealer_slug=dealer_slug, pk=pk)
@@ -5005,10 +4907,12 @@ class SaleOrderDetail(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
saleorder = kwargs.get("object")
+ dealer = self.request.dealer
estimate = saleorder.estimate
if estimate.get_itemtxs_data():
- calculator = CarFinanceCalculator(estimate)
- finance_data = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(estimate)
+ # finance_data = calculator.get_finance_data()
+ finance_data = get_finance_data(estimate,dealer)
kwargs["data"] = finance_data
return super().get_context_data(**kwargs)
@@ -5106,9 +5010,10 @@ class EstimatePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailVie
def get_context_data(self, **kwargs):
estimate = kwargs.get("object")
if estimate.get_itemtxs_data():
+
# data = get_financial_values(estimate)
- calculator = CarFinanceCalculator(estimate)
- kwargs["data"] = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(estimate)
+ kwargs["data"] = get_finance_data(estimate,self.request.dealer)
return super().get_context_data(**kwargs)
@@ -5288,8 +5193,9 @@ class InvoiceDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView)
invoice = kwargs.get("object")
if invoice.get_itemtxs_data():
- calculator = CarFinanceCalculator(invoice)
- finance_data = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(invoice)
+ # finance_data = calculator.get_finance_data()
+ finance_data = get_finance_data(invoice,self.request.dealer)
kwargs["data"] = finance_data
kwargs["payments"] = JournalEntryModel.objects.filter(
ledger=invoice.ledger
@@ -5515,16 +5421,17 @@ def invoice_create(request, dealer_slug, pk):
ledger.save()
invoice.save()
- calculator = CarFinanceCalculator(estimate)
- finance_data = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(estimate)
+ # finance_data = calculator.get_finance_data()
+ finance_data = get_finance_data(estimate,dealer)
+ car = finance_data.get("car")
invoice_itemtxs = {
- i.get("item_number"): {
- "unit_cost": i.get("grand_total"),
+ car.item_model.item_number: {
+ "unit_cost": finance_data.get("grand_total"),
"quantity": 1,
- "total_amount": i.get("grand_total"),
+ "total_amount": finance_data.get("grand_total"),
}
- for i in finance_data.get("cars")
}
invoice_itemtxs = invoice.migrate_itemtxs(
@@ -5592,8 +5499,8 @@ class InvoicePreviewView(LoginRequiredMixin, PermissionRequiredMixin, DetailView
dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"])
invoice = kwargs.get("object")
if invoice.get_itemtxs_data():
- calculator = CarFinanceCalculator(invoice)
- finance_data = calculator.get_finance_data()
+ # calculator = CarFinanceCalculator(invoice)
+ finance_data = get_finance_data(invoice,dealer)
kwargs["data"] = finance_data
kwargs["dealer"] = dealer
return super().get_context_data(**kwargs)
@@ -6938,11 +6845,11 @@ class OpportunityCreateView(
if self.request.is_dealer:
form.fields["lead"].queryset = models.Lead.objects.filter(
dealer=dealer
- )
+ )
elif self.request.is_staff:
form.fields["lead"].queryset = models.Lead.objects.filter(
dealer=dealer, staff=self.request.staff
- )
+ )
return form
def get_success_url(self):
@@ -9499,7 +9406,7 @@ def pricing_page(request, dealer_slug):
else:
messages.info(request,_("You already have an plan!!"))
return redirect('home',dealer_slug=dealer_slug)
-
+
@login_required
@@ -10687,13 +10594,13 @@ def upload_cars(request, dealer_slug, pk=None):
vendor=vendor,
receiving_date=receiving_date,
)
- if po_item:
- models.CarFinance.objects.create(
- car=car,
- cost_price=po_item.item.unit_cost,
- marked_price=0,
- selling_price=0,
- )
+ # if po_item: #TODO:update
+ # models.CarFinance.objects.create(
+ # car=car,
+ # cost_price=po_item.item.unit_cost,
+ # marked_price=0,
+ # selling_price=0,
+ # )
car.add_colors(exterior=exterior, interior=interior)
cars_created += 1
logger.debug(
@@ -10765,11 +10672,8 @@ def bulk_update_car_price(request):
else:
for car_pk in cars:
car = models.Car.objects.get(pk=car_pk)
- if not hasattr(car, "finances"):
- models.CarFinance.objects.create(car=car, cost_price=Decimal(price))
- else:
- car.finances.cost_price = Decimal(price)
- car.finances.save()
+ car.cost_price = Decimal(price)
+ car.save()
messages.success(request, "Price updated successfully")
response = HttpResponse()
@@ -10979,11 +10883,11 @@ def car_sale_report_csv_export(request,dealer_slug):
car.stock_type,
car.created_at.strftime("%Y-%m-%d %H:%M:%S") if car.created_at else '',
car.sold_date.strftime("%Y-%m-%d %H:%M:%S") if car.sold_date else '',
- car.finances.cost_price,
- car.finances.marked_price,
- car.finances.discount_amount,
- car.finances.selling_price,
- car.finances.vat_amount,
+ car.cost_price,
+ car.marked_price,
+ car.discount_amount,
+ car.selling_price,
+ car.vat_amount, # TODO : check later
car.item_model.invoicemodel_set.first().invoice_number
])
@@ -11232,4 +11136,8 @@ def ticket_update(request, ticket_id):
return render(request, 'support/ticket_update.html', {
'ticket': ticket,
'form': form
- })
\ No newline at end of file
+ })
+
+
+class ChartOfAccountModelListView(ChartOfAccountModelListViewBase):
+ template_name = 'chart_of_accounts/coa_list.html'
\ No newline at end of file
diff --git a/templates/chart_of_accounts/coa_list.html b/templates/chart_of_accounts/coa_list.html
new file mode 100644
index 00000000..5ca6639c
--- /dev/null
+++ b/templates/chart_of_accounts/coa_list.html
@@ -0,0 +1,38 @@
+{% extends 'base.html' %}
+{% load i18n %}
+{% load static %}
+{% load icon from django_ledger %}
+
+{% block content %}
+
+
+
+
+ {% for coa_model in coa_list %}
+
+ {% include 'chart_of_accounts/includes/coa_card.html' with coa_model=coa_model %}
+
+ {% endfor %}
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/templates/chart_of_accounts/includes/coa_card.html b/templates/chart_of_accounts/includes/coa_card.html
new file mode 100644
index 00000000..e3d56ecd
--- /dev/null
+++ b/templates/chart_of_accounts/includes/coa_card.html
@@ -0,0 +1,116 @@
+{% load django_ledger %}
+{% load i18n %}
+{% now "Y" as current_year %}
+
+
+
+
+
+
+
+
+ {% trans 'Entity Default' %}:
+ {% if coa_model.is_default %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {% trans 'Is Active' %}:
+ {% if coa_model.is_active %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ CoA ID:
+ {{ coa_model.slug }}
+
+
+
+
+
+ {% trans 'Total Accounts' %}:
+ {{ coa_model.accountmodel_total__count }}
+
+
+
+ {% trans 'Active Accounts' %}:
+ {{ coa_model.accountmodel_active__count }}
+
+
+
+ {% trans 'Locked Accounts' %}:
+ {{ coa_model.accountmodel_locked__count }}
+
+
+
+
+
+
+
+
+
+
+ {% trans 'Created' %}:
+ {{ coa_model.created|date }}
+
+
+
+
+
+ {% trans 'Updated' %}:
+ {{ coa_model.created|timesince }} {% trans 'ago' %}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/templates/crm/opportunities/opportunity_detail.html b/templates/crm/opportunities/opportunity_detail.html
index 8de794ef..143670f0 100644
--- a/templates/crm/opportunities/opportunity_detail.html
+++ b/templates/crm/opportunities/opportunity_detail.html
@@ -70,9 +70,9 @@
{% endif %}
- {% if opportunity.car.finances %}
+ {% if opportunity.car.marked_price %}
- {{ opportunity.car.finances.total }}
+ {{ opportunity.car.total }} # TODO : check later
{% endif %}
diff --git a/templates/crm/opportunities/opportunity_list copy.html b/templates/crm/opportunities/opportunity_list copy.html
index 3c9133dd..7250543d 100644
--- a/templates/crm/opportunities/opportunity_list copy.html
+++ b/templates/crm/opportunities/opportunity_list copy.html
@@ -75,7 +75,7 @@
height: 12px;
width: 12px">{{ opportunity.get_stage_display }}
- {{ opportunity.car.finances.total }}
+ {{ opportunity.car.total }}
# TODO : check later
@@ -107,7 +107,7 @@
: |
- {{ opportunity.car.finances.total }}
+ {{ opportunity.car.total }}# TODO : check later
|
diff --git a/templates/header.html b/templates/header.html
index cec75ee8..f1d20ad7 100644
--- a/templates/header.html
+++ b/templates/header.html
@@ -217,7 +217,7 @@
{% trans 'Financials' %}
{% if perms.django_ledger.view_accountmodel %}
-
+
{% trans 'Chart of Accounts'|capfirst %}
@@ -295,7 +295,7 @@
{% endif %}
-
+
{% if perms.django_ledger.can_view_reports %}
-
+
-
+
@@ -356,14 +356,14 @@
{% endif %}
-
-
+
+
{% endif %}
-
+
{# --- Support & Contact Section (New) --- #}
diff --git a/templates/inventory/car_detail.html b/templates/inventory/car_detail.html
index f6499423..fc02cefa 100644
--- a/templates/inventory/car_detail.html
+++ b/templates/inventory/car_detail.html
@@ -20,11 +20,11 @@
- {% if not car.finances and not car.colors %}
+ {% if not car.marked_price and not car.colors %}
{{ _("This car information is not complete , please add colors and finances both before making it ready for sale .") }}
- {% elif car.finances and not car.colors %}
+ {% elif car.marked_price and not car.colors %}
{{ _("This car information is not complete , please add colors before making it ready for sale .") }}
@@ -205,7 +205,7 @@
| {% trans 'Location'|capfirst %} |
- {% if car.finances and not car.get_transfer %}
+ {% if car.marked_price and not car.get_transfer %}
{% if car.location %}
{% if car.location.is_owner_showroom %}
{% trans 'Our Showroom' %}
@@ -257,16 +257,16 @@
|