diff --git a/inventory/models.py b/inventory/models.py index 3fbe4bfc..904382f3 100644 --- a/inventory/models.py +++ b/inventory/models.py @@ -3416,6 +3416,8 @@ class DealerSettings(models.Model): on_delete=models.SET_NULL, null=True, blank=True, + help_text=_("Cash account to track cash transactions when an invoice is created."), + verbose_name=_("Invoice Cash Account"), ) invoice_prepaid_account = models.ForeignKey( AccountModel, @@ -3423,6 +3425,8 @@ class DealerSettings(models.Model): on_delete=models.SET_NULL, null=True, blank=True, + help_text=_("Prepaid Revenue account to track prepaid revenue when an invoice is created."), + verbose_name=_("Invoice Prepaid Account"), ) invoice_unearned_account = models.ForeignKey( AccountModel, @@ -3430,6 +3434,54 @@ class DealerSettings(models.Model): on_delete=models.SET_NULL, null=True, blank=True, + help_text=_("Unearned Revenue account to track unearned revenue when an invoice is created."), + verbose_name=_("Invoice Unearned Account"), + ) + invoice_tax_payable_account = models.ForeignKey( + AccountModel, + related_name="invoice_tax_payable", + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text=_("Tax Payable account to track tax liabilities when an invoice is created."), + verbose_name=_("Invoice Tax Payable Account"), + ) + invoice_vehicle_sale_account = models.ForeignKey( + AccountModel, + related_name="invoice_vehicle_sale", + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text=_("Vehicle Sales account to track vehicle sales revenue when an invoice is created."), + verbose_name=_("Invoice Vehicle Sale Account"), + ) + invoice_additional_services_account = models.ForeignKey( + AccountModel, + related_name="invoice_additional_services", + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text=_("Additional Services account to track additional services revenue when an invoice is created."), + verbose_name=_("Invoice Additional Services Account"), + ) + invoice_cost_of_good_sold_account = models.ForeignKey( + AccountModel, + related_name="invoice_cost_of_good_sold", + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text=_("Cost of Goods Sold account to track the cost of goods sold when an invoice is created."), + verbose_name=_("Invoice Cost of Goods Sold Account"), + ) + + invoice_inventory_account = models.ForeignKey( + AccountModel, + related_name="invoice_inventory", + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text=_("Inventory account to track the cost of goods sold when an invoice is created."), + verbose_name=_("Invoice Inventory Account"), ) bill_cash_account = models.ForeignKey( @@ -3438,6 +3490,8 @@ class DealerSettings(models.Model): on_delete=models.SET_NULL, null=True, blank=True, + help_text=_("Cash account to track cash transactions when a bill is created."), + verbose_name=_("Bill Cash Account"), ) bill_prepaid_account = models.ForeignKey( AccountModel, @@ -3445,6 +3499,8 @@ class DealerSettings(models.Model): on_delete=models.SET_NULL, null=True, blank=True, + help_text=_("Prepaid account to track prepaid expenses when a bill is created."), + verbose_name=_("Bill Prepaid Account"), ) bill_unearned_account = models.ForeignKey( AccountModel, @@ -3452,9 +3508,11 @@ class DealerSettings(models.Model): on_delete=models.SET_NULL, null=True, blank=True, + help_text=_("Unearned account to track unearned expenses when a bill is created."), + verbose_name=_("Bill Unearned Account"), ) - additional_info = models.JSONField(default=dict, null=True, blank=True) - + additional_info = models.JSONField(default=dict, null=True, blank=True, help_text=_("Additional information")) + def __str__(self): return f"Settings for {self.dealer}" diff --git a/inventory/signals.py b/inventory/signals.py index 4dbea6dc..3596d189 100644 --- a/inventory/signals.py +++ b/inventory/signals.py @@ -311,8 +311,8 @@ def create_item_model(sender, instance, created, **kwargs): instance.item_model = inventory instance.save() - if instance.marked_price: - instance.item_model.default_amount = instance.marked_price + if instance.cost_price: + instance.item_model.default_amount = instance.cost_price instance.item_model.save() # inventory = entity.create_item_inventory( @@ -813,7 +813,7 @@ def create_dealer_settings(sender, instance, created, **kwargs): # entity = instance.entity # coa = entity.get_default_coa() -# for make in models.CarMake.objects.all(): +# for make in models. ke.objects.all(): # last_account = entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).order_by('-created').first() # if len(last_account.code) == 4: # code = f"{int(last_account.code)}{1:03d}" @@ -824,7 +824,7 @@ def create_dealer_settings(sender, instance, created, **kwargs): # code=code, # role=roles.ASSET_CA_RECEIVABLES, # coa_model=coa, -# balance_type="credit", +# balance_type="credit",b vgbvf vh cbgl;;; # active=True # ) diff --git a/inventory/utils.py b/inventory/utils.py index eb4cc5f4..d4294400 100644 --- a/inventory/utils.py +++ b/inventory/utils.py @@ -1598,44 +1598,23 @@ def _post_sale_and_cogs(invoice, dealer): # calc = CarFinanceCalculator(invoice) data = get_finance_data(invoice, dealer) car = data.get("car") - cash_acc = ( - entity.get_default_coa_accounts() - .filter(role_default=True, role=roles.ASSET_CA_CASH) - .first() - ) - ar_acc = ( - entity.get_default_coa_accounts() - .filter(role_default=True, role=roles.ASSET_CA_RECEIVABLES) - .first() - ) - vat_acc = ( - entity.get_default_coa_accounts() - .filter(role_default=True, role=roles.LIABILITY_CL_TAXES_PAYABLE) - .first() - ) - car_rev = ( - entity.get_default_coa_accounts() - .filter(role_default=True, role=roles.INCOME_OPERATIONAL) - .first() - ) - add_rev = entity.get_default_coa_accounts().filter(code="4020").first() - cogs_acc = ( - entity.get_default_coa_accounts() - .filter(role_default=True, role=roles.COGS) - .first() - ) - inv_acc = ( - entity.get_default_coa_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']) - + # cash_acc = ( + # entity.get_default_coa_accounts() + # .filter(role_default=True, role=roles.ASSET_CA_CASH) + # .first() + # ) + cash_acc = invoice.cash_account or dealer.settings.invoice_cash_account + + vat_acc = dealer.settings.invoice_tax_payable_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.LIABILITY_CL_TAXES_PAYABLE).first() + + car_rev = dealer.settings.invoice_vehicle_sale_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.INCOME_OPERATIONAL).first() + + add_rev = dealer.settings.invoice_additional_services_account + + cogs_acc = dealer.settings.invoice_cost_of_good_sold_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.COGS).first() + + inv_acc = dealer.settings.invoice_inventory_account or entity.get_default_coa_accounts().filter(role_default=True, role=roles.ASSET_CA_INVENTORY).first() + net_car_price = Decimal(data["discounted_price"]) net_additionals_price = Decimal(data["additional_services"]["total"]) vat_amount = Decimal(data["vat_amount"]) @@ -1663,23 +1642,6 @@ def _post_sale_and_cogs(invoice, dealer): description="Debit to Cash on Hand", ) - # # 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", - description="Credit to Tax Payable", - ) - # Cr Sales – Car TransactionModel.objects.create( journal_entry=je_sale, @@ -1689,22 +1651,43 @@ def _post_sale_and_cogs(invoice, dealer): description=" Credit to Car Sales", ) + # Cr VAT Payable + TransactionModel.objects.create( + journal_entry=je_sale, + account=vat_acc, + amount=vat_amount + car.get_additional_services_vat, + tx_type="credit", + description="Credit to Tax Payable", + ) + + # # Cr A/R (clear the receivable) + # TransactionModel.objects.create( + # journal_entry=je_sale, + # account=ar_acc, + # amount=grand_total, + # tx_type='credit' + # ) + + if car.get_additional_services_amount > 0: # Cr Sales – Additional Services - TransactionModel.objects.create( - journal_entry=je_sale, - account=add_rev, - amount=car.get_additional_services_amount, - tx_type="credit", - description="Credit to After-Sales Services", - ) - TransactionModel.objects.create( - journal_entry=je_sale, - account=vat_acc, - amount=car.get_additional_services_vat, - tx_type="credit", - description="Credit to Tax Payable (Additional Services)", - ) + if not add_rev: + logger.warning(f"Additional Services account not set for dealer {dealer}. Skipping additional services revenue entry.") + else: + TransactionModel.objects.create( + journal_entry=je_sale, + account=add_rev, + amount=car.get_additional_services_amount, + tx_type="credit", + description="Credit to After-Sales Services", + ) + # TransactionModel.objects.create( + # journal_entry=je_sale, + # account=vat_acc, + # amount=car.get_additional_services_vat, + # tx_type="credit", + # description="Credit to Tax Payable (Additional Services)", + # ) # ------------------------------------------------------------------ # 2B. Journal: COGS / Inventory reduction diff --git a/inventory/views.py b/inventory/views.py index 1390ab5f..df35f062 100644 --- a/inventory/views.py +++ b/inventory/views.py @@ -503,9 +503,7 @@ def general_dashboard(request,dealer_slug): 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 - - expenses = models.ItemModel.objects.filter(entity__admin__dealer=dealer, item_role='expense') - total_expenses = expenses.aggregate(total=Sum('default_amount'))['total'] or 0 + total_expenses=sum([x.amount_paid for x in dealer.entity.get_bills().filter(bill_items__item_role="expense")]) gross_profit = net_profit_from_cars - total_expenses # ---------------------------------------------------- @@ -4201,7 +4199,7 @@ class BankAccountCreateView( def get_form(self, form_class=None): dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) form = super().get_form(form_class) - account_qs = dealer.entity.get_default_coa_accounts().filter( + account_qs = dealer.entity.get_get_default_coa_accounts().filter( role__in=[ roles.ASSET_CA_CASH, roles.LIABILITY_CL_ACC_PAYABLE, @@ -4296,7 +4294,7 @@ class BankAccountUpdateView( def get_form(self, form_class=None): dealer = get_object_or_404(models.Dealer, slug=self.kwargs["dealer_slug"]) form = super().get_form(form_class) - account_qs = dealer.entity.get_default_coa_accounts().filter( + account_qs = dealer.entity.get_get_default_coa_accounts().filter( role__in=[ roles.ASSET_CA_CASH, roles.LIABILITY_CL_ACC_PAYABLE, @@ -9221,27 +9219,47 @@ def DealerSettingsView(request, slug): form = forms.DealerSettingsForm(instance=dealer_setting, initial={"dealer": dealer}) form.fields[ "invoice_cash_account" - ].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH) + ].queryset = dealer.entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_CASH) form.fields[ "invoice_prepaid_account" - ].queryset = dealer.entity.get_all_accounts().filter( + ].queryset = dealer.entity.get_default_coa_accounts().filter( role=roles.ASSET_CA_RECEIVABLES ) form.fields[ "invoice_unearned_account" - ].queryset = dealer.entity.get_all_accounts().filter( + ].queryset = dealer.entity.get_default_coa_accounts().filter( role=roles.LIABILITY_CL_DEFERRED_REVENUE ) + form.fields[ + "invoice_tax_payable_account" + ].queryset = dealer.entity.get_default_coa_accounts().filter( + role=roles.LIABILITY_CL_TAXES_PAYABLE + ) + form.fields[ + "invoice_vehicle_sale_account" + ].queryset = dealer.entity.get_default_coa_accounts().filter( + role=roles.INCOME_OPERATIONAL + ) + form.fields[ + "invoice_cost_of_good_sold_account" + ].queryset = dealer.entity.get_default_coa_accounts().filter( + role=roles.COGS + ) + form.fields[ + "invoice_inventory_account" + ].queryset = dealer.entity.get_default_coa_accounts().filter( + role=roles.ASSET_CA_INVENTORY + ) - form.fields["bill_cash_account"].queryset = dealer.entity.get_all_accounts().filter( + form.fields["bill_cash_account"].queryset = dealer.entity.get_default_coa_accounts().filter( role=roles.ASSET_CA_CASH ) form.fields[ "bill_prepaid_account" - ].queryset = dealer.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID) + ].queryset = dealer.entity.get_default_coa_accounts().filter(role=roles.ASSET_CA_PREPAID) form.fields[ "bill_unearned_account" - ].queryset = dealer.entity.get_all_accounts().filter( + ].queryset = dealer.entity.get_default_coa_accounts().filter( role=roles.LIABILITY_CL_ACC_PAYABLE ) return render(request, "account/user_settings.html", {"form": form}) diff --git a/static/images/car_images/d004326438f695f30050fa1e7f252d9d2d60da4b7b26f49e42badcc0687ebb3c.png b/static/images/car_images/d004326438f695f30050fa1e7f252d9d2d60da4b7b26f49e42badcc0687ebb3c.png new file mode 100644 index 00000000..10fe5ecb Binary files /dev/null and b/static/images/car_images/d004326438f695f30050fa1e7f252d9d2d60da4b7b26f49e42badcc0687ebb3c.png differ diff --git a/templates/account/user_settings.html b/templates/account/user_settings.html index 9a3243da..88111e63 100644 --- a/templates/account/user_settings.html +++ b/templates/account/user_settings.html @@ -24,12 +24,18 @@ {{ form.invoice_cash_account|as_crispy_field }} {{ form.invoice_prepaid_account|as_crispy_field }} {{ form.invoice_unearned_account|as_crispy_field }} + {{ form.invoice_tax_payable_account|as_crispy_field }} + {{ form.invoice_vehicle_sale_account|as_crispy_field }} + {{ form.invoice_additional_services_account|as_crispy_field }} + {{ form.invoice_cost_of_good_sold_account|as_crispy_field }} + {{ form.invoice_inventory_account|as_crispy_field }}
{% trans "Total Revenue from Cars" %}
{% trans "Net Profit from Cars" %}
{% trans "Total Cost of Cars Sold" %}
{% trans "Total VAT from Cars" %}
{% trans "New Cars Revenue" %}
{% trans "New Cars Net Profit" %}
{% trans "New Cars VAT" %}
{% trans "New Cars Cost" %}
{% trans "Used Cars Revenue" %}
{% trans "Used Cars Net Profit" %}
{% trans "Used Cars VAT" %}
{% trans "Used Cars Cost" %}
{% trans "Total Inventory Value" %}
{% trans "New Cars Inventory Value" %}
{% trans "Used Cars Inventory Value" %}
{% trans "Total Revenue from Services" %}
{% trans "Total VAT from Services" %}
{% trans "Total Revenue Generated" %}
{% trans "Total VAT Collected" %}
{% trans "Total Expenses" %}
- {{ total_revenue_from_cars|floatformat:2 }} + {{ total_revenue_from_cars|floatformat:'2g' }}
@@ -133,7 +133,7 @@ {% trans 'Total Revenue from Services' %}- {{ total_revenue_from_additonals|floatformat:2 }} + {{ total_revenue_from_additonals|floatformat:'2g' }}
@@ -145,7 +145,7 @@ {% trans 'Total Revenue' %}- {{ total_revenue_collected|floatformat:2 }} + {{ total_revenue_collected|floatformat:'2g' }}
@@ -157,7 +157,7 @@ {% trans 'Total VAT from Cars' %}- {{ total_vat_on_cars|floatformat:2 }} + {{ total_vat_on_cars|floatformat:'2g' }}
@@ -169,7 +169,7 @@ {% trans 'Total VAT from Services' %}- {{ total_vat_from_additonals|floatformat:2 }} + {{ total_vat_from_additonals|floatformat:'2g' }}
@@ -181,7 +181,7 @@ {% trans 'Total VAT' %}- {{ total_vat_collected|floatformat:2 }} + {{ total_vat_collected|floatformat:'2g' }}
@@ -193,7 +193,7 @@ {% trans 'Total Discount Amount' %}- {{ total_discount|floatformat:2 }} + {{ total_discount|floatformat:'2g' }}
diff --git a/templates/ledger/reports/purchase_report.html b/templates/ledger/reports/purchase_report.html index e713d777..0690bf81 100644 --- a/templates/ledger/reports/purchase_report.html +++ b/templates/ledger/reports/purchase_report.html @@ -75,7 +75,7 @@{{ total_po_amount }}
+{{ total_po_amount|floatformat:'2g' }}