add ledger and journalentry

This commit is contained in:
gitea 2025-03-11 21:36:19 +00:00
parent 55167f2cc1
commit 68fb46cf65
24 changed files with 1093 additions and 30 deletions

View File

@ -6,7 +6,6 @@ class InventoryConfig(AppConfig):
def ready(self):
import inventory.signals
# from decimal import Decimal
# from inventory.models import VatRate
# VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)
from decimal import Decimal
from inventory.models import VatRate
VatRate.objects.get_or_create(rate=Decimal('0.15'), is_active=True)

View File

@ -21,7 +21,9 @@ from django_ledger.forms.estimate import (
EstimateModelCreateForm as EstimateModelCreateFormBase,
)
# from django_ledger.forms.ledger import LedgerModelCreateForm as LedgerModelCreateFormBase
from django_ledger.forms.bill import BillModelCreateForm as BillModelCreateFormBase
from django_ledger.forms.journal_entry import JournalEntryModelCreateForm as JournalEntryModelCreateFormBase
from .models import (
Dealer,
@ -953,3 +955,10 @@ class DealersMakeForm(forms.Form):
for car_make in self.cleaned_data["car_makes"]:
DealersMake.objects.create(dealer=self.dealer, car_make=car_make)
class JournalEntryModelCreateForm(JournalEntryModelCreateFormBase):
pass
# class LedgerModelCreateForm(LedgerModelCreateFormBase):
# pass

View File

@ -82,11 +82,6 @@ def create_car_location(sender, instance, created, **kwargs):
except Exception as e:
print(f"Failed to create CarLocation for car {instance.vin}: {e}")
@receiver(post_save, sender=models.Dealer)
def create_dealer_settings(sender, instance, created, **kwargs):
if created:
models.DealerSettings.objects.create(dealer=instance)
# Create Entity
@receiver(post_save, sender=models.Dealer)
def create_ledger_entity(sender, instance, created, **kwargs):
@ -625,7 +620,6 @@ def create_ledger_entity(sender, instance, created, **kwargs):
entity.create_account(coa_model=coa, code="6303", role=roles.EXPENSE_OTHER, name=_("Foreign Currency Translation"), balance_type="debit", active=True)
entity.create_account(coa_model=coa, code="6304", role=roles.EXPENSE_OTHER, name=_("Interest Expenses"), balance_type="debit", active=True)
@receiver(post_save, sender=models.Dealer)
def create_dealer_groups(sender, instance, created, **kwargs):
@ -872,6 +866,24 @@ def update_car_status_on_reservation_update(sender, instance, **kwargs):
car.status = models.CarStatusChoices.AVAILABLE
car.save()
@receiver(post_save, sender=models.Dealer)
def create_dealer_settings(sender, instance, created, **kwargs):
if created:
models.DealerSettings.objects.create(
dealer=instance,
invoice_cash_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH).first(),
invoice_prepaid_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_RECEIVABLES).first(),
invoice_unearned_account=instance.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE).first(),
bill_cash_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_CASH).first(),
bill_prepaid_account=instance.entity.get_all_accounts().filter(role=roles.ASSET_CA_PREPAID).first(),
bill_unearned_account=instance.entity.get_all_accounts().filter(role=roles.LIABILITY_CL_ACC_PAYABLE).first()
)
@receiver(post_save, sender=models.Dealer)
def check_if_vat_exists(sender, instance, created, **kwargs):
if created:
models.VatRate.objects.get_create(is_active=True)
# @receiver(post_save, sender=EstimateModel)
# def update_estimate_status(sender, instance,created, **kwargs):

View File

@ -13,6 +13,7 @@ from django import template
from django.db.models import Sum
from django.urls import reverse
from django.utils.formats import number_format
from decimal import Decimal
# from django_ledger import __version__
# from django_ledger.forms.app_filters import EntityFilterForm, ActivityFilterForm
@ -27,7 +28,9 @@ from django_ledger.io.io_core import validate_activity, get_localdate
register = template.Library()
@register.filter()
def to_int(value):
return Decimal(value).quantize(Decimal("0.01"))
# @register.simple_tag(name='current_version')
# def current_version():
# return __version__

View File

@ -407,6 +407,33 @@ urlpatterns = [
name="representative_delete",
),
# Ledger URLS
# Ledger
path(
"ledgers/", views.LedgerModelListView.as_view(), name="ledger_list"
),
path(
"ledgers/<slug:entity_slug>/detail/<uuid:invoice_pk>/", views.LedgerModelDetailView.as_view(), name="ledger_detail"
),
# path(
# "ledgers/create/", views.LedgerModelCreateView.as_view(), name="ledger_create"
# ),
path(
"journalentries/<uuid:pk>/list/", views.JournalEntryListView.as_view(), name="journalentry_list"
),
path(
"journalentries/<uuid:pk>/create/", views.JournalEntryCreateView.as_view(), name="journalentry_create"
),
path(
"journalentries/<uuid:pk>/delete/", views.JournalEntryDeleteView, name="journalentry_delete"
),
path(
"journalentries/<uuid:pk>/transactions/",
views.JournalEntryTransactionsView,
name="journalentry_transactions",
),
path('journalentries/<slug:entity_slug>/<uuid:ledger_pk>/detail/<uuid:je_pk>/txs/',
views.JournalEntryModelTXSDetailView.as_view(),
name='journalentry_txs'),
# Bank Account
path(
"bank_accounts/", views.BankAccountListView.as_view(), name="bank_account_list"
@ -597,6 +624,7 @@ urlpatterns = [
name="bill_mark_as_paid",
),
# orders
path("orders/", views.OrderListView.as_view(), name="order_list_view"),

View File

@ -48,12 +48,15 @@ from django.views.generic import (
UpdateView,
DeleteView,
TemplateView,
ArchiveIndexView,
)
#####################################################################
# Django Ledger
from django_ledger.io import roles
from django_ledger.utils import accruable_net_summary
from django_ledger.views.invoice import InvoiceModelDetailView as InvoiceModelDetailViewBase
from django_ledger.views import LedgerModelListView as LedgerModelListViewBase,JournalEntryModelTXSDetailView as JournalEntryModelTXSDetailViewBase
from django_ledger.forms.account import AccountModelCreateForm, AccountModelUpdateForm
from django_ledger.views.entity import EntityModelDetailBaseView,EntityModelDetailHandlerView
from django_ledger.forms.item import (
@ -85,6 +88,7 @@ from django_ledger.models import (
CustomerModel,
ItemModel,
BillModel,
LedgerModel,
VendorModel,
)
from django_ledger.views.financial_statement import (
@ -2569,6 +2573,8 @@ def invoice_create(request, pk):
invoice.save()
messages.success(request, "Invoice created successfully!")
return redirect("invoice_detail", pk=invoice.pk)
else:
print(form.errors)
form = forms.InvoiceModelCreateForm(
entity_slug=entity.slug, user_model=entity.admin
)
@ -3993,7 +3999,7 @@ class CarListViewTable(LoginRequiredMixin, ExportMixin, SingleTableView):
@login_required
def DealerSettingsView(request,pk):
dealer_setting = get_object_or_404(models.DealerSettings, pk=pk)
dealer_setting = get_object_or_404(models.DealerSettings, dealer__pk=pk)
dealer = get_user_type(request)
if request.method == 'POST':
form = forms.DealerSettingsForm(request.POST, instance=dealer_setting)
@ -4039,3 +4045,121 @@ def assign_car_makes(request):
form = forms.DealersMakeForm(initial={"car_makes": existing_car_makes}, dealer=dealer)
return render(request, "dealers/assign_car_makes.html", {"form": form})
class LedgerModelListView(LoginRequiredMixin, ListView,ArchiveIndexView):
model = LedgerModel
context_object_name = "ledgers"
template_name = "ledger/ledger/ledger_list.html"
date_field = 'created'
ordering = '-created'
show_all = False
show_current = False
show_visible = False
def get_queryset(self):
qs = super().get_queryset()
dealer = get_user_type(self.request)
qs = qs.filter(entity=dealer.entity)
qs = qs.select_related('billmodel', 'invoicemodel')
qs = qs.order_by('-created')
if self.show_all:
return qs
if self.show_current:
qs = qs.current()
if self.show_visible:
qs = qs.visible()
return qs
class LedgerModelDetailView(InvoiceModelDetailViewBase):
model = LedgerModel
context_object_name = "ledger"
template_name = "ledger/ledger/ledger_detail.html"
# class LedgerModelCreateView(LoginRequiredMixin,SuccessMessageMixin, CreateView):
# model = LedgerModel
# template_name = "ledger/ledger/ledger_form.html"
# form_class = forms.LedgerModelCreateForm
# success_message = "Ledger created"
# def get_form(self, form_class=None):
# dealer = get_user_type(self.request)
# form = forms.LedgerModelCreateForm(entity_slug=dealer.entity.slug,user_model=dealer.entity.admin,**self.get_form_kwargs())
# return form
# def get_success_url(self):
# return reverse('ledger_list')
# def form_valid(self, form):
# instance = form.save(commit=False)
# dealer = get_user_type(self.request)
# instance.entity = dealer.entity
# instance.save()
# return super().form_valid(form)
class JournalEntryListView(LoginRequiredMixin, ListView):
model = JournalEntryModel
context_object_name = "journal_entries"
template_name = "ledger/journal_entry/journal_entry_list.html"
def get_queryset(self):
qs = super().get_queryset()
ledger = LedgerModel.objects.filter(pk=self.kwargs['pk']).first()
qs = qs.filter(ledger=ledger)
return qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['ledger'] = LedgerModel.objects.filter(pk=self.kwargs['pk']).first()
return context
class JournalEntryCreateView(LoginRequiredMixin,SuccessMessageMixin, CreateView):
model = JournalEntryModel
template_name = "ledger/journal_entry/journal_entry_form.html"
form_class = forms.JournalEntryModelCreateForm
ledger_model = None
success_message = "Journal Entry created"
def get_form(self, form_class=None):
dealer = get_user_type(self.request)
ledger = LedgerModel.objects.filter(pk=self.kwargs['pk']).first()
form = forms.JournalEntryModelCreateForm(
entity_model=dealer.entity,
ledger_model=ledger,
**self.get_form_kwargs()
)
form.fields.pop('entity_unit')
return form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["ledger"] = LedgerModel.objects.filter(pk=self.kwargs['pk']).first()
return context
def get_success_url(self):
ledger = LedgerModel.objects.filter(pk=self.kwargs['pk']).first()
return reverse("journalentry_list", kwargs={"pk": ledger.pk})
def JournalEntryDeleteView(request,pk):
journal_entry = get_object_or_404(JournalEntryModel, pk=pk)
ledger = journal_entry.ledger
journal_entry.delete()
messages.success(request, 'Journal Entry deleted')
return redirect("journalentry_list", pk=ledger.pk)
def JournalEntryTransactionsView(request, pk):
journal = JournalEntryModel.objects.filter(pk=pk).first()
transactions = (
TransactionModel.objects.filter(journal_entry=journal)
.order_by("account__code")
.all()
)
return render(
request,
"ledger/journal_entry/journal_entry_transactions.html",
{"journal_entry": journal, "transactions": transactions},
)
class JournalEntryModelTXSDetailView(JournalEntryModelTXSDetailViewBase):
template_name = 'ledger/journal_entry/journal_entry_txs.html'

View File

@ -249,6 +249,14 @@
</li>
{% endif %}
{% if perms.django_ledger.view_itemmodel %}
<li class="nav-item">
<a class="nav-link" href="{% url 'ledger_list' %}">
<div class="d-flex align-items-center">
<span class="nav-link-icon"><span class="fas fa-book"></span></span><span class="nav-link-text">{% trans "Ledgers"|capfirst %}</span>
</div>
</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{% url 'item_service_list' %}">
<div class="d-flex align-items-center">
@ -256,7 +264,6 @@
</div>
</a>
</li>
{% endif %}
{% if perms.django_ledger.view_itemmodel %}
<li class="nav-item">
<a class="nav-link" href="{% url 'item_expense_list' %}">
@ -452,7 +459,6 @@
<div class="card position-relative border-0">
<div class="card-body p-0">
<div class="text-center pt-4 pb-3">
<div class="avatar avatar-xl">
{% if user.dealer.logo %}
<img class="rounded-circle" src="{{ user.dealer.logo.url }}" alt="" />

View File

@ -11,7 +11,7 @@
{% 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">
<div class="d-flex flex-column flex-sm-grow-1 p-4">
<main class="d-grid gap-4 p-1">
<!-- Search Bar -->
<div class="row g-4">

View File

@ -0,0 +1,149 @@
{% load django_ledger %}
{% load i18n %}
{% if not create_invoice %}
{% if style == 'dashboard' %}
<div class="card">
<div class="card-body">
<p class="text-muted text-end">
<span class="me-2">{% icon "bi:cash-stack" 16 %}</span>
{% trans 'Invoice' %}
</p>
<h3 class="card-title">{{ invoice.customer.customer_name }}</h3>
<p class="text-muted">{{ invoice.customer.address_1 }}</p>
{% if not invoice.is_past_due %}
<p class="h5 text-info">{% trans 'Due in' %}: {{ invoice.date_due | timeuntil }}</p>
{% else %}
<p class="text-danger fw-bold h5">Past Due: {{ invoice.date_due | timesince }} ago</p>
{% endif %}
{% if invoice.accrue %}
<p>Accrue: <span class="text-success">{% icon 'ant-design:check-circle-filled' 24 %}</span></p>
{% else %}
<p>Accrue: <span class="text-danger">{% icon 'maki:roadblock-11' 24 %}</span></p>
{% endif %}
<p class="h5 text-success">Owed to You: {% currency_symbol %}{{ invoice.get_amount_open | currency_format }}</p>
<p>Amount Paid: {% currency_symbol %}{{ invoice.amount_paid | currency_format }}</p>
<p>Progressed: {{ invoice.get_progress | percentage }}</p>
<div class="progress my-3">
<div class="progress-bar bg-success" role="progressbar" style="width: {{ invoice.get_progress_percent }}%" aria-valuenow="{{ invoice.get_progress_percent }}" aria-valuemin="0" aria-valuemax="100">{{ invoice.get_progress | percentage }}</div>
</div>
{% modal_action invoice 'get' entity_slug %}
</div>
<div class="card-footer d-flex justify-content-between">
<a href="#" class="btn btn-link text-primary">{% trans 'View' %}</a>
<a href="#" class="btn btn-link text-warning">{% trans 'Update' %}</a>
{% if not invoice.is_paid %}
<a onclick="djLedger.toggleModal('{{ invoice.get_html_id }}')" class="btn btn-link text-info">{% trans 'Mark as Paid' %}</a>
{% endif %}
</div>
</div>
{% elif style == 'invoice-detail' %}
<div class="card">
<div class="card-header">
<h2 class="card-title h3">
<span class="me-2">{% icon 'uil:bill' 36 %}</span>
{% trans 'Invoice Info' %}
</h2>
</div>
<div class="card-body text-center">
{% if invoice.is_draft %}
<h3 class="h3 text-warning fw-bold">{% trans 'This invoice is' %} {{ invoice.get_invoice_status_display }}</h3>
<p class="h3">{% trans 'Amount Due' %}: <span class="fw-bold">{% currency_symbol %}{{ invoice.amount_due | currency_format }}</span></p>
<p class="h3">{% trans 'Due Date' %}: <span class="fw-bold">{{ invoice.date_due | timeuntil }}</span></p>
<p class="h3">{% trans 'Is Accrued' %}:
{% if invoice.accrue %}
<span class="text-success">{% icon 'ant-design:check-circle-filled' 24 %}</span>
{% else %}
<span class="text-danger">{% icon 'maki:roadblock-11' 24 %}</span>
{% endif %}
</p>
{% elif invoice.is_review %}
<h3 class="h3 text-warning fw-bold">{% trans 'This invoice is' %} {{ invoice.get_invoice_status_display }}</h3>
<p class="h3">{% trans 'Amount Due' %}: <span class="fw-bold">{% currency_symbol %}{{ invoice.amount_due | currency_format }}</span></p>
<p class="h3">{% trans 'Due Date' %}: <span class="fw-bold">{{ invoice.date_due | timeuntil }}</span></p>
<p class="h3">{% trans 'Is Accrued' %}:
{% if invoice.accrue %}
<span class="text-success">{% icon 'ant-design:check-circle-filled' 24 %}</span>
{% else %}
<span class="text-danger">{% icon 'maki:roadblock-11' 24 %}</span>
{% endif %}
</p>
{% if invoice.xref %}
<p class="h5 fst-italic">{% trans 'External Ref' %}: {{ invoice.xref }}</p>
{% endif %}
{% elif invoice.is_approved %}
<h3 class="h3 text-info fw-bold">{% trans 'This invoice is' %} {{ invoice.get_invoice_status_display }}</h3>
<p class="h3">{% trans 'Amount Due' %}: <span class="fw-bold">{% currency_symbol %}{{ invoice.amount_due | currency_format }}</span></p>
<p class="h3">{% trans 'Due Date' %}: <span class="fw-bold">{{ invoice.date_due | timeuntil }}</span></p>
<p class="h3">{% trans 'Is Accrued' %}:
{% if invoice.accrue %}
<span class="text-success">{% icon 'ant-design:check-circle-filled' 24 %}</span>
{% else %}
<span class="text-danger">{% icon 'maki:roadblock-11' 24 %}</span>
{% endif %}
</p>
<p class="h3 fw-bold">{% trans 'Amount Paid' %}: {% currency_symbol %}{{ invoice.amount_paid | currency_format }}</p>
<p class="h5">{% trans 'Progressed' %}: {{ invoice.get_progress | percentage }}</p>
<div class="progress my-3">
<div class="progress-bar bg-success" role="progressbar" style="width: {{ invoice.get_progress_percent }}%" aria-valuenow="{{ invoice.get_progress_percent }}" aria-valuemin="0" aria-valuemax="100">{{ invoice.get_progress | percentage }}</div>
</div>
{% elif invoice.is_paid %}
<h3 class="h3 text-success fw-bold">{% trans 'This invoice is' %} {{ invoice.get_invoice_status_display }}</h3>
<p class="h3">{% trans 'Amount Paid' %}: <span class="fw-bold">{% currency_symbol %}{{ invoice.amount_paid | currency_format }}</span></p>
<p class="h3">{% trans 'Paid Date' %}: <span class="fw-bold">{{ invoice.date_paid | date }}</span></p>
{% else %}
<p class="h3">Invoice Amount: <span class="fw-bold">{% currency_symbol %}{{ invoice.amount_due | currency_format }}</span></p>
<p class="h3 text-danger">{{ invoice.get_invoice_status_display | upper }}</p>
{% endif %}
</div>
<div class="card-footer d-flex justify-content-between">
{# MARK DRAFT #}
{% if invoice.can_draft %}
<a onclick="djLedger.toggleModal('{{ invoice.get_mark_as_draft_html_id }}')" class="btn btn-link text-info">{% trans 'Mark as Draft' %}</a>
{% modal_action_v2 invoice invoice.get_mark_as_draft_url invoice.get_mark_as_draft_message invoice.get_mark_as_draft_html_id %}
{% endif %}
{# MARK REVIEW #}
{% if invoice.can_review %}
<a onclick="djLedger.toggleModal('{{ invoice.get_mark_as_review_html_id }}')" class="btn btn-link text-info">{% trans 'Mark as Review' %}</a>
{% modal_action_v2 invoice invoice.get_mark_as_review_url invoice.get_mark_as_review_message invoice.get_mark_as_review_html_id %}
{% endif %}
{# MARK APPROVED #}
{% if invoice.can_approve %}
<a onclick="djLedger.toggleModal('{{ invoice.get_mark_as_approved_html_id }}')" class="btn btn-link text-success">{% trans 'Approve' %}</a>
{% modal_action_v2 invoice invoice.get_mark_as_approved_url invoice.get_mark_as_approved_message invoice.get_mark_as_approved_html_id %}
{% endif %}
{# MARK PAID #}
{% if invoice.can_pay %}
<a onclick="djLedger.toggleModal('{{ invoice.get_mark_as_paid_html_id }}')" class="btn btn-link text-success">{% trans 'Mark as Paid' %}</a>
{% modal_action_v2 invoice invoice.get_mark_as_paid_url invoice.get_mark_as_paid_message invoice.get_mark_as_paid_html_id %}
{% endif %}
{# MARK VOID #}
{% if invoice.can_void %}
<a onclick="djLedger.toggleModal('{{ invoice.get_mark_as_void_html_id }}')" class="btn btn-link text-danger">{% trans 'Void' %}</a>
{% modal_action_v2 invoice invoice.get_mark_as_void_url invoice.get_mark_as_void_message invoice.get_mark_as_void_html_id %}
{% endif %}
{# MARK CANCELED #}
{% if invoice.can_cancel %}
<a onclick="djLedger.toggleModal('{{ invoice.get_mark_as_canceled_html_id }}')" class="btn btn-link text-danger fw-bold">{% trans 'Cancel' %}</a>
{% modal_action_v2 invoice invoice.get_mark_as_canceled_url invoice.get_mark_as_canceled_message invoice.get_mark_as_canceled_html_id %}
{% endif %}
</div>
</div>
{% endif %}
{% else %}
<div class="card text-center">
<div class="card-body">
<a href="#">
<span class="text-muted">{% icon "ic:baseline-add-circle-outline" 48 %}</span>
</a>
<h2 class="h3 text-muted">{% trans 'New Invoice' %}</h2>
</div>
</div>
{% endif %}

View File

@ -0,0 +1,58 @@
{% load django_ledger %}
{% load i18n %}
<div class="card">
<div class="card-header">
<h2 class="card-header-title display-4">{% trans 'Journal Entry Detail' %}</h2>
</div>
<div class="card-body">
<h2 class="display-4 text-success">{{ journal_entry.je_number }}</h2>
{% if journal_entry.entity_unit %}
<h2 class="display-4 font-weight-light">{{ journal_entry.entity_unit.name }}</h2>
{% endif %}
<h2 class="display-4">{% trans 'Date' %}: {{ journal_entry.timestamp | date }}</h2>
<h3 class="h4">{% trans 'Posted' %}:
{% if journal_entry.is_posted %}
<span class="text-success">{% icon 'ant-design:check-circle-filled' 24 %}</span>
{% else %}
<span class="text-danger">{% icon 'maki:roadblock-11' 24 %}</span>
{% endif %}
</h3>
<h3 class="h4">{% trans 'Locked' %}:
{% if journal_entry.is_locked %}
<span class="text-success">{% icon 'ant-design:check-circle-filled' 24 %}</span>
{% else %}
<span class="text-danger">{% icon 'maki:roadblock-11' 24 %}</span>
{% endif %}
</h3>
{% if journal_entry.activity %}
<h3 class="h3">{% trans 'Activity' %}: {{ journal_entry.get_activity_display }}</h3>
{% endif %}
{% if journal_entry.description %}
<h4 class="h4 font-weight-light">{{ journal_entry.description }}</h4>
{% endif %}
</div>
<div class="card-footer">
<div class="d-flex justify-content-between">
{% if journal_entry.can_lock %}
<a href="{{ journal_entry.get_lock_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}"
class="btn btn-success font-weight-bold">{% trans 'Lock' %}</a>
{% endif %}
{% if journal_entry.can_unlock %}
<a href="{{ journal_entry.get_unlock_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}"
class="btn btn-warning font-weight-bold">{% trans 'UnLock' %}</a>
{% endif %}
{% if journal_entry.can_post %}
<a href="{{ journal_entry.get_post_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}"
class="btn btn-success font-weight-bold">{% trans 'Post' %}</a>
{% endif %}
{% if journal_entry.can_unpost %}
<a href="{{ journal_entry.get_unpost_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}"
class="btn btn-danger font-weight-bold">{% trans 'UnPost' %}</a>
{% endif %}
</div>
</div>
</div>

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n static %}
{% block title %}{{ _("Create Journal Entry") }}{% endblock title %}
{% block content %}
<div class="row mt-4">
<h3 class="text-center">{% trans "Create Journal Entry" %}</h3>
<form id="mainForm" method="post" class="needs-validation">
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
</div>
<div class="mt-5 text-center">
<button type="submit" class="btn btn-success me-2"><i class="fa-solid fa-floppy-disk"></i>{% trans "Save" %}</button>
<a href="{% url 'journalentry_list' ledger.pk %}" class="btn btn-secondary"><i class="fa-solid fa-ban"></i> {% trans "Cancel" %}</a>
</div>
</form>
</div>
{% endblock content %}

View File

@ -0,0 +1,119 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ _("Journal Entries") }}{% endblock title %}
{% block content %}
<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 justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h5 class="mmb-0 me-2 text-warning-dark" id="confirmModalLabel">
<i class="fas fa-exclamation-circle text-warning-dark ms-2"></i>
{% trans 'Confirm' %}</h5>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close">
<span class="fas fa-times"></span>
</button>
</div>
<div class="modal-body">
{% trans 'Are you sure ?' %}
<div class="modal-footer flex justify-content-center border-top-0">
<form id="confirmForm" method="POST" action="" class="form">
{% csrf_token %}
<div class="container-fluid m-0 p-0">
<button type="button" class="btn btn-danger btn-sm" data-bs-dismiss="modal"><i class="fa-solid fa-ban"></i> {% trans 'No' %}</button>
<button type="submit" class="btn btn-success btn-sm"><i class="fa-solid fa-circle-check"></i> {% trans "Yes" %}</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Journal Entries" %}</h3>
<a href="{% url 'journalentry_create' ledger.pk %}" class="btn btn-sm btn-phoenix-primary ">{% trans "Add Journal Entry" %}</a>
</div>
<div class="table-responsive px-1 scrollbar">
<table class="table fs-9 mb-0 border-top border-translucent">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Document Number" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Timestamp" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Activity" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Description" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Posted" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Locked" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Transaction Count" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th>
</tr>
</thead>
<tbody class="list">
{% for je in journal_entries %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap">{{ je.je_number }}</td>
<td class="align-middle product white-space-nowrap">{{ je.timestamp }}</td>
<td class="align-middle product white-space-nowrap">
{% if je.get_activity_display %}
{{ je.get_activity_display }}
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">{{ je.description }}</td>
<td class="align-middle product white-space-nowrap">
{% if je.is_posted %}
<i class="fa-solid fa-square-check text-success"></i>
{% else %}
<i class="fa-solid fa-circle-xmark text-danger"></i>
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{% if je.is_locked %}
<i class="fa-solid fa-lock text-success"></i>
{% else %}
<i class="fa-solid fa-unlock text-danger"></i>
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{{ je.txs_count }}
</td>
<td class="align-middle white-space-nowrap text-start">
<div class="btn-reveal-trigger position-static">
<button
class="btn btn-sm dropdown-toggle dropdown-caret-none transition-none btn-reveal fs-10"
type="button"
data-bs-toggle="dropdown"
data-boundary="window"
aria-haspopup="true"
aria-expanded="false"
data-bs-reference="parent">
<span class="fas fa-ellipsis-h fs-10"></span>
</button>
<div class="dropdown-menu dropdown-menu-end py-2">
<a class="dropdown-item" href="#">{% trans "View" %}</a>
<a class="dropdown-item" href="#">{% trans "Edit" %}</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'journalentry_delete' je.pk %}">{% trans "Delete" %}</a>
<a class="dropdown-item" href="{% url 'journalentry_transactions' je.pk %}">{% trans "View" %}</a>
<a class="dropdown-item" href="{% url 'journalentry_txs' je.entity_slug je.ledger_id je.pk %}">{% trans "Transactions" %}</a>
</div>
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center">{% trans "No Bank Accounts Found" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-center">
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,49 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ _("Transactions") }}{% endblock title %}
{% block content %}
<div class="row mt-4">
<div class="col-12">
{% include 'ledger/journal_entry/includes/card_journal_entry.html' with journal_entry=journal_entry %}
</div>
<h3 class="mb-3 mt-5"><i class="fa-solid fa-right-left"></i> {% trans "Transactions" %}</h3>
<div class="table-responsive px-1 scrollbar">
<table class="table fs-9 mb-0 border-top border-translucent">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "#" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Timestamp" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Account Name" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Account Code" %}</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 "Credit" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Description" %}</th>
</thead>
<tbody class="list">
{% for transaction in transactions %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td>{{ forloop.counter }}</td>
<td class="align-middle product white-space-nowrap py-0">{{ transaction.created|date}}</td>
<td class="align-middle product white-space-nowrap">{{ transaction.account.name }}</td>
<td class="align-middle product white-space-nowrap">{{ transaction.account.code }}</td>
<td class="align-middle product white-space-nowrap text-success">{% if transaction.tx_type == "debit" %}<i class="fa-solid fa-circle-up"></i> {{ transaction.amount }}{{ CURRENCY }}{% endif %}</td>
<td class="align-middle product white-space-nowrap text-danger">{% if transaction.tx_type == "credit" %}<i class="fa-solid fa-circle-down"></i> {{ transaction.amount }}{{ CURRENCY }}{% endif %}</td>
<td class="align-middle product white-space-nowrap">{{ transaction.description }}</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center">{% trans "No Transactions Found" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-center">
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,99 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load crispy_forms_tags %}
{% block content %}
<div class="row justify-content-center">
<div class="col-12">
{% include 'ledger/journal_entry/includes/card_journal_entry.html' with journal_entry=journal_entry %}
</div>
<div class="col-12">
<div class="card">
<div class="card-body">
<form action="{{ view.request.path }}" method="post">
{% csrf_token %}
<div class="row">
<div class="col-12">
{% if txs_formset.non_form_errors %}
<div class="alert alert-subtle-warning" role="alert">
{{ txs_formset.non_form_errors }}
</div>
{% endif %}
{{ txs_formset.management_form|crispy }}
</div>
<div class="col-12">
<table class="table table-bordered">
<thead>
<tr>
<th>Account</th>
<th>TX Type</th>
<th>Amount</th>
<th>Description</th>
{% if txs_formset.can_delete %}
<th>Delete</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for f in txs_formset %}
<tr>
<td class="px-2">
{% for hidden_field in f.hidden_fields %}
{{ hidden_field }}
{% endfor %}
{{ f.account|as_crispy_field }}
</td>
<td>{{ f.tx_type|as_crispy_field }}</td>
<td>{{ f.amount|as_crispy_field }}</td>
<td>{{ f.description|as_crispy_field }}</td>
<td>
{% if txs_formset.can_delete %}
{{ f.DELETE|as_crispy_field }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="col-12 text-center">
<button class="btn btn-primary">
{% trans 'Save' %}
</button>
<a class="btn btn-secondary"
href="{% url 'journalentry_list' journal_entry.ledger_id %}">
{% trans 'Done' %}
</a>
{% if journal_entry.can_lock %}
<a class="btn btn-danger"
href="{{ journal_entry.get_action_lock_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}">
{% trans 'Lock' %}
</a>
{% endif %}
{% if journal_entry.can_unlock %}
<a class="btn btn-warning"
href="{{ journal_entry.get_action_unlock_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}">
{% trans 'UnLock' %}
</a>
{% endif %}
{% if journal_entry.can_post %}
<a class="btn btn-danger"
href="{{ journal_entry.get_action_post_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}">
{% trans 'Post' %}
</a>
{% endif %}
{% if journal_entry.can_unpost %}
<a class="btn btn-warning"
href="{{ journal_entry.get_action_unpost_url }}?next={% url 'journalentry_txs' journal_entry.entity_slug journal_entry.ledger_id journal_entry.pk %}">
{% trans 'UnPost' %}
</a>
{% endif %}
</div>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,155 @@
{% extends 'base.html' %}
{% load i18n %}
{% load static %}
{% load django_ledger %}
{% block content %}
<div class="row">
<div class="col-md-4">
<div class="row">
{{invoice}}
<div class="col-12 mb-4">
{% include 'ledger/journal_entry/includes/card_invoice.html' with invoice=invoice entity_slug=view.kwargs.entity_slug style='invoice-detail' %}
</div>
<div class="col-12 mb-4">
</div>
<div class="col-12">
<a class="btn btn-info btn-block"
href="#">
{% trans 'Invoice List' %}
</a>
</div>
</div>
</div>
<div class="col-md-8">
<div class="row">
<div class="col-12 mb-4">
<div class="d-flex justify-content-around text-center">
<div>
<p class="text-muted">{% trans 'Cash Account' %}:
<a href="#"
class="text-danger">{{ invoice.cash_account.code }}</a>
</p>
<p class="h4">
{% currency_symbol %}{{ invoice.get_amount_cash | absolute | currency_format }}</p>
</div>
{% if invoice.accrue %}
<div>
<p class="text-muted">{% trans 'Accounts Receivable' %}:
<a href="#"
class="text-danger">{{ invoice.prepaid_account.code }}</a>
</p>
<p class="h4 text-success">
{% currency_symbol %}{{ invoice.get_amount_prepaid | currency_format }}</p>
</div>
<div>
<p class="text-muted">{% trans 'Deferred Revenue' %}:
<a href="#"
class="text-danger">{{ invoice.unearned_account.code }}</a>
</p>
<p class="h4 text-danger">
{% currency_symbol %}{{ invoice.get_amount_unearned | currency_format }}</p>
</div>
<div>
<p class="text-muted">Accrued {{ invoice.get_progress_percent }}%</p>
<p class="h4">
{% currency_symbol %}{{ invoice.get_amount_earned | currency_format }}</p>
</div>
{% else %}
<div>
<p class="text-muted">You Are Owed</p>
<p class="h4 text-success">
{% currency_symbol %}{{ invoice.get_amount_open | currency_format }}</p>
</div>
{% endif %}
</div>
</div>
<div class="col-12 mb-4">
<div class="card">
<div class="card-header">
<h2 class="card-title h3">
<span class="me-2">{% icon 'grommet-icons:transaction' 36 %}</span>
{% trans 'Invoice Items' %}
</h2>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>{% trans 'Item' %}</th>
<th>{% trans 'Unit Cost' %}</th>
<th>{% trans 'Quantity' %}</th>
<th>{% trans 'Total' %}</th>
</tr>
</thead>
<tbody>
{% for invoice_item in itemtxs_qs %}
<tr>
<td>{{ invoice_item.item_model }}</td>
<td>{% currency_symbol %}{{ invoice_item.unit_cost | currency_format }}</td>
<td>{{ invoice_item.quantity }}</td>
<td>
{% currency_symbol %}{{ invoice_item.total_amount | currency_format }}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<th colspan="3">{% trans 'Total' %}</th>
<th>
{% currency_symbol %}{{ total_amount_due | currency_format }}
</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
{% if invoice.is_active %}
<div class="col-12 mb-4">
<div class="d-flex justify-content-center gap-2">
<a href="#"
class="btn btn-info">{% trans 'Balance Sheet' %}</a>
<a href="#"
class="btn btn-info">{% trans 'Income Statement' %}</a>
<a href="#"
class="btn btn-info">{% trans 'Cash Flow Statement' %}</a>
</div>
<div class="col-12 mt-3">
<div class="d-flex justify-content-center gap-2">
<a href="#"
class="btn btn-success">
{% trans 'Balance Sheet PDF' %}{% icon 'bytesize:download' 24 %}</a>
<a href="#"
class="btn btn-success">
{% trans 'Income Statement PDF' %}{% icon 'bytesize:download' 24 %}</a>
<a href="#"
class="btn btn-success">
{% trans 'Cash Flow Statement PDF' %}{% icon 'bytesize:download' 24 %}</a>
</div>
</div>
</div>
{% endif %}
<div class="col-12 mb-4">
<div class="card">
<div class="card-header">
<h2 class="card-title h3">
<span class="me-2">{% icon 'grommet-icons:transaction' 36 %}</span>
{% trans 'Invoice Transactions' %}
</h2>
</div>
<div class="card-body">
</div>
</div>
</div>
<div class="col-12">
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,21 @@
{% extends "base.html" %}
{% load crispy_forms_filters %}
{% load i18n static %}
{% block title %}{{ _("Create Ledger") }}{% endblock title %}
{% block content %}
<div class="row mt-4">
<h3 class="text-center">{% trans "Create Ledger" %}</h3>
<form id="mainForm" method="post" class="needs-validation">
{% csrf_token %}
<div class="row g-3">
{{ form|crispy }}
</div>
<div class="mt-5 text-center">
<button type="submit" class="btn btn-success me-2"><i class="fa-solid fa-floppy-disk"></i>{% trans "Save" %}</button>
<a href="{% url 'ledger_list' %}" class="btn btn-secondary"><i class="fa-solid fa-ban"></i> {% trans "Cancel" %}</a>
</div>
</form>
</div>
{% endblock content %}

View File

@ -0,0 +1,71 @@
{% extends "base.html" %}
{% load i18n static %}
{% block title %}{{ _("Ledger") }}{% endblock title %}
{% block content %}
<div class="row mt-4">
<div class="d-flex justify-content-between mb-2">
<h3 class="">{% trans "Ledger" %}</h3>
</div>
<div class="table-responsive px-1 scrollbar">
<table class="table fs-9 mb-0 border-top border-translucent">
<thead>
<tr>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Ledger Name" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Journal Entries" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Earliest Date" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Posted" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Locked" %}</th>
<th class="sort white-space-nowrap align-middle" scope="col">{% trans "Action" %}</th>
</tr>
</thead>
<tbody class="list">
{% for ledger in ledgers %}
<tr class="hover-actions-trigger btn-reveal-trigger position-static">
<td class="align-middle product white-space-nowrap">
<a href="#">{{ ledger.get_wrapped_model_instance }}</a>
</td>
<td class="align-middle product white-space-nowrap">
<a class="btn btn-sm btn-primary"
href="{% url 'journalentry_list' ledger.pk %}">
<i class="fa-solid fa-right-left"></i>
<span>
<span class="has-text-weight-bold">{{ ledger.journal_entries__count }}</span>
<span>{{ _('Journal Entries') }}</span>
</span>
</a>
</td>
<td class="align-middle product white-space-nowrap">
{% if ledger.earliest_timestamp %}{{ ledger.earliest_timestamp | date }}{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{% if ledger.is_posted %}
<i class="fa-solid fa-square-check text-success"></i>
{% else %}
<i class="fa-solid fa-circle-xmark text-danger"></i>
{% endif %}
</td>
<td class="align-middle product white-space-nowrap">
{% if ledger.is_locked %}
<i class="fa-solid fa-lock text-success"></i>
{% else %}
<i class="fa-solid fa-unlock text-danger"></i>
{% endif %}
</td>
<td></td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center">{% trans "No Bank Accounts Found" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="d-flex justify-content-center">
</div>
</div>
{% endblock %}

View File

@ -4,6 +4,23 @@
{% block title %}{{ _("View Quotation") }}{% endblock title %}
{% block content %}
<!-- View PO Modal -->
<div class="modal fade" id="POModal" data-bs-keyboard="true" tabindex="-1" aria-labelledby="POModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header justify-content-between align-items-start gap-5 px-4 pt-4 pb-3 border-0">
<h4 class="mb-0 me-2 text-primary"><i class="fas text-info ms-2"></i></h4>
<button class="btn p-0 text-body-quaternary fs-6" data-bs-dismiss="modal" aria-label="Close"><span class="fas fa-times"></span></button>
</div>
<div class="modal-body p-4">
{% include "sales/orders/purchase_order.html" %}
</div>
<div class="modal-footer flex justify-content-center border-top-0">
</div>
</div>
</div>
</div>
<!-- Cancel Modal -->
<div class="modal fade" id="CancelModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-labelledby="CancelModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
@ -78,6 +95,7 @@
{% if estimate.invoicemodel_set.first %}
<a href="{% url 'invoice_detail' estimate.invoicemodel_set.first.pk %}" class="btn btn-primary btn-sm" type="button"><i class="fa-solid fa-receipt"></i>
{{ _("View Invoice")}}</a>
<button class="btn btn-phoenix-primary" data-bs-toggle="modal" data-bs-target="#POModal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-receipt"></i> {% trans 'View Purchase Order' %}</span></button>
{% endif %}
{% if estimate.status == 'draft' %}

View File

@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load i18n %}
{% load tenhal_tag %}
{% block title %}{{ _("View Estimate") }}{% endblock title %}
{% block customCSS %}
@ -88,11 +89,12 @@
<a href="{% url 'payment_create' invoice.pk %}" class="btn btn-phoenix-success"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-money-bill"></i> {% trans 'Record Payment' %}</span></a>
{% endif %}
{% if not invoice.is_paid %}
<button {% if invoice.is_review %}disabled{% endif %} id="mark_invoice_as_paid" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#mark_as_paid_Modal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-money-check-dollar"></i> {% trans 'Mark as Paid' %}</span></button>
<button {% if invoice.is_review or invoice.amount_paid|to_int < invoice.amount_due|to_int %}disabled{% endif %} id="mark_invoice_as_paid" class="btn btn-phoenix-secondary" data-bs-toggle="modal" data-bs-target="#mark_as_paid_Modal"><span class="d-none d-sm-inline-block"><i class="fa-solid fa-money-check-dollar"></i> {% trans 'Mark as Paid' %}</span></button>
{% endif %}
<a href="{% url 'invoice_preview' invoice.pk %}" class="btn btn-phoenix-primary"><span class="d-none d-sm-inline-block"><i class="fa-regular fa-eye"></i> {% trans 'Preview' %}</span></a>
</div>
</div>
{{invoice.amount_owned}}
<!-- ============================================-->
<div class="card mb-5 {% if invoice.is_review %}disabled{% endif %}">

View File

@ -0,0 +1,120 @@
{% block customCSS %}
<style>
.invoice {
width: 100%;
height: 400px; /* Fixed height */
display: flex;
flex-direction: column;
justify-content: space-between; /* Aligns content to top and bottom */
background-color: #fff;
padding: 1rem;
}
.invoice-items {
width: 100%;
}
.invoice-items td {
padding: 0.75rem;
border-top: 1px solid #dee2e6;
}
.invoice-items .total td {
font-weight: bold;
border-top: 2px solid #000;
}
.footer {
margin-top: 2rem;
text-align: center;
color: #6c757d;
}
.b-top {
border-top: 2px solid #000;
}
</style>
{% endblock %}
<div>
<div class="row justify-content-center px-12">
<button class="btn btn-primary" type="button" onclick="printDiv('printableArea')">
<i class="fa-solid fa-print"></i> {{ _('Print') }}
</button>
</div>
<div class="container" id="printableArea">
<div class="row justify-content-center">
<div class="col-md-10">
<div class="card mt-2">
<div class="card-body text-center">
<h2 class="card-title">{{ _('Purchase Order') }}</h2>
</div>
<div class="card-body">
<div class="invoice p-4">
<div class="mb-4">
<strong>{{ estimate.customer.customer_name }}</strong><br />
Order ID #{{ estimate.sale_orders.first.formatted_order_id }}<br />
{{ estimate.sale_orders.first.created|date }}
</div>
<table class="invoice-items table">
<thead>
<tr>
<th>Item</th>
<th class="text-end">Price</th>
</tr>
</thead>
<tbody>
<tr class="b-top"></tr>
{% for item in data.cars %}
<tr>
<td>{{ item.make }}</td>
<td class="text-end">{{ item.unit_price }}</td>
</tr>
{% endfor %}
<tr class="b-top">
<td>Additionals :</td>
</tr>
{% for service in data.additionals %}
<tr>
<td>{{ service.name }}</td>
<td class="text-end">{{ service.price_ }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card-body text-center">
<table class="invoice-items table">
<thead>
<tr>
<th></th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody>
<tr class="total">
<td class="text-end" width="80%"></td>
<td class="text-end">{{ data.grand_total }}</td>
</tr>
</tbody>
</table>
</div>
<div class="card-body text-center"></div>
</div>
<div class="mt-5">
<p>{{ _('Signature') }}:</p>
</div>
</div>
</div>
</div>
</div>
{% block customJS %}
<script>
function printDiv(divName) {
var printContents = document.getElementById(divName).innerHTML
var originalContents = document.body.innerHTML
document.body.innerHTML = printContents
window.print()
document.body.innerHTML = originalContents
}
</script>
{% endblock %}