This commit is contained in:
gitea 2025-01-01 15:59:30 +00:00
parent 0dd461d8cc
commit 146fd26d52
25 changed files with 4140 additions and 2957 deletions

View File

@ -189,7 +189,7 @@ class CarUpdateForm(forms.ModelForm, AddClassMixin):
class CarFinanceForm(AddClassMixin, forms.ModelForm):
additional_finances = forms.ModelMultipleChoiceField(
queryset=AdditionalServices.objects.all(),
queryset=ItemModel.objects.filter(item_role=ItemModel.ITEM_ROLE_SERVICE),
widget=forms.CheckboxSelectMultiple(attrs={"class": "form-check-input"}),
required=False,
)
@ -198,7 +198,6 @@ class CarFinanceForm(AddClassMixin, forms.ModelForm):
model = CarFinance
exclude = [
"car",
"additional_finances",
"profit_margin",
"vat_amount",
"total",
@ -206,12 +205,12 @@ class CarFinanceForm(AddClassMixin, forms.ModelForm):
"additional_services",
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance.pk:
self.fields[
"additional_finances"
].initial = self.instance.additional_services.all()
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# if self.instance.pk:
# self.fields[
# "additional_finances"
# ].initial = self.instance.additional_services.all()
def save(self, commit=True):
instance = super().save()
@ -523,9 +522,9 @@ class ItemForm(forms.Form):
queryset=ItemModel.objects.all(), label="Item", required=True
)
quantity = forms.DecimalField(label="Quantity", required=True)
unit = forms.DecimalField(label="Unit", required=True)
unit_cost = forms.DecimalField(label="Unit Cost", required=True)
unit_sales_price = forms.DecimalField(label="Unit Sales Price", required=True)
# unit = forms.DecimalField(label="Unit", required=True)
# unit_cost = forms.DecimalField(label="Unit Cost", required=True)
# unit_sales_price = forms.DecimalField(label="Unit Sales Price", required=True)
class PaymentForm(forms.Form):

View File

@ -26,4 +26,16 @@ class LogUserActivityMiddleware:
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
return x_forwarded_for.split(',')[0]
return request.META.get('REMOTE_ADDR')
return request.META.get('REMOTE_ADDR')
class InjectParamsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
request.entity = request.user.dealer.entity
response = self.get_response(request)
return response

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-01-01 12:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
('inventory', '0022_rename_log_oportunitylog'),
]
operations = [
migrations.RemoveField(
model_name='carfinance',
name='additional_services',
),
migrations.AddField(
model_name='carfinance',
name='services',
field=models.ManyToManyField(blank=True, related_name='services', to='django_ledger.itemmodel'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 4.2.17 on 2025-01-01 12:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('django_ledger', '0017_alter_accountmodel_unique_together_and_more'),
('inventory', '0023_remove_carfinance_additional_services_and_more'),
]
operations = [
migrations.RemoveField(
model_name='carfinance',
name='services',
),
migrations.AddField(
model_name='carfinance',
name='additional_services',
field=models.ManyToManyField(blank=True, related_name='additional_finances', to='django_ledger.itemmodel'),
),
]

View File

@ -17,6 +17,7 @@ from django_ledger.models import (
UnitOfMeasureModel,
CustomerModel,
ItemModelQuerySet,
)
from django.db.models import Sum
from decimal import Decimal, InvalidOperation
@ -304,7 +305,7 @@ class CarReservation(models.Model):
# Car Finance Model
class CarFinance(models.Model):
additional_services = models.ManyToManyField(AdditionalServices, related_name="additional_finances",blank=True)
additional_services = models.ManyToManyField(ItemModel, 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"))
@ -328,8 +329,17 @@ class CarFinance(models.Model):
# default=Decimal('0.00'))
@property
def total(self):
"""Calculate the total amount including VAT."""
return get_total(self)
vat = VatRate.objects.filter(is_active=True).first()
total = 0
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 * vat.vat_rate).quantize(Decimal('0.01')) + total
return total
def __str__(self):
return f"Car: {self.car}, Selling Price: {self.selling_price}"

View File

@ -241,64 +241,64 @@ def create_customer(sender, instance, created, **kwargs):
# Create Item
# @receiver(post_save, sender=models.Car)
# def create_item_model(sender, instance, created, **kwargs):
# item_name = f"{instance.year} - {instance.id_car_make} - {instance.id_car_model} - {instance.id_car_trim}"
# uom_name = _("Car")
# unit_abbr = _("C")
#
# uom, uom_created = UnitOfMeasureModel.objects.get_or_create(
# name=uom_name,
# unit_abbr=unit_abbr
# )
#
# if uom_created:
# print(f"UOM created: {uom_name}")
# else:
# print(f"Using existing UOM: {uom_name}")
#
# entity = EntityModel.objects.filter(name=instance.dealer.name).first()
#
# inventory_account = AccountModel.objects.first()
# cogs_account = AccountModel.objects.first()
# earnings_account = AccountModel.objects.first()
#
# entity.create_item_product(
# item_name=item_name,
# item_role=ItemModelAbstract.ITEM_ROLE_PRODUCT,
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
# item_id=instance.vin,
# sold_as_unit=True,
# inventory_received=1.00,
# inventory_received_value=0.00,
# inventory_account=inventory_account,
# for_inventory=True,)
#
# item = ItemModel.objects.create(
# entity=entity,
# uom=uom,
# name=item_name,
# item_role=ItemModelAbstract.ITEM_ROLE_INVENTORY,
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
# item_id=instance.vin,
# sold_as_unit=True,
# inventory_received=1.00,
# inventory_received_value=0.00,
# inventory_account=inventory_account,
# for_inventory=True,
# is_product_or_service=True,
# cogs_account=cogs_account,
# earnings_account=earnings_account,
# is_active=True,
# additional_info={
# "remarks": instance.remarks,
# "status": instance.status,
# "stock_type": instance.stock_type,
# "mileage": instance.mileage,
# },
# )
#
# print(f"ItemModel {'created' if created else 'updated'} for Car: {item.name}")
@receiver(post_save, sender=models.Car)
def create_item_model(sender, instance, created, **kwargs):
# item_name = f"{instance.year} - {instance.id_car_make} - {instance.id_car_model} - {instance.id_car_trim}"
# uom_name = _("Car")
# unit_abbr = _("C")
# uom, uom_created = UnitOfMeasureModel.objects.get_or_create(
# name=uom_name,
# unit_abbr=unit_abbr
# )
# if uom_created:
# print(f"UOM created: {uom_name}")
# else:
# print(f"Using existing UOM: {uom_name}")
entity = EntityModel.objects.first()
uom = entity.get_uom_all().first()
coa = entity.get_default_coa()
entity.create_item_product(
name=f"{instance.vin}",
item_type=ItemModel.ITEM_TYPE_OTHER,
uom_model=uom,
coa_model=coa
)
entity.create_item_inventory(
name=f"{instance.vin}",
item_type=ItemModel.ITEM_TYPE_OTHER,
uom_model=uom,
coa_model=coa
)
# item = ItemModel.objects.create(
# entity=entity,
# uom=uom,
# name=item_name,
# item_role=ItemModelAbstract.ITEM_ROLE_INVENTORY,
# item_type=ItemModelAbstract.ITEM_TYPE_MATERIAL,
# item_id=instance.vin,
# sold_as_unit=True,
# inventory_received=1.00,
# inventory_received_value=0.00,
# inventory_account=inventory_account,
# for_inventory=True,
# is_product_or_service=True,
# cogs_account=cogs_account,
# earnings_account=earnings_account,
# is_active=True,
# additional_info={
# "remarks": instance.remarks,
# "status": instance.status,
# "stock_type": instance.stock_type,
# "mileage": instance.mileage,
# },
# )
# print(f"ItemModel {'created' if created else 'updated'} for Car: {item.name}")
#
#
# # update price - CarFinance

View File

@ -153,6 +153,11 @@ urlpatterns = [
# path('sales/payments/<uuid:pk>/preview/', views.JournalEntryPreviewView.as_view(), name='payment_preview'),
# # Journal
# path('sales/journal/<uuid:pk>/create/', views.JournalEntryCreateView.as_view(), name='journal_create'),
#Items
path('items/services/', views.ItemServiceListView.as_view(), name='item_service_list'),
path('items/services/create/', views.ItemServiceCreateView.as_view(), name='item_service_create'),
]

View File

@ -2,7 +2,7 @@
from decimal import Decimal
from django.conf import settings
from inventory import models
from django_ledger.models.items import ItemModel
def calculate_vat(value):
"""Helper to calculate VAT dynamically for a given value."""
vat_rate = getattr(settings, 'VAT_RATE', Decimal('0.15')) # Default VAT rate
@ -13,7 +13,7 @@ def calculate_vat(value):
# return getattr(instance, attribute, Decimal('0.00')) if instance else Decimal('0.00')
def get_financial_value(name,vat=False):
val = models.AdditionalServices.objects.filter(name=name).first()
val = ItemModel.objects.filter(name=name).first()
if not val:
return 0
if vat:
@ -24,8 +24,9 @@ def get_financial_value(name,vat=False):
def get_total_financials(instance,vat=False):
total = 0
if instance.additional_services.count() != 0:
total = sum(x.price for x in instance.additional_services.all()) + instance.selling_price
if vat:
total_additional_services = sum(x.price for x in instance.additional_services.all())
total = instance.selling_price + total_additional_services
if vat and total:
total = (total * settings.VAT_RATE).quantize(Decimal('0.01')) + total
return total

View File

@ -4,7 +4,7 @@ from django.conf import settings
from django.core.mail import send_mail
from django.utils.translation import gettext_lazy as _
from inventory.utilities.financials import get_financial_value
from django_ledger.models.items import ItemModel
def get_jwt_token():
url = 'https://carapi.app/api/auth/login'
@ -39,8 +39,8 @@ def get_calculations(quotation):
cars = [x.car for x in quotation.quotation_cars.all()]
finances = models.CarFinance.objects.filter(car__in=cars)
services = models.AdditionalServices.objects.filter(additional_finances__in=finances).all()
data = [{"name":x.name,"price":x.price,"total_price":x.price * qc_len,"vated":float(x.price) * 0.15 * float(qc_len),"total_price_vat":float(x.price) + (float(x.price) * 0.15 * float(qc_len))} for x in services]
services = ItemModel.objects.filter(additional_finances__in=finances).all()
data = [{"name":x.name,"price":x.default_amount,"total_price":x.default_amount * qc_len,"vated":float(x.default_amount) * 0.15 * float(qc_len),"total_price_vat":float(x.default_amount) + (float(x.default_amount) * 0.15 * float(qc_len))} for x in services]
context["services"] = data
context["total_cost"] = 0
context["total_vat"] = 0

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -30,14 +30,16 @@
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;400;600;700;800;900&amp;display=swap" rel="stylesheet">
<link href="{% static 'vendors/simplebar/simplebar.min.css' %}" rel="stylesheet">
<link href="{% static 'css/sweetalert2.min.css' %}" rel="stylesheet">
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
<link rel="stylesheet" href="https://unicons.iconscout.com/release/v4.0.8/css/line.css">
{% if LANGUAGE_CODE == 'en' %}
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
{% else %}
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
{% endif %}
{% endif %}
{% block extra_css %}{% endblock extra_css %}
</head>
<body>

View File

@ -244,8 +244,8 @@
{% if car.finances.additional_services.first.pk %}
{% for service in car.finances.additional_services.all %}
<tr>
<td>{{service.get_local_name}}</td>
<td>{{ service.price }}</td>
<td>{{service.name}}</td>
<td>{{ service.default_amount }}</td>
</tr>
{% endfor %}
{% endif %}

View File

@ -0,0 +1,24 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load static %}
{% load i18n %}
{% block title %}{{ _("Service") }}{% endblock title %}
{% block content %}
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ _("Add Service") }}</div>
<div class="card-body">
<form method="post" action="">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">{% trans 'Save' %}</button>
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock content %}

View File

@ -0,0 +1,106 @@
{% extends "base.html" %}
{% load i18n %}
{% load render_table from django_tables2 %}
{% block title %}{% trans "users" %}{% endblock title %}
{% block users %}<a class="nav-link active">{% trans "users"|capfirst %}</a>{% endblock %}
{% block content %}
<div class="d-flex flex-column min-vh-100">
<div class="d-flex flex-column flex-sm-grow-1 ms-sm-14 p-4">
<main class="d-grid gap-4 p-1">
<div class="row g-4">
<div class="col-lg-6 col-xl-12">
<div class="container-fluid p-2">
<form method="get">
<div class="input-group input-group-sm">
<button id="inputGroup-sizing-sm"
class="btn btn-sm btn-secondary rounded-start" type="submit">
{% trans 'search'|capfirst %}
</button>
<input type="text"
name="q"
class="form-control form-control-sm rounded-end"
value="{{ request.GET.q }}"
aria-describedby="inputGroup-sizing-sm"/>
<!-- Clear Button -->
{% if request.GET.q %}
<a href="{% url request.resolver_match.view_name %}"
class="btn btn-sm btn-outline-danger ms-1 rounded">
<i class="bi bi-x-lg"></i>
</a>
{% endif %}
</div>
</form>
</div>
<table class="table table-hover table-responsive-sm">
<thead>
<tr>
<th>{% trans 'Item Number'|capfirst %}</th>
<th>{% trans 'Name'|capfirst %}</th>
<th>{% trans 'Unit of Measure'|capfirst %}</th>
<th>{% trans 'Cost of Goods Sold'|capfirst %}</th>
</tr>
</thead>
<tbody>
{% for service in services %}
<tr>
<td>{{ service.item_number }}</td>
<td>{{ service.name }}</td>
<td>{{ service.uom }}</td>
<td>{{ service.cogs_account }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- Optional: Pagination -->
{% if is_paginated %}
<nav aria-label="Page navigation">
<ul class="pagination mb-0">
{% if page_obj.has_previous %}
<li class="page-item py-0">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
<span aria-hidden="true"><span class="fas fa-chevron-left"></span></span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Previous">
<span aria-hidden="true"><span class="fas fa-chevron-left"></span></span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Next">
<span aria-hidden="true"><span class="fas fa-chevron-right"></span></span>
</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" href="#" aria-label="Next">
<span aria-hidden="true"><span class="fas fa-chevron-right"></span></span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</div>
</main>
</div>
</div>
{% endblock %}

View File

@ -7,10 +7,10 @@
<div class="modal fade" id="confirmModal" tabindex="-1" aria-labelledby="confirmModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header bg-primary">
<h5 class="modal-title text-light" id="confirmModalLabel">{% trans 'Confirm' %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-header bg-primary">
<h5 class="modal-title text-light" id="confirmModalLabel">{% trans 'Confirm' %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{% trans 'Are you sure' %}
<div class="modal-footer">
@ -28,24 +28,26 @@
</div>
</div>
</div>
<!-- ============================================-->
<!-- <section> begin ============================-->
<section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="container-small mt-3">
<div class="d-flex justify-content-between align-items-end mb-4">
<h2 class="mb-0">Estimate</h2>
<h2 class="mb-0">{% trans 'Estimate' %}</h2>
<div class="d-flex align-items-center gap-2">
{% if estimate.status == 'draft' %}
<a href="{% url 'send_email' estimate.pk %}" class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">Send Estimate</span></a>
<button id="mark_as_sent_estimate" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">Mark As Sent</span></button>
<a href="{% url 'send_email' estimate.pk %}" class="btn btn-phoenix-primary me-2"><span class="fa-regular fa-paper-plane me-sm-2"></span><span class="d-none d-sm-inline-block">{% trans 'Send Estimate' %}</span></a>
<button id="mark_as_sent_estimate" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">{% trans 'Mark As Sent' %}</span></button>
{% endif %}
{% if estimate.status == 'in_review' %}
<button id="accept_estimate" onclick="setFormAction('accepted')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">Mark As Accepted</span></button>
<button id="accept_estimate" onclick="setFormAction('accepted')" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">{% trans 'Mark As Accept' %}</span></button>
{% endif %}
{% if estimate.status == 'approved' %}
<a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">Create Invoice</span></a>
<a href="{% url 'invoice_create' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Create Invoice' %}</span></a>
{% endif %}
<a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">Preview</span></a>
<a href="{% url 'estimate_preview' estimate.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span></a>
</div>
</div>
<div class="bg-body dark__bg-gray-1100 p-4 mb-4 rounded-2">
@ -55,7 +57,7 @@
<div class="col-12 col-sm-6 col-lg-12">
<div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5">
<h6 class="mb-0 me-3">Estimate No :</h6>
<h6 class="mb-0 me-3">{% trans 'Estimate Number' %} :</h6>
</div>
<div class="col-auto col-lg-6 col-xl-7">
<p class="fs-9 text-body-secondary fw-semibold mb-0">#{{estimate.estimate_number}}</p>
@ -65,7 +67,7 @@
<div class="col-12 col-sm-6 col-lg-12">
<div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5">
<h6 class="me-3">Estimate Date :</h6>
<h6 class="me-3">{% trans 'Estimate Date' %} :</h6>
</div>
<div class="col-auto col-lg-6 col-xl-7">
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.created}}</p>
@ -77,11 +79,11 @@
<div class="col-12 col-sm-6 col-lg-5">
<div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5">
<h6 class="mb-2 me-3">Customer :</h6>
<h6 class="mb-2 me-3">{% trans 'Customer' %} :</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.customer_name}}</p>
</div>
<div class="col-12 col-lg-4">
<h6 class="mb-2"> Email :</h6>
<h6 class="mb-2"> {% trans 'Email' %} :</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{estimate.customer.email}}</p>
</div>
</div>
@ -89,16 +91,16 @@
<div class="col-12 col-sm-6 col-lg-4">
<div class="row g-4">
<div class="col-12 col-lg-6">
<h6 class="mb-2"> Estimate Status :</h6>
<h6 class="mb-2"> {% trans "Estimate Status" %} :</h6>
<div class="fs-9 text-body-secondary fw-semibold mb-0">
{% if estimate.status == 'draft' %}
<span class="badge text-bg-warning">Draft</span>
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
{% elif estimate.status == 'in_review' %}
<span class="badge text-bg-info">Sent</span>
<span class="badge text-bg-info">{% trans "In Review" %}</span>
{% elif estimate.status == 'approved' %}
<span class="badge text-bg-success">Approved</span>
<span class="badge text-bg-success">{% trans "Approved" %}</span>
{% elif estimate.status == 'declined' %}
<span class="badge text-bg-danger">Declined</span>
<span class="badge text-bg-danger">{% trans "Declined" %}</span>
{% endif %}
</div>
</div>
@ -112,10 +114,10 @@
<thead class="bg-body-secondary">
<tr>
<th scope="col" style="width: 24px;">#</th>
<th scope="col" style="min-width: 260px;">Item</th>
<th scope="col" style="min-width: 60px;">Quantity</th>
<th scope="col" style="min-width: 60px;">Unit Price</th>
<th scope="col" style="min-width: 60px;">Total</th>
<th scope="col" style="min-width: 260px;">{% trans "Item" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Total" %}</th>
</tr>
</thead>
@ -130,13 +132,13 @@
</tr>
{% endfor %}
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">Vat ({{vat}}%)</td>
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">{% trans "Vat" %} ({{vat}}%)</td>
<td class="align-middle text-start fw-bold">
<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">Grand Total</td>
<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">
<span id="grand-total">{{total}}</span>
</td>
@ -147,7 +149,6 @@
</div>
</div>
</div>
<!-- end of .container-->
</section>

View File

@ -25,6 +25,8 @@
<div class="mb-2 col-sm-2">
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
</div>
<!---
<div class="mb-2 col-sm-2">
<input class="form-control unitCost" type="number" placeholder="Unit Cost" name="unitCost[]" step="0.01" required>
</div>
@ -40,6 +42,7 @@
<div class="mb-2 col-sm-1">
<button class="btn btn-danger removeBtn">Remove</button>
</div>
-->
</div>
</div>
<div class="col-12">
@ -59,7 +62,7 @@
<script>
// Function to calculate Total Cost and Total Revenue
function calculateTotals(container) {
/*function calculateTotals(container) {
const quantity = parseFloat(container.querySelector('.quantity').value) || 0;
const unitCost = parseFloat(container.querySelector('.unitCost').value) || 0;
const unitSalesPrice = parseFloat(container.querySelector('.unitSalesPrice').value) || 0;
@ -69,14 +72,14 @@
container.querySelector('.totalCost').value = totalCost.toFixed(2);
container.querySelector('.totalRevenue').value = totalRevenue.toFixed(2);
}
}*/
// Add event listeners to inputs for dynamic calculation
function addInputListeners(container) {
/*function addInputListeners(container) {
container.querySelectorAll('.quantity, .unitCost, .unitSalesPrice').forEach(input => {
input.addEventListener('input', () => calculateTotals(container));
});
}
}*/
// Add new form fields
document.getElementById('addMoreBtn').addEventListener('click', function(e) {
@ -94,19 +97,7 @@
</div>
<div class="mb-2 col-sm-2">
<input class="form-control quantity" type="number" placeholder="Quantity" name="quantity[]" required>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control unitCost" type="number" placeholder="Unit Cost" name="unitCost[]" step="0.01" required>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control unitSalesPrice" type="number" placeholder="Unit Sales Price" name="unitSalesPrice[]" step="0.01" required>
</div>
<div class="mb-2 col-sm-2">
<input class="form-control totalCost" type="number" placeholder="Total Cost" name="totalCost[]" readonly>
</div>
<div class="mb-2 col-sm-1">
<input class="form-control totalRevenue" type="number" placeholder="Total Revenue" name="totalRevenue[]" readonly>
</div>
</div>
<div class="mb-2 col-sm-1">
<button class="btn btn-danger removeBtn">Remove</button>
</div>
@ -148,8 +139,10 @@ const url = "{% url 'estimate_create' %}"
data[key] = value;
}
});
console.log(formData);
console.log(data);
// Send data to the server using fetch
fetch(url, {
/* fetch(url, {
method: 'POST',
body: formData,
headers: {
@ -175,7 +168,7 @@ const url = "{% url 'estimate_create' %}"
console.error('Error:', error);
notify("error",error);
alert('An error occurred while submitting the form.');
});
});*/
});
</script>

View File

@ -25,7 +25,23 @@
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap py-0">{{ estimate.estimate_number }}</td>
<td class="align-middle product white-space-nowrap">{{ estimate.customer }}</td>
<td class="align-middle product white-space-nowrap">{{ estimate.status }}</td>
<td class="align-middle product white-space-nowrap">
{% if estimate.status == 'draft' %}
<span class="badge bg-warning text-light">{% trans "Draft" %}</span>
{% elif estimate.status == 'in_review' %}
<span class="badge bg-info text-light">{% trans "In Review" %}</span>
{% elif estimate.status == 'approved' %}
<span class="badge bg-success text-light">{% trans "Approved" %}</span>
{% elif estimate.status == 'declined' %}
<span class="badge bg-danger text-light">{% trans "Declined" %}</span>
{% elif estimate.status == 'canceled' %}
<span class="badge bg-danger text-light">{% trans "Canceled" %}</span>
{% elif estimate.status == 'completed' %}
<span class="badge bg-success text-light">{% trans "Completed" %}</span>
{% elif estimate.status == 'void' %}
<span class="badge bg-secondary text-light">{% trans "Void" %}</span>
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">{{ estimate.get_status_action_date }}</td>
<td class="align-middle product white-space-nowrap">{{ estimate.created }}</td>
<td class="text-center">

View File

@ -1,3 +1,4 @@
{% load static i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
@ -9,6 +10,7 @@
<!-- Google Fonts - Roboto -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<!-- Custom CSS -->
<style>
body {
background-color: #f8f9fa;
@ -111,10 +113,17 @@
margin-right:10rem;
}
</style>
{% if LANGUAGE_CODE == 'en' %}
<link href="{% static 'css/theme.min.css' %}" type="text/css" rel="stylesheet" id="style-default">
<link href="{% static 'css/user.min.css' %}" type="text/css" rel="stylesheet" id="user-style-default">
{% else %}
<link href="{% static 'css/theme-rtl.min.css' %}" type="text/css" rel="stylesheet" id="style-rtl">
<link href="{% static 'css/user-rtl.min.css' %}" type="text/css" rel="stylesheet" id="user-style-rtl">
{% endif %}
</head>
<body>
<div class="button-container">
<button id="download-pdf" class="btn btn-primary">Download Estimate</button>
<button id="download-pdf" class="btn btn-primary">{% trans 'Download Estimate' %}</button>
</div>
<div class="estimate-container" id="estimate-content">
<!-- Header -->
@ -171,17 +180,17 @@
<path fill-rule="evenodd" clip-rule="evenodd" d="M97.3451 20.9973C97.2528 21.0348 97.1554 21.0535 97.0531 21.0535C96.8983 21.0535 96.7597 21.0185 96.6374 20.9486C96.515 20.8787 96.4189 20.7826 96.349 20.6602C96.2791 20.5379 96.2441 20.3993 96.2441 20.2445C96.2441 20.0797 96.2816 19.9349 96.3565 19.8101C96.4314 19.6827 96.5337 19.5841 96.6636 19.5142C96.7934 19.4418 96.9432 19.4056 97.113 19.4056C97.2803 19.4056 97.4288 19.4405 97.5587 19.5105C97.6885 19.5779 97.7896 19.6727 97.862 19.7951C97.9369 19.9174 97.9744 20.0585 97.9744 20.2183C97.9744 20.3282 97.9557 20.4393 97.9182 20.5516C97.8808 20.6615 97.8183 20.7876 97.731 20.9299L97.0531 22.0422H96.6935V22.016L97.3451 20.9973ZM97.6561 20.2333C97.6561 20.3381 97.6323 20.4318 97.5849 20.5142C97.5375 20.5966 97.4725 20.6615 97.3901 20.7089C97.3078 20.7539 97.2129 20.7763 97.1055 20.7763C96.9981 20.7763 96.9045 20.7539 96.8246 20.7089C96.7447 20.664 96.6811 20.6016 96.6336 20.5217C96.5887 20.4393 96.5662 20.3469 96.5662 20.2445C96.5662 20.1372 96.5887 20.0435 96.6336 19.9636C96.6811 19.8837 96.746 19.8213 96.8284 19.7764C96.9108 19.7289 97.0056 19.7052 97.113 19.7052C97.2179 19.7052 97.3102 19.7277 97.3901 19.7726C97.4725 19.8176 97.5375 19.88 97.5849 19.9599C97.6323 20.0373 97.6561 20.1284 97.6561 20.2333Z" fill="#15447A"></path>
<path d="M100.343 6.74274C100.343 7.17876 99.9895 7.53222 99.5534 7.53222C99.1174 7.53222 98.7639 7.17876 98.7639 6.74274C98.7639 6.30671 99.1174 5.95325 99.5534 5.95325C99.9895 5.95325 100.343 6.30671 100.343 6.74274Z" fill="#15447A"></path>
</svg>
<h1 style="margin-top: 10px;">Estimate</h1>
<p>Thank you for choosing us. We appreciate your business!</p>
<h1 style="margin-top: 10px;"><b>{% trans "Estimate" %}</b></h1>
<p>{% trans "Thank you for choosing us. We appreciate your business" %}</p>
</div>
<!-- Details -->
<div class="estimate-details">
<p><strong>Estimate Number:</strong> <span class="highlight">#{{estimate.estimate_number}}</span></p>
<p><strong>Date:</strong> {{estimate.date_in_review}}</p>
<p><strong>Customer:</strong> {{estimate.customer.customer_name}}</p>
<p><strong>Email:</strong> {{estimate.customer.email}}</p>
<p><strong>Terms:</strong> {{estimate.terms|title}}</p>
<p><strong>{% trans "Estimate Number" %} :</strong> <span class="highlight">#{{estimate.estimate_number}}</span></p>
<p><strong>{% trans "Date" %} :</strong> {{estimate.date_in_review}}</p>
<p><strong>{% trans "Customer" %} :</strong> {{estimate.customer.customer_name}}</p>
<p><strong>{% trans "Email" %} :</strong> {{estimate.customer.email}}</p>
<p><strong>{% trans "Terms" %} :</strong> {{estimate.terms|title}}</p>
</div>
<!-- Items Table -->
@ -189,19 +198,19 @@
<table class="table table-bordered">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Total</th>
<th>{% trans "Item" %}</th>
<th class="text-center">{% trans "Quantity" %}</th>
<th class="text-center">{% trans "Unit Price" %}</th>
<th class="text-center">{% trans "Total" %}</th>
</tr>
</thead>
<tbody>
{% for item in estimate.get_itemtxs_data.0 %}
<tr>
<td>{{ item.item_model.name }}</td>
<td>{{ item.ce_quantity }}</td>
<td>{{ item.ce_unit_cost_estimate }}</td>
<td>{{ item.ce_cost_estimate }}</td>
<td class="text-center">{{ item.ce_quantity }}</td>
<td class="text-center">{{ item.ce_unit_cost_estimate }}</td>
<td class="highlight fw-semibold text-center">{{ item.ce_cost_estimate }}</td>
</tr>
{% endfor %}
</tbody>
@ -210,19 +219,19 @@
<!-- Additional Charges (VAT and Services) -->
<div class="additional-charges">
<p><strong>VAT ({{vat}}%):</strong> <span class="highlight">${{vate_amount}}</span></p>
<p><strong>Additional Services:</strong> <span class="highlight">$50.00</span></p>
<p><strong>{% trans "VAT" %} ({{vat}}%):</strong> <span class="highlight">${{vat_amount}}</span></p>
<p><strong>{% trans "Additional Services" %}:</strong> <span class="highlight">$50.00</span></p>
</div>
<!-- Total -->
<div class="estimate-total">
<p><strong>Total Amount:</strong> <span class="highlight">${{total}}</span></p>
<p><strong>{%trans "Total Amount" %}:</strong> <span class="highlight">${{total}}</span></p>
</div>
<!-- Footer Note -->
<div class="footer-note">
<p>If you have any questions, feel free to contact us at <a href="mailto:support@example.com">support@example.com</a>.</p>
<p>Thank you for your business!</p>
<p>{% trans "If you have any questions, feel free to contact us at" %} <a href="mailto:support@example.com">support@example.com</a>.</p>
<p>{% trans "Thank you for your business" %}</p>
</div>
<!-- Button Container -->
</div>

View File

@ -4,7 +4,7 @@
{% load i18n %}
{% block title %}{{ _("Invoice") }}{% endblock title %}
{% block content %}
<div class="container">
<div class="container paid">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">

View File

@ -33,15 +33,15 @@
<section class="pt-5 pb-9 bg-body-emphasis dark__bg-gray-1200 border-top">
<div class="container-small mt-3">
<div class="d-flex justify-content-between align-items-end mb-4">
<h2 class="mb-0">Invoice</h2>
<h2 class="mb-0">{% trans 'Invoice' %}</h2>
<div class="d-flex align-items-center gap-2">
{% if invoice.invoice_status == 'in_review' %}
<button id="accept_invoice" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">Accept</span></button>
<button id="accept_invoice" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#confirmModal"><span class="d-none d-sm-inline-block">{% trans 'Accept' %}</span></button>
{% endif %}
{% if invoice.invoice_status == 'approved' %}
<a href="{% url 'payment_create' invoice.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">Record Payment</span></a>
<a href="{% url 'payment_create' invoice.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Record Payment' %}</span></a>
{% endif %}
<a href="{% url 'invoice_preview' invoice.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">Preview</span></a>
<a href="{% url 'invoice_preview' invoice.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block">{% trans 'Preview' %}</span></a>
</div>
</div>
@ -53,7 +53,7 @@
<div class="d-sm-block d-inline-flex d-md-flex flex-xl-column flex-xxl-row align-items-center align-items-xl-start align-items-xxl-center">
<div class="d-flex bg-success-subtle rounded flex-center me-3 mb-sm-3 mb-md-0 mb-xl-3 mb-xxl-0" style="width:32px; height:32px"><span class="text-success-dark" data-feather="dollar-sign" style="width:24px; height:24px"></span></div>
<div>
<p class="fw-bold mb-1">Paid Amount</p>
<p class="fw-bold mb-1">{% trans 'Paid Amount' %}</p>
<h4 class="fw-bolder text-nowrap">${{invoice.amount_paid}}</h4>
</div>
</div>
@ -62,7 +62,7 @@
<div class="d-sm-block d-inline-flex d-md-flex flex-xl-column flex-xxl-row align-items-center align-items-xl-start align-items-xxl-center border-start-sm ps-sm-5 border-translucent">
<div class="d-flex bg-primary-subtle rounded flex-center me-3 mb-sm-3 mb-md-0 mb-xl-3 mb-xxl-0" style="width:32px; height:32px"><span class="text-primary-dark" data-feather="layout" style="width:24px; height:24px"></span></div>
<div>
<p class="fw-bold mb-1">Due Amount</p>
<p class="fw-bold mb-1">{% trans 'Due Amount' %}</p>
<h4 class="fw-bolder text-nowrap">${{invoice.amount_due}} </h4>
</div>
</div>
@ -78,7 +78,7 @@
<div class="col-12 col-sm-6 col-lg-12">
<div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5">
<h6 class="mb-0 me-3">invoice No :</h6>
<h6 class="mb-0 me-3">{% trans "Invoice Number" %} :</h6>
</div>
<div class="col-auto col-lg-6 col-xl-7">
<p class="fs-9 text-body-secondary fw-semibold mb-0">#{{invoice.invoice_number}}</p>
@ -88,7 +88,7 @@
<div class="col-12 col-sm-6 col-lg-12">
<div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5">
<h6 class="me-3">invoice Date :</h6>
<h6 class="me-3">{% trans "Invoice Date" %} :</h6>
</div>
<div class="col-auto col-lg-6 col-xl-7">
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.created}}</p>
@ -100,11 +100,11 @@
<div class="col-12 col-sm-6 col-lg-5">
<div class="row align-items-center g-0">
<div class="col-auto col-lg-6 col-xl-5">
<h6 class="mb-2 me-3">Customer :</h6>
<h6 class="mb-2 me-3">{% trans "Customer Name" %} :</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.customer.customer_name}}</p>
</div>
<div class="col-12 col-lg-4">
<h6 class="mb-2"> Email :</h6>
<h6 class="mb-2"> {% trans "Customer Email" %} :</h6>
<p class="fs-9 text-body-secondary fw-semibold mb-0">{{invoice.customer.email}}</p>
</div>
</div>
@ -112,16 +112,18 @@
<div class="col-12 col-sm-6 col-lg-4">
<div class="row g-4">
<div class="col-12 col-lg-6">
<h6 class="mb-2"> invoice Status :</h6>
<h6 class="mb-2"> {% trans "Invoice Status" %} :</h6>
<div class="fs-9 text-body-secondary fw-semibold mb-0">
{% if invoice.invoice_status == 'draft' %}
<span class="badge text-bg-warning">Draft</span>
<span class="badge text-bg-warning">{% trans "Draft" %}</span>
{% elif invoice.invoice_status == 'in_review' %}
<span class="badge text-bg-info">Sent</span>
<span class="badge text-bg-info">{% trans "In Review" %}</span>
{% elif invoice.invoice_status == 'approved' %}
<span class="badge text-bg-success">Approved</span>
<span class="badge text-bg-info">{% trans "Approved" %}</span>
{% elif invoice.invoice_status == 'declined' %}
<span class="badge text-bg-danger">Declined</span>
<span class="badge text-bg-danger">{% trans "Declined" %}</span>
{% elif invoice.invoice_status == 'paid' %}
<span class="badge text-bg-success">{% trans "Paid" %}</span>
{% endif %}
</div>
</div>
@ -135,10 +137,10 @@
<thead class="bg-body-secondary">
<tr>
<th scope="col" style="width: 24px;">#</th>
<th scope="col" style="min-width: 260px;">Item</th>
<th scope="col" style="min-width: 60px;">Quantity</th>
<th scope="col" style="min-width: 60px;">Unit Price</th>
<th scope="col" style="min-width: 60px;">Total</th>
<th scope="col" style="min-width: 260px;">{% trans "Item" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Quantity" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Unit Price" %}</th>
<th scope="col" style="min-width: 60px;">{% trans "Total" %}</th>
</tr>
</thead>
<tbody>
@ -152,13 +154,13 @@
</tr>
{% endfor %}
<tr class="bg-body-secondary total-sum">
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">Vat ({{vat}}%)</td>
<td class="align-middle ps-4 fw-bold text-body-highlight" colspan="4">{% trans "VAT" %} ({{vat}}%)</td>
<td class="align-middle text-start fw-bold">
<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">Grand Total</td>
<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">
<span id="grand-total">{{total}}</span>
</td>
@ -166,8 +168,7 @@
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -26,17 +26,19 @@
<td class="align-middle product white-space-nowrap py-0">{{ invoice.invoice_number }}</td>
<td class="align-middle product white-space-nowrap">{{ invoice.customer }}</td>
<td class="align-middle product white-space-nowrap text-success">
{% if invoice.invoice_status == "approved" %}
<span class="badge badge-phoenix badge-phoenix-success">{{ invoice.invoice_status }}</span>
{% elif invoice.invoice_status == "canceled" %}
<span class="badge badge-phoenix badge-phoenix-danger">{{ invoice.invoice_status }}</span>
{% elif invoice.invoice_status == "draft" %}
<span class="badge badge-phoenix badge-phoenix-warning">{{ invoice.invoice_status }}</span>
{% elif invoice.invoice_status == "in_review" %}
<span class="badge badge-phoenix badge-phoenix-info">{{ invoice.invoice_status }}</span>
{% elif invoice.invoice_status == "paid" %}
<span class="badge badge-phoenix badge-phoenix-success">{{ invoice.invoice_status }}</span>
{% endif %}
{% if invoice.is_past_due %}
<span class="badge badge-phoenix badge-phoenix-danger">{% trans "Past Due" %}</span>
{% elif invoice.is_approved %}
<span class="badge badge-phoenix badge-phoenix-success">{% trans "Approved" %}</span>
{% elif invoice.is_canceled %}
<span class="badge badge-phoenix badge-phoenix-secondary">{% trans "Canceled" %}</span>
{% elif invoice.is_draft %}
<span class="badge badge-phoenix badge-phoenix-warning">{% trans "Draft" %}</span>
{% elif invoice.is_review %}
<span class="badge badge-phoenix badge-phoenix-info">{% trans "In Review" %}</span>
{% elif invoice.is_paid %}
<span class="badge badge-phoenix badge-phoenix-success">{% trans "Paid" %}</span>
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{% if invoice.invoice_status == "in_review" %}

View File

@ -19,7 +19,6 @@
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Description" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Credit" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Debit" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Actions" %}</th>
</thead>
<tbody class="list">
{% for transaction in journal.transactionmodel_set.all %}
@ -32,7 +31,6 @@
<td class="align-middle product white-space-nowrap">{{ transaction.description }}</td>
<td class="align-middle product white-space-nowrap">{% if transaction.tx_type == "credit" %}${{ transaction.amount }}{% endif %}</td>
<td class="align-middle product white-space-nowrap">{% if transaction.tx_type == "debit" %}${{ transaction.amount }}{% endif %}</td>
<td class="align-middle product white-space-nowrap"></td>
</tr>
{% empty %}
<tr>

View File

@ -3,12 +3,24 @@
{% load static %}
{% load i18n %}
{% block title %}{{ _("Make Payment") }}{% endblock title %}
{% block extra_css %}
<style>
.paid {
pointer-events: none;
opacity: 0.4;
}
</style>
{% endblock extra_css %}
{% block content %}
<div class="container">
<div class="container {% if invoice.invoice_status == 'paid' %}paid{% endif %}">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
{% if invoice.invoice_status == 'paid' %}
<div class="card-header">{{ _("Payment Already Made") }}</div>
{% else %}
<div class="card-header">{{ _("Make Payment") }}</div>
{% endif %}
<div class="card-body">
{% if invoice %}
<form method="post" action="{% url 'payment_create' pk=invoice.pk %}">