From 02885f2e5b26d94dbb7bde68fe70d7906a3d0a2d Mon Sep 17 00:00:00 2001 From: ismail Date: Tue, 17 Jun 2025 19:59:51 +0300 Subject: [PATCH] add bill transaction table --- inventory/templatetags/custom_filters.py | 32 +++++++- templates/bill/bill_detail.html | 7 +- .../bill/transactions/tags/txs_table.html | 73 +++++++++++++++++++ templates/header.html | 9 ++- templates/inventory/car_list_view.html | 31 +++++++- 5 files changed, 145 insertions(+), 7 deletions(-) create mode 100644 templates/bill/transactions/tags/txs_table.html diff --git a/inventory/templatetags/custom_filters.py b/inventory/templatetags/custom_filters.py index 6813139f..72fb9be5 100644 --- a/inventory/templatetags/custom_filters.py +++ b/inventory/templatetags/custom_filters.py @@ -1,10 +1,13 @@ +from typing import Union from random import randint from django import template -from calendar import month_abbr from django.urls import reverse +from calendar import month_abbr +from django.conf import settings +from django.forms import ValidationError from django.utils.formats import number_format from django_ledger.io.io_core import get_localdate,validate_activity -from django.conf import settings +from django_ledger.models import InvoiceModel, JournalEntryModel, BillModel register = template.Library() @@ -390,3 +393,28 @@ def bill_item_formset_table(context, item_formset): 'total_amount__sum': context['total_amount__sum'], 'item_formset': item_formset, } + +@register.inclusion_tag('bill/transactions/tags/txs_table.html') +def transactions_table(object_type: Union[JournalEntryModel, BillModel, InvoiceModel], style='detail'): + if isinstance(object_type, JournalEntryModel): + transaction_model_qs = object_type.transactionmodel_set.all().with_annotated_details().order_by( + '-timestamp') + elif isinstance(object_type, BillModel): + transaction_model_qs = object_type.get_transaction_queryset(annotated=True).order_by('-timestamp') + elif isinstance(object_type, InvoiceModel): + transaction_model_qs = object_type.get_transaction_queryset(annotated=True).order_by('-timestamp') + else: + raise ValidationError( + 'Cannot handle object of type {} to get transaction model queryset'.format(type(object_type)) + ) + + total_credits = sum(tx.amount for tx in transaction_model_qs if tx.is_credit()) + total_debits = sum(tx.amount for tx in transaction_model_qs if tx.is_debit()) + + return { + 'style': style, + 'transaction_model_qs': transaction_model_qs, + 'total_debits': total_debits, + 'total_credits': total_credits, + 'object': object_type + } diff --git a/templates/bill/bill_detail.html b/templates/bill/bill_detail.html index 9fa08961..9abc9b17 100644 --- a/templates/bill/bill_detail.html +++ b/templates/bill/bill_detail.html @@ -2,6 +2,7 @@ {% load i18n %} {% load static %} {% load django_ledger %} +{% load custom_filters %} {% block title %}Bill Details - {{ block.super }}{% endblock %} @@ -64,7 +65,7 @@
{% trans 'Cash Account' %}: - {{ bill.cash_account.code }} @@ -79,7 +80,7 @@
{% trans 'Prepaid Account' %}: - {{ bill.prepaid_account.code }} @@ -93,7 +94,7 @@
{% trans 'Accounts Payable' %}: - {{ bill.unearned_account.code }} diff --git a/templates/bill/transactions/tags/txs_table.html b/templates/bill/transactions/tags/txs_table.html new file mode 100644 index 00000000..0e801373 --- /dev/null +++ b/templates/bill/transactions/tags/txs_table.html @@ -0,0 +1,73 @@ +{% load i18n %} +{% load django_ledger %} + +{% if style == 'detail' %} +
+ + + + + + + + + + + + + + {% for transaction_model in transaction_model_qs %} + + + + + + + + + + {% endfor %} + + + + + + + + +
{% trans 'Timestamp' %}{% trans 'Account' %}{% trans 'Account Name' %}{% trans 'Unit' %}{% trans 'Credit' %}{% trans 'Debit' %}{% trans 'Description' %}
{{ transaction_model.timestamp }}{{ transaction_model.account_code }}{{ transaction_model.account_name }}{% if transaction_model.entity_unit_name %}{{ transaction_model.entity_unit_name }}{% endif %}{% if transaction_model.is_credit %}${{ transaction_model.amount | currency_format }}{% endif %}{% if transaction_model.is_debit %}${{ transaction_model.amount | currency_format }}{% endif %}{% if transaction_model.description %}{{ transaction_model.description }}{% endif %}
{% trans 'Total' %}{% currency_symbol %}{{ total_credits | currency_format }}{% currency_symbol %}{{ total_debits | currency_format }}
+
+{% elif style == 'compact' %} +
+ + + + + + + + + + + + {% for transaction_model in transaction_model_qs %} + + + + + + + + {% endfor %} + + + + + + + + +
{% trans 'Account' %}{% trans 'Account Name' %}{% trans 'Credit' %}{% trans 'Debit' %}{% trans 'Description' %}
{{ transaction_model.account_code }}{{ transaction_model.account_name }}{% if transaction_model.is_credit %}${{ transaction_model.amount | currency_format }}{% endif %}{% if transaction_model.is_debit %}${{ transaction_model.amount | currency_format }}{% endif %}{% if transaction_model.description %}{{ transaction_model.description }}{% endif %}
{% trans 'Total' %}{% currency_symbol %}{{ total_credits | currency_format }}{% currency_symbol %}{{ total_debits | currency_format }}
+
+{% endif %} + diff --git a/templates/header.html b/templates/header.html index c66156b1..386f4a00 100644 --- a/templates/header.html +++ b/templates/header.html @@ -38,7 +38,14 @@ + diff --git a/templates/inventory/car_list_view.html b/templates/inventory/car_list_view.html index 0a71c589..7716231d 100644 --- a/templates/inventory/car_list_view.html +++ b/templates/inventory/car_list_view.html @@ -145,6 +145,10 @@ hx-on::after-request="filter_after_request()">{{ _("Search") }}
+
+ + +
+ +
+ +
+ {{ _("VIN") }} {{ _("Make") }} {{ _("Model") }} @@ -174,7 +183,12 @@ {% for car in cars %} - + + +
+ +
+ {{ car.vin }} @@ -297,5 +311,20 @@ document.querySelector('.car_status').removeAttribute('disabled') } + document.getElementById('select-all').addEventListener('change', function() { + const checkboxes = document.querySelectorAll('#project-list-table-body input[type="checkbox"]'); + checkboxes.forEach(checkbox => { + checkbox.checked = this.checked; + }); + }); + document.getElementById('car-checkbox').addEventListener('change', function() { + const form = document.querySelector('.update-price-form'); + if (this.checked) { + form.classList.remove('d-none'); + } else { + form.classList.add('d-none'); + } + }); + {% endblock customJS %}