final final
This commit is contained in:
parent
1fe85ff3ce
commit
cfa7d80ecc
Binary file not shown.
Binary file not shown.
121
accounting/templates/accounting/vat_report.html
Normal file
121
accounting/templates/accounting/vat_report.html
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container-fluid py-4">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||||
|
<div>
|
||||||
|
<h2 class="mb-0">{% trans "VAT Report" %} / تقرير ضريبة القيمة المضافة</h2>
|
||||||
|
<p class="text-muted">{% trans "Tax Declaration Summary" %} / ملخص الإقرار الضريبي</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onclick="window.print()" class="btn btn-outline-secondary">
|
||||||
|
<i class="bi bi-printer"></i> {% trans "Print" %} / طباعة
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Filter Form -->
|
||||||
|
<div class="card border-0 shadow-sm mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="get" class="row g-3 align-items-end">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">{% trans "Start Date" %} / تاريخ البدء</label>
|
||||||
|
<input type="date" name="start_date" class="form-control" value="{{ start_date }}">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">{% trans "End Date" %} / تاريخ الانتهاء</label>
|
||||||
|
<input type="date" name="end_date" class="form-control" value="{{ end_date }}">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
|
<i class="bi bi-filter"></i> {% trans "Generate Report" %} / إنشاء التقرير
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Report Content -->
|
||||||
|
<div class="row">
|
||||||
|
<!-- Sales / Output Tax -->
|
||||||
|
<div class="col-md-6 mb-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100">
|
||||||
|
<div class="card-header bg-light py-3">
|
||||||
|
<h5 class="card-title mb-0 text-primary">
|
||||||
|
1. {% trans "Sales (Output VAT)" %} / المبيعات (ضريبة المخرجات)
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<table class="table table-striped mb-0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="py-3">{% trans "Total Sales (Excl. VAT)" %} <br> <small class="text-muted">إجمالي المبيعات (غير شامل الضريبة)</small></td>
|
||||||
|
<td class="text-end py-3 fw-bold">{{ total_sales_subtotal|floatformat:3 }} {{ global_settings.currency_symbol }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="py-3">{% trans "Total VAT Collected" %} <br> <small class="text-muted">إجمالي الضريبة المحصلة</small></td>
|
||||||
|
<td class="text-end py-3 fw-bold text-danger">{{ total_output_vat|floatformat:3 }} {{ global_settings.currency_symbol }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-primary">
|
||||||
|
<td class="py-3">{% trans "Total Gross Sales" %} <br> <small class="text-muted">إجمالي المبيعات (شامل الضريبة)</small></td>
|
||||||
|
<td class="text-end py-3 fw-bold">{{ total_sales_gross|floatformat:3 }} {{ global_settings.currency_symbol }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Purchases / Input Tax -->
|
||||||
|
<div class="col-md-6 mb-4">
|
||||||
|
<div class="card border-0 shadow-sm h-100">
|
||||||
|
<div class="card-header bg-light py-3">
|
||||||
|
<h5 class="card-title mb-0 text-success">
|
||||||
|
2. {% trans "Purchases (Input VAT)" %} / المشتريات (ضريبة المدخلات)
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<table class="table table-striped mb-0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="py-3">{% trans "Total Purchases (Excl. VAT)" %} <br> <small class="text-muted">إجمالي المشتريات (غير شامل الضريبة)</small></td>
|
||||||
|
<td class="text-end py-3 fw-bold">{{ total_purchases_subtotal|floatformat:3 }} {{ global_settings.currency_symbol }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="py-3">{% trans "Total VAT Paid (Recoverable)" %} <br> <small class="text-muted">إجمالي الضريبة المدفوعة (القابلة للاسترداد)</small></td>
|
||||||
|
<td class="text-end py-3 fw-bold text-success">{{ total_input_vat|floatformat:3 }} {{ global_settings.currency_symbol }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="table-success">
|
||||||
|
<td class="py-3">{% trans "Total Gross Purchases" %} <br> <small class="text-muted">إجمالي المشتريات (شامل الضريبة)</small></td>
|
||||||
|
<td class="text-end py-3 fw-bold">{{ total_purchases_gross|floatformat:3 }} {{ global_settings.currency_symbol }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Net VAT Position -->
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card border-0 shadow-sm bg-primary text-white">
|
||||||
|
<div class="card-body text-center py-4">
|
||||||
|
<h4 class="mb-2">{% trans "Net VAT Payable / (Refundable)" %}</h4>
|
||||||
|
<h5 class="mb-3">صافي الضريبة المستحقة الدفع / (المستردة)</h5>
|
||||||
|
<h1 class="display-4 fw-bold mb-0">
|
||||||
|
{{ net_vat|floatformat:3 }} {{ global_settings.currency_symbol }}
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 mb-0 opacity-75">
|
||||||
|
{% if net_vat > 0 %}
|
||||||
|
{% trans "Amount to be paid to Tax Authority" %} / المبلغ المستحق للدفع للهيئة الضريبية
|
||||||
|
{% else %}
|
||||||
|
{% trans "Amount to be refunded from Tax Authority" %} / المبلغ المستحق للاسترداد من الهيئة الضريبية
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -9,6 +9,7 @@ urlpatterns = [
|
|||||||
path('journal-entries/', views.journal_entries, name='journal_entries'),
|
path('journal-entries/', views.journal_entries, name='journal_entries'),
|
||||||
path('journal-entries/manual/', views.manual_journal_entry, name='manual_journal_entry'),
|
path('journal-entries/manual/', views.manual_journal_entry, name='manual_journal_entry'),
|
||||||
path('ledger/<int:account_id>/', views.account_ledger, name='account_ledger'),
|
path('ledger/<int:account_id>/', views.account_ledger, name='account_ledger'),
|
||||||
|
path('reports/vat/', views.vat_report, name='vat_report'),
|
||||||
path('trial-balance/', views.trial_balance, name='trial_balance'),
|
path('trial-balance/', views.trial_balance, name='trial_balance'),
|
||||||
path('balance-sheet/', views.balance_sheet, name='balance_sheet'),
|
path('balance-sheet/', views.balance_sheet, name='balance_sheet'),
|
||||||
path('profit-loss/', views.profit_loss, name='profit_loss'),
|
path('profit-loss/', views.profit_loss, name='profit_loss'),
|
||||||
|
|||||||
@ -4,13 +4,71 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from .models import Account, JournalEntry, JournalItem
|
from .models import Account, JournalEntry, JournalItem
|
||||||
from .forms import AccountForm, JournalEntryForm
|
from .forms import AccountForm, JournalEntryForm
|
||||||
from django.db.models import Sum, Q, Value, DecimalField
|
from core.models import Sale, Purchase, Product
|
||||||
|
from django.db.models import Sum, Q, Value, DecimalField, F
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import datetime
|
from datetime import datetime, date
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def vat_report(request):
|
||||||
|
start_date = request.GET.get('start_date')
|
||||||
|
end_date = request.GET.get('end_date')
|
||||||
|
|
||||||
|
if not start_date:
|
||||||
|
start_date = timezone.now().replace(day=1).strftime('%Y-%m-%d')
|
||||||
|
if not end_date:
|
||||||
|
end_date = timezone.now().strftime('%Y-%m-%d')
|
||||||
|
|
||||||
|
# Convert strings to date objects for filtering
|
||||||
|
# Note: We filter by the day inclusive
|
||||||
|
|
||||||
|
sales = Sale.objects.filter(created_at__date__gte=start_date, created_at__date__lte=end_date).exclude(status='cancelled')
|
||||||
|
purchases = Purchase.objects.filter(created_at__date__gte=start_date, created_at__date__lte=end_date).exclude(status='cancelled').prefetch_related('items__product')
|
||||||
|
|
||||||
|
# Output VAT (Sales)
|
||||||
|
total_sales_subtotal = sales.aggregate(sum=Sum('subtotal'))['sum'] or 0
|
||||||
|
total_output_vat = sales.aggregate(sum=Sum('vat_amount'))['sum'] or 0
|
||||||
|
total_sales_gross = sales.aggregate(sum=Sum('total_amount'))['sum'] or 0
|
||||||
|
|
||||||
|
# Input VAT (Purchases) - Estimated based on Product VAT rate
|
||||||
|
# Since Purchase model doesn't store VAT explicitly, we calculate it from items
|
||||||
|
total_purchases_subtotal = 0
|
||||||
|
total_input_vat = 0
|
||||||
|
|
||||||
|
for purchase in purchases:
|
||||||
|
purchase_vat = 0
|
||||||
|
purchase_subtotal = 0
|
||||||
|
for item in purchase.items.all():
|
||||||
|
# Assume item line_total is cost * quantity
|
||||||
|
# We calculate VAT on top.
|
||||||
|
rate = float(item.product.vat)
|
||||||
|
line_total = float(item.line_total)
|
||||||
|
tax = line_total * (rate / 100.0)
|
||||||
|
purchase_vat += tax
|
||||||
|
purchase_subtotal += line_total
|
||||||
|
|
||||||
|
total_input_vat += purchase_vat
|
||||||
|
total_purchases_subtotal += purchase_subtotal
|
||||||
|
|
||||||
|
total_purchases_gross = total_purchases_subtotal + total_input_vat
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'start_date': start_date,
|
||||||
|
'end_date': end_date,
|
||||||
|
'total_sales_subtotal': total_sales_subtotal,
|
||||||
|
'total_output_vat': total_output_vat,
|
||||||
|
'total_sales_gross': total_sales_gross,
|
||||||
|
'total_purchases_subtotal': total_purchases_subtotal,
|
||||||
|
'total_input_vat': total_input_vat,
|
||||||
|
'total_purchases_gross': total_purchases_gross,
|
||||||
|
'net_vat': float(total_output_vat) - total_input_vat,
|
||||||
|
'currency': 'OMR',
|
||||||
|
}
|
||||||
|
return render(request, 'accounting/vat_report.html', context)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def accounting_dashboard(request):
|
def accounting_dashboard(request):
|
||||||
total_assets = sum(acc.balance for acc in Account.objects.filter(account_type='asset'))
|
total_assets = sum(acc.balance for acc in Account.objects.filter(account_type='asset'))
|
||||||
|
|||||||
Binary file not shown.
@ -3,11 +3,44 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4 no-print">
|
||||||
<h1 class="h3 mb-0 text-gray-800">Customer Statement</h1>
|
<h1 class="h3 mb-0 text-gray-800">Customer Statement</h1>
|
||||||
|
{% if selected_customer %}
|
||||||
|
<button onclick="window.print()" class="btn btn-secondary">
|
||||||
|
<i class="bi bi-printer"></i> Print Statement
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card shadow mb-4">
|
<style>
|
||||||
|
@media print {
|
||||||
|
body * {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.printable-area, .printable-area * {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.printable-area {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/* Reset card styles for print */
|
||||||
|
.card {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="card shadow mb-4 no-print">
|
||||||
<div class="card-header py-3">
|
<div class="card-header py-3">
|
||||||
<h6 class="m-0 font-weight-bold text-primary">Filter</h6>
|
<h6 class="m-0 font-weight-bold text-primary">Filter</h6>
|
||||||
</div>
|
</div>
|
||||||
@ -40,28 +73,45 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if selected_customer %}
|
{% if selected_customer %}
|
||||||
<div class="card shadow">
|
<div class="card shadow printable-area">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Statement for: {{ selected_customer.name }}</h5>
|
<div class="mb-4">
|
||||||
|
<h4 class="text-center mb-3">Customer Statement</h4>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<h5 class="fw-bold">{{ selected_customer.name }}</h5>
|
||||||
|
{% if selected_customer.phone %}<p class="mb-0">Phone: {{ selected_customer.phone }}</p>{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-6 text-end">
|
||||||
|
<p class="mb-0">Date Range:</p>
|
||||||
|
<p class="fw-bold">
|
||||||
|
{% if start_date %}{{ start_date }}{% else %}Start{% endif %}
|
||||||
|
to
|
||||||
|
{% if end_date %}{{ end_date }}{% else %}Present{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr class="table-light">
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Invoice #</th>
|
<th>Invoice #</th>
|
||||||
<th>Total</th>
|
<th class="text-end">Total</th>
|
||||||
<th>Paid</th>
|
<th class="text-end">Paid</th>
|
||||||
<th>Balance</th>
|
<th class="text-end">Balance</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for sale in sales %}
|
{% for sale in sales %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ sale.created_at|date:"Y-m-d" }}</td>
|
<td>{{ sale.created_at|date:"Y-m-d" }}</td>
|
||||||
<td>{{ sale.invoice_number }}</td>
|
<td>{{ sale.invoice_number|default:sale.id }}</td>
|
||||||
<td>{{ sale.total_amount }}</td>
|
<td class="text-end">{{ sale.total_amount }}</td>
|
||||||
<td>{{ sale.paid_amount }}</td>
|
<td class="text-end">{{ sale.paid_amount }}</td>
|
||||||
<td>{{ sale.balance_due }}</td>
|
<td class="text-end">{{ sale.balance_due }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
@ -69,6 +119,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr class="fw-bold table-light">
|
||||||
|
<td colspan="2" class="text-end">Totals:</td>
|
||||||
|
<td class="text-end">{{ total_amount|floatformat:2 }}</td>
|
||||||
|
<td class="text-end">{{ total_paid|floatformat:2 }}</td>
|
||||||
|
<td class="text-end">{{ total_balance|floatformat:2 }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -58,6 +58,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<a href="{% url 'vat_report' %}" class="card border-0 shadow-sm text-decoration-none h-100 lift-hover">
|
||||||
|
<div class="card-body text-center p-4">
|
||||||
|
<div class="icon-box bg-info-soft text-info rounded-circle mx-auto mb-3" style="width: 60px; height: 60px; display: flex; align-items: center; justify-content: center;">
|
||||||
|
<i class="bi bi-percent fs-3"></i>
|
||||||
|
</div>
|
||||||
|
<h6 class="fw-bold text-dark mb-1">{% trans "VAT Report" %}</h6>
|
||||||
|
<small class="text-muted">{% trans "Tax declaration summary" %}</small>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
@ -121,6 +132,7 @@
|
|||||||
.bg-success-soft { background-color: rgba(25, 135, 84, 0.1); }
|
.bg-success-soft { background-color: rgba(25, 135, 84, 0.1); }
|
||||||
.bg-primary-soft { background-color: rgba(13, 110, 253, 0.1); }
|
.bg-primary-soft { background-color: rgba(13, 110, 253, 0.1); }
|
||||||
.bg-warning-soft { background-color: rgba(255, 193, 7, 0.1); }
|
.bg-warning-soft { background-color: rgba(255, 193, 7, 0.1); }
|
||||||
|
.bg-info-soft { background-color: rgba(13, 202, 240, 0.1); }
|
||||||
.lift-hover { transition: transform 0.2s, box-shadow 0.2s; }
|
.lift-hover { transition: transform 0.2s, box-shadow 0.2s; }
|
||||||
.lift-hover:hover { transform: translateY(-5px); box-shadow: 0 .5rem 1rem rgba(0,0,0,.15)!important; }
|
.lift-hover:hover { transform: translateY(-5px); box-shadow: 0 .5rem 1rem rgba(0,0,0,.15)!important; }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -3,11 +3,44 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
<div class="d-flex justify-content-between align-items-center mb-4 no-print">
|
||||||
<h1 class="h3 mb-0 text-gray-800">Supplier Statement</h1>
|
<h1 class="h3 mb-0 text-gray-800">Supplier Statement</h1>
|
||||||
|
{% if selected_supplier %}
|
||||||
|
<button onclick="window.print()" class="btn btn-secondary">
|
||||||
|
<i class="bi bi-printer"></i> Print Statement
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card shadow mb-4">
|
<style>
|
||||||
|
@media print {
|
||||||
|
body * {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.printable-area, .printable-area * {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
.printable-area {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.no-print {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/* Reset card styles for print */
|
||||||
|
.card {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
.card-body {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="card shadow mb-4 no-print">
|
||||||
<div class="card-header py-3">
|
<div class="card-header py-3">
|
||||||
<h6 class="m-0 font-weight-bold text-primary">Filter</h6>
|
<h6 class="m-0 font-weight-bold text-primary">Filter</h6>
|
||||||
</div>
|
</div>
|
||||||
@ -40,28 +73,45 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if selected_supplier %}
|
{% if selected_supplier %}
|
||||||
<div class="card shadow">
|
<div class="card shadow printable-area">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Statement for: {{ selected_supplier.name }}</h5>
|
<div class="mb-4">
|
||||||
|
<h4 class="text-center mb-3">Supplier Statement</h4>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<h5 class="fw-bold">{{ selected_supplier.name }}</h5>
|
||||||
|
{% if selected_supplier.phone %}<p class="mb-0">Phone: {{ selected_supplier.phone }}</p>{% endif %}
|
||||||
|
</div>
|
||||||
|
<div class="col-6 text-end">
|
||||||
|
<p class="mb-0">Date Range:</p>
|
||||||
|
<p class="fw-bold">
|
||||||
|
{% if start_date %}{{ start_date }}{% else %}Start{% endif %}
|
||||||
|
to
|
||||||
|
{% if end_date %}{{ end_date }}{% else %}Present{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-bordered">
|
<table class="table table-bordered">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr class="table-light">
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Ref #</th>
|
<th>Ref #</th>
|
||||||
<th>Total</th>
|
<th class="text-end">Total</th>
|
||||||
<th>Paid</th>
|
<th class="text-end">Paid</th>
|
||||||
<th>Balance</th>
|
<th class="text-end">Balance</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for purchase in purchases %}
|
{% for purchase in purchases %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ purchase.created_at|date:"Y-m-d" }}</td>
|
<td>{{ purchase.created_at|date:"Y-m-d" }}</td>
|
||||||
<td>{{ purchase.invoice_number }}</td>
|
<td>{{ purchase.invoice_number|default:purchase.id }}</td>
|
||||||
<td>{{ purchase.total_amount }}</td>
|
<td class="text-end">{{ purchase.total_amount }}</td>
|
||||||
<td>{{ purchase.paid_amount }}</td>
|
<td class="text-end">{{ purchase.paid_amount }}</td>
|
||||||
<td>{{ purchase.balance_due }}</td>
|
<td class="text-end">{{ purchase.balance_due }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
@ -69,6 +119,14 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr class="fw-bold table-light">
|
||||||
|
<td colspan="2" class="text-end">Totals:</td>
|
||||||
|
<td class="text-end">{{ total_amount|floatformat:2 }}</td>
|
||||||
|
<td class="text-end">{{ total_paid|floatformat:2 }}</td>
|
||||||
|
<td class="text-end">{{ total_balance|floatformat:2 }}</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -900,24 +900,42 @@ def customer_statement(request):
|
|||||||
selected_customer = None
|
selected_customer = None
|
||||||
sales = []
|
sales = []
|
||||||
|
|
||||||
|
# Totals
|
||||||
|
total_amount = 0
|
||||||
|
total_paid = 0
|
||||||
|
total_balance = 0
|
||||||
|
|
||||||
customer_id = request.GET.get('customer')
|
customer_id = request.GET.get('customer')
|
||||||
start_date = request.GET.get('start_date')
|
start_date = request.GET.get('start_date')
|
||||||
end_date = request.GET.get('end_date')
|
end_date = request.GET.get('end_date')
|
||||||
|
|
||||||
if customer_id:
|
if customer_id:
|
||||||
selected_customer = get_object_or_404(Customer, id=customer_id)
|
selected_customer = get_object_or_404(Customer, id=customer_id)
|
||||||
sales = Sale.objects.filter(customer=selected_customer).order_by('-created_at')
|
sales = Sale.objects.filter(customer=selected_customer).order_by('created_at')
|
||||||
if start_date:
|
if start_date:
|
||||||
sales = sales.filter(created_at__date__gte=start_date)
|
sales = sales.filter(created_at__date__gte=start_date)
|
||||||
if end_date:
|
if end_date:
|
||||||
sales = sales.filter(created_at__date__lte=end_date)
|
sales = sales.filter(created_at__date__lte=end_date)
|
||||||
|
|
||||||
|
# Calculate totals
|
||||||
|
aggregates = sales.aggregate(
|
||||||
|
sum_total=Sum('total_amount'),
|
||||||
|
sum_paid=Sum('paid_amount'),
|
||||||
|
sum_balance=Sum('balance_due')
|
||||||
|
)
|
||||||
|
total_amount = aggregates['sum_total'] or 0
|
||||||
|
total_paid = aggregates['sum_paid'] or 0
|
||||||
|
total_balance = aggregates['sum_balance'] or 0
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'customers': customers,
|
'customers': customers,
|
||||||
'selected_customer': selected_customer,
|
'selected_customer': selected_customer,
|
||||||
'sales': sales,
|
'sales': sales,
|
||||||
'start_date': start_date,
|
'start_date': start_date,
|
||||||
'end_date': end_date
|
'end_date': end_date,
|
||||||
|
'total_amount': total_amount,
|
||||||
|
'total_paid': total_paid,
|
||||||
|
'total_balance': total_balance
|
||||||
}
|
}
|
||||||
return render(request, 'core/customer_statement.html', context)
|
return render(request, 'core/customer_statement.html', context)
|
||||||
|
|
||||||
@ -927,24 +945,42 @@ def supplier_statement(request):
|
|||||||
selected_supplier = None
|
selected_supplier = None
|
||||||
purchases = []
|
purchases = []
|
||||||
|
|
||||||
|
# Totals
|
||||||
|
total_amount = 0
|
||||||
|
total_paid = 0
|
||||||
|
total_balance = 0
|
||||||
|
|
||||||
supplier_id = request.GET.get('supplier')
|
supplier_id = request.GET.get('supplier')
|
||||||
start_date = request.GET.get('start_date')
|
start_date = request.GET.get('start_date')
|
||||||
end_date = request.GET.get('end_date')
|
end_date = request.GET.get('end_date')
|
||||||
|
|
||||||
if supplier_id:
|
if supplier_id:
|
||||||
selected_supplier = get_object_or_404(Supplier, id=supplier_id)
|
selected_supplier = get_object_or_404(Supplier, id=supplier_id)
|
||||||
purchases = Purchase.objects.filter(supplier=selected_supplier).order_by('-created_at')
|
purchases = Purchase.objects.filter(supplier=selected_supplier).order_by('created_at')
|
||||||
if start_date:
|
if start_date:
|
||||||
purchases = purchases.filter(created_at__date__gte=start_date)
|
purchases = purchases.filter(created_at__date__gte=start_date)
|
||||||
if end_date:
|
if end_date:
|
||||||
purchases = purchases.filter(created_at__date__lte=end_date)
|
purchases = purchases.filter(created_at__date__lte=end_date)
|
||||||
|
|
||||||
|
# Calculate totals
|
||||||
|
aggregates = purchases.aggregate(
|
||||||
|
sum_total=Sum('total_amount'),
|
||||||
|
sum_paid=Sum('paid_amount'),
|
||||||
|
sum_balance=Sum('balance_due')
|
||||||
|
)
|
||||||
|
total_amount = aggregates['sum_total'] or 0
|
||||||
|
total_paid = aggregates['sum_paid'] or 0
|
||||||
|
total_balance = aggregates['sum_balance'] or 0
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'suppliers': suppliers,
|
'suppliers': suppliers,
|
||||||
'selected_supplier': selected_supplier,
|
'selected_supplier': selected_supplier,
|
||||||
'purchases': purchases,
|
'purchases': purchases,
|
||||||
'start_date': start_date,
|
'start_date': start_date,
|
||||||
'end_date': end_date
|
'end_date': end_date,
|
||||||
|
'total_amount': total_amount,
|
||||||
|
'total_paid': total_paid,
|
||||||
|
'total_balance': total_balance
|
||||||
}
|
}
|
||||||
return render(request, 'core/supplier_statement.html', context)
|
return render(request, 'core/supplier_statement.html', context)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user