fix the invoice and estimate calculation

This commit is contained in:
gitea 2025-01-07 14:35:36 +00:00
parent 0cb378d25f
commit e1b2fb9c83
5 changed files with 128 additions and 74 deletions

View File

@ -321,42 +321,34 @@ class CarFinance(models.Model):
selling_price = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Selling Price"))
discount_amount = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Discount Amount"),
default=Decimal('0.00'))
# profit_margin = models.DecimalField(max_digits=14,
# decimal_places=2,
# verbose_name=_("Profit Margin"),
# editable=False)
# vat_amount = models.DecimalField(max_digits=14,
# decimal_places=2,
# verbose_name=_("Vat Amount"),
# editable=False,default=Decimal('0.00'))
# registration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Registration Fee"),
# default=Decimal('0.00'))
# administration_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Administration Fee"),
# default=Decimal('0.00'))
# transportation_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Transportation Fee"),
# default=Decimal('0.00'))
# custom_card_fee = models.DecimalField(max_digits=14, decimal_places=2, verbose_name=_("Custom Card Fee"),
# default=Decimal('0.00'))
@property
def total(self):
total = 0
def total(self):
total = self.selling_price
if self.additional_services.count() != 0:
total_additional_services = sum(x.default_amount for x in self.additional_services.all())
total = self.selling_price + total_additional_services
else:
total = self.selling_price
if self.discount_amount != 0:
total = total - self.discount_amount
total += total_additional_services
return total
@property
def total_discount(self):
if self.discount_amount != 0:
total = self.total - self.discount_amount
return total
return self.total
@property
def total_vat(self):
return self.total_discount + self.vat_amount
@property
def vat_amount(self):
vat = VatRate.objects.filter(is_active=True).first()
return (self.total * vat.vat_rate).quantize(Decimal('0.01'))
@property
def total_vat(self):
return self.total + self.vat_amount
if vat:
return (self.total_discount * Decimal(vat.vat_rate)).quantize(Decimal('0.01'))
return Decimal('0.00')

View File

@ -1,3 +1,4 @@
from decimal import Decimal
from django.shortcuts import redirect
from django.contrib import messages
from django.utils import timezone
@ -90,4 +91,11 @@ def reserve_car(car,request):
except Exception as e:
messages.error(request, f"Error reserving car: {e}")
return redirect("car_detail", pk=car.pk)
return redirect("car_detail", pk=car.pk)
def calculate_vat_amount(amount):
vat = models.VatRate.objects.filter(is_active=True).first()
if vat:
return ((amount * Decimal(vat.vat_rate)).quantize(Decimal('0.01')),vat.vat_rate)
return amount

View File

@ -69,7 +69,13 @@ from . import models, forms
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.models import Group
from .utils import get_calculations, reserve_car, send_email, get_user_type
from .utils import (
calculate_vat_amount,
get_calculations,
reserve_car,
send_email,
get_user_type,
)
from django.contrib.auth.models import User
from allauth.account import views
from django.db.models import Count, F, Value
@ -639,8 +645,8 @@ class CustomCardCreateView(LoginRequiredMixin, CreateView):
@login_required()
def reserve_car_view(request, car_id):
if request.method == "POST":
car = get_object_or_404(models.Car, pk=car_id)
if car.is_reserved():
car = get_object_or_404(models.Car, pk=car_id)
if car.is_reserved():
messages.error(request, _("This car is already reserved."))
return redirect("car_detail", pk=car.pk)
response = reserve_car(car, request)
@ -749,13 +755,16 @@ class CustomerDetailView(LoginRequiredMixin, DetailView):
model = models.Customer
template_name = "customers/view_customer.html"
context_object_name = "customer"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
name = f"{context['customer'].first_name} {context['customer'].middle_name} {context['customer'].last_name}"
context["estimates"] = self.request.entity.get_estimates().filter(customer__customer_name=name)
context["estimates"] = self.request.entity.get_estimates().filter(
customer__customer_name=name
)
return context
class CustomerCreateView(
LoginRequiredMixin,
SuccessMessageMixin,
@ -1425,6 +1434,7 @@ def download_quotation_pdf(request, quotation_id):
# return redirect("quotation_detail", pk=pk)
def payment_create(request, pk):
quotation = get_object_or_404(models.SaleQuotation, pk=pk)
dealer = get_user_type(request)
@ -1573,6 +1583,7 @@ def bank_account_delete(request, pk):
# Accounts
class AccountListView(LoginRequiredMixin, ListView):
model = AccountModel
template_name = "ledger/coa_accounts/account_list.html"
@ -1707,9 +1718,9 @@ def create_estimate(request):
"item_number": item_instance.item_number,
"quantity": float(item.get("quantity")),
"unit_cost": car_instance.finances.cost_price,
"unit_revenue": car_instance.finances.total_vat,
"total_amount": car_instance.finances.total_vat
* int(item.get("quantity")),
"unit_revenue": car_instance.finances.selling_price,
"total_amount": (car_instance.finances.total_vat)
* int(item.get("quantity")),
}
)
@ -1730,7 +1741,8 @@ def create_estimate(request):
"unit_cost": instance.finances.cost_price,
"unit_revenue": instance.finances.selling_price,
"quantity": float(quantities),
"total_amount": instance.finances.total * int(quantities),
"total_amount": instance.finances.total_vat
* int(quantities),
}
}
@ -1743,9 +1755,9 @@ def create_estimate(request):
if isinstance(items, list):
for item in items:
item_instance = ItemModel.objects.get(pk=item)
instance = models.Car.objects.get(vin=item_instance.name)
instance = models.Car.objects.get(vin=item_instance.name)
reserve_car(instance, request)
else:
item_instance = ItemModel.objects.get(pk=items)
instance = models.Car.objects.get(vin=item_instance.name)
@ -1759,7 +1771,7 @@ def create_estimate(request):
"url": f"{url}",
}
)
form = EstimateModelCreateForm(entity_slug=entity.slug, user_model=entity.admin)
car_list = models.Car.objects.filter(
dealer=dealer, finances__selling_price__gt=0
@ -1786,21 +1798,29 @@ class EstimateDetailView(LoginRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
estimate = kwargs.get("object")
if estimate.get_itemtxs_data():
if estimate.get_itemtxs_data():
total = sum(
(
models.Car.objects.get(vin=x.item_model.name).finances.total_vat
float(
models.Car.objects.get(
vin=x.item_model.name
).finances.total
)
* float(x.ce_quantity)
for x in estimate.get_itemtxs_data()[0].all()
)
discount_amount = sum(
models.CarFinance.objects.get(
car__vin=i.item_model.name
).discount_amount
for i in estimate.get_itemtxs_data()[0].all()
)
vat = models.VatRate.objects.filter(is_active=True).first()
vat_amount = round(total * vat.vat_rate, 2)
# grand_total = round(
# (total * vat.vat_rate) + total, 2
# )
grand_total = float(total) - float(discount_amount)
vat_amount = round(float(grand_total) * float(vat.vat_rate), 2)
kwargs["vat_amount"] = vat_amount
kwargs["total"] = total
kwargs["total"] = grand_total + vat_amount
kwargs["discount_amount"] = discount_amount
kwargs["vat"] = vat.rate
kwargs["invoice"] = (
InvoiceModel.objects.all().filter(ce_model=estimate).first()
@ -1848,24 +1868,24 @@ def estimate_mark_as(request, pk):
if mark == "review":
if not estimate.can_review():
messages.error(request, "Estimate is not ready for review")
return redirect("estimate_detail", pk=estimate.pk)
return redirect("estimate_detail", pk=estimate.pk)
estimate.mark_as_review()
elif mark == "approved":
if not estimate.can_approve():
messages.error(request, "Estimate is not ready for approval")
return redirect("estimate_detail", pk=estimate.pk)
estimate.mark_as_approved()
messages.success(request, "Estimate approved successfully.")
estimate.mark_as_approved()
messages.success(request, "Estimate approved successfully.")
elif mark == "rejected":
if not estimate.can_cancel():
messages.error(request, "Estimate is not ready for rejection")
return redirect("estimate_detail", pk=estimate.pk)
estimate.mark_as_canceled()
messages.success(request, "Estimate canceled successfully.")
messages.success(request, "Estimate canceled successfully.")
elif mark == "completed":
if not estimate.can_complete():
messages.error(request, "Estimate is not ready for completion")
return redirect("estimate_detail", pk=estimate.pk)
return redirect("estimate_detail", pk=estimate.pk)
estimate.save()
messages.success(request, "Estimate marked as " + mark.upper())
@ -1891,15 +1911,27 @@ class InvoiceDetailView(LoginRequiredMixin, DetailView):
def get_context_data(self, **kwargs):
invoice = kwargs.get("object")
vat = models.VatRate.objects.filter(is_active=True).first()
if invoice.get_itemtxs_data():
total = sum(
x.unit_cost * x.quantity for x in invoice.get_itemtxs_data()[0].all()
float(x.ce_revenue_estimate) * float(x.ce_quantity)
for x in invoice.ce_model.get_itemtxs_data()[0].all()
)
total = int(total)
vat = models.VatRate.objects.filter(is_active=True).first()
kwargs["vat_amount"] = total * vat.vat_rate
kwargs["total"] = (total * vat.vat_rate) + total
discount_amount = sum(
models.CarFinance.objects.get(
car__vin=i.item_model.name
).discount_amount
for i in invoice.get_itemtxs_data()[0].all()
)
grand_total = float(total) - float(discount_amount)
vat_amount = round(float(grand_total) * float(vat.vat_rate), 2)
kwargs["vat_amount"] = vat_amount
kwargs["total"] = grand_total + vat_amount
kwargs["discount_amount"] = discount_amount
kwargs["vat"] = vat.rate
kwargs["amount_left"] = invoice.amount_due - invoice.amount_paid
kwargs["payments"] = JournalEntryModel.objects.filter(
@ -1961,17 +1993,27 @@ def invoice_create(request, pk):
invoice_model.save()
unit_items = estimate.get_itemtxs_data()[0]
# for item in unit_items:
# car = models.Car.objects.get(vin=item.item_model.name)
itemtxs = []
for item in unit_items:
car = models.Car.objects.get(vin=item.item_model.name)
itemtxs.append(
{
"item_number": item.item_model.item_number,
"unit_cost": car.finances.total_vat,
"unit_revenue": car.finances.total_vat,
"quantity": item.ce_quantity,
"total_amount": float(car.finances.total_vat)
* float(item.ce_quantity),
}
)
invoice_itemtxs = {
i.item_model.item_number: {
"unit_cost": i.ce_unit_revenue_estimate,
"quantity": i.ce_quantity,
"total_amount": i.ce_revenue_estimate,
i.get("item_number"): {
"unit_cost": i.get("unit_cost"),
"quantity": i.get("quantity"),
"total_amount": i.get("total_amount"),
}
for i in unit_items
for i in itemtxs
}
invoice_itemtxs = invoice_model.migrate_itemtxs(
@ -2117,7 +2159,6 @@ class UserActivityLogListView(ListView):
return queryset
# CRM RELATED VIEWS
def create_lead(request, pk):
customer = get_object_or_404(models.Customer, pk=pk)
@ -2344,6 +2385,7 @@ def send_email_view(request, pk):
{"estimate": estimate, "message": msg},
)
# errors
def custom_page_not_found_view(request, exception):
return render(request, "errors/404.html", {})

View File

@ -141,6 +141,12 @@
<span id="grand-total">{{vat_amount}}</span>
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">{% trans "Discount Amount" %}</td>
<td class="align-middle text-start fw-bold">
<span id="grand-total">{{discount_amount}}</span>
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">{% trans "Grand Total" %}</td>
<td class="align-middle text-start fw-bold">

View File

@ -145,13 +145,13 @@
</tr>
</thead>
<tbody>
{% for item in invoice.get_itemtxs_data.0 %}
{% for item in invoice.ce_model.get_itemtxs_data.0 %}
<tr>
<td class="">{{forloop.counter}}</td>
<td class="">{{item.item_model.name}}</td>
<td class="align-middle">{{item.quantity}}</td>
<td class="align-middle ps-5">{{item.unit_cost}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.total_amount}}</td>
<td class="align-middle">{{item.ce_quantity}}</td>
<td class="align-middle ps-5">{{item.ce_unit_revenue_estimate}}</td>
<td class="align-middle text-body-tertiary fw-semibold">{{item.ce_revenue_estimate}}</td>
</tr>
{% endfor %}
<tr class="bg-body-secondary total-sum">
@ -160,6 +160,12 @@
<span id="grand-total">{{vat_amount}}</span>
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">{% trans "Discount Amount" %}</td>
<td class="align-middle text-start fw-bold">
<span id="grand-total">{{discount_amount}}</span>
</td>
</tr>
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">{% trans "Grand Total" %}</td>
<td class="align-middle text-start fw-bold">