Files
wms-app/app/accounting/vat_report.php
T
Thanakorn f11af6e949 Self-host front-end libraries, minimal sign-in header and CSP
- sign-in pages load only what they use (include_login_header.php, ajax_core.js)
- every library, font and data file served from assets/vendor with pinned
  versions (VERSIONS.json); no CDN at runtime
- Content-Security-Policy on app, sign-in and landing pages
- remove httpbin Dropzone target and source-map references
2026-09-24 14:53:41 +07:00

261 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
require_once __DIR__ . '/../session.php';
require '../config.php';
require '../include_header.php';
?>
<body>
<?php require '../include_topbar.php'; ?>
<?php require '../include_sidebar_ac.php'; ?>
<main id="content" class="content py-15">
<div class="container-fluid">
<div class="row mb-5">
<div class="col-12">
<h1 class="fs-3 mb-1">VAT Report</h1>
<p class="mb-0 text-muted">Output VAT (Sales Tax) and Input VAT (Purchase Tax) from posted journal entries</p>
</div>
</div>
<!-- Filters -->
<div class="card p-4 mb-4">
<div class="row g-2 align-items-end">
<div class="col-auto">
<label class="form-label mb-1 small">From Date</label>
<input type="text" id="f_from" class="form-control form-control-sm" placeholder="DD/MM/YYYY" style="width:160px;">
</div>
<div class="col-auto">
<label class="form-label mb-1 small">To Date</label>
<input type="text" id="f_to" class="form-control form-control-sm" placeholder="DD/MM/YYYY" style="width:160px;">
</div>
<div class="col-auto">
<label class="form-label mb-1 small">Category</label>
<select id="f_cat" class="form-select form-select-sm" style="width:180px;">
<option value="">All</option>
<option value="sales_tax">Output VAT (Sales)</option>
<option value="purchase_tax">Input VAT (Purchase)</option>
</select>
</div>
<div class="col-auto">
<label class="form-label mb-1 small">Department</label>
<select id="f_department" class="form-select form-select-sm" style="width:200px;">
<option value="0">All Departments</option>
</select>
</div>
<div class="col-auto">
<button class="btn btn-secondary btn-sm" onclick="load_report()">
<i class="ti ti-search me-1"></i>Run
</button>
</div>
<div class="col-auto">
<div class="dropdown">
<a href="#" role="button" class="btn btn-outline-secondary btn-sm text-nowrap" data-bs-toggle="dropdown" aria-expanded="false">
<i class="ti ti-download me-1"></i>Export
</a>
<div class="dropdown-menu dropdown-menu-end p-0" style="min-width:160px;">
<div class="d-flex gap-3 align-items-center border-bottom px-3 py-3">
<i class="ti ti-download"></i><div><h4 class="mb-0 small">Export</h4></div>
</div>
<div class="p-3 d-flex flex-column gap-1 small lh-lg">
<a href="javascript:;" class="ac-export-link" onclick="export_report('csv')"><i class="ti ti-file-type-csv me-2"></i>CSV</a>
<a href="javascript:;" class="ac-export-link" onclick="export_report('xlsx')"><i class="ti ti-file-type-xls me-2"></i>Excel</a>
<a href="javascript:;" class="ac-export-link" onclick="export_report('pdf')"><i class="ti ti-file-type-pdf me-2"></i>PDF</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Summary cards -->
<div class="row g-3 mb-4" id="vat_summary" style="display:none;">
<div class="col-md-4">
<div class="card border-0 shadow-sm">
<div class="card-body">
<p class="text-muted small mb-1">Total Debit</p>
<h4 class="mb-0 fw-bold" id="vat_debit">—</h4>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm">
<div class="card-body">
<p class="text-muted small mb-1">Total Credit</p>
<h4 class="mb-0 fw-bold" id="vat_credit">—</h4>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card border-0 shadow-sm">
<div class="card-body">
<p class="text-muted small mb-1">Net VAT (Credit − Debit)</p>
<h4 class="mb-0 fw-bold" id="vat_net">—</h4>
</div>
</div>
</div>
</div>
<!-- Table -->
<div class="card">
<div class="card-body p-0">
<table class="table table-hover mb-0 table-sm">
<thead class="table-primary border-light">
<tr>
<th>Date</th>
<th>Period</th>
<th>Type</th>
<th>Department</th>
<th>Reference</th>
<th>Account</th>
<th>Category</th>
<th>Description</th>
<th class="text-end">Debit</th>
<th class="text-end">Credit</th>
</tr>
</thead>
<tbody id="vat_tbody">
<tr><td colspan="10" class="text-center text-muted py-5">Select a date range and click Run.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</main>
<?php require '../include_ending.php'; ?>
<script>
var now = new Date();
var curMonth = now.getFullYear() + '-' + String(now.getMonth()+1).padStart(2,'0');
document.getElementById('f_from').value = curMonth + '-01';
document.getElementById('f_to').value = curMonth + '-' + String(new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate()).padStart(2,'0');
flatpickr('#f_from, #f_to', { dateFormat: 'Y-m-d', altInput: true, altFormat: 'd/m/Y', allowInput: true });
var export_data = [];
var cat_labels = { sales_tax: 'Output VAT', purchase_tax: 'Input VAT' };
var src_labels = {
invoice: 'Invoice', credit_note: 'Credit Note',
purchase_invoice: 'Purchase Invoice', supplier_credit_note: 'Supplier Credit Note',
receipt: 'Receipt', payment: 'Payment', manual: 'Manual',
};
load_departments();
function load_departments() {
ajax_request({
url: server_url + 'accounting/api/engine/department.php',
autoPrepare: true,
checkRequired: 0,
noLoading: true,
action: 'read',
onSuccess: function(res) {
var html = '<option value="0">All Departments</option>';
(res.output || []).filter(function(d){ return String(d.status) === '1'; }).forEach(function(d) {
html += '<option value="' + d.id + '">' + escape_html(d.dept_code + ' - ' + d.dept_name) + '</option>';
});
document.getElementById('f_department').innerHTML = html;
}
});
}
function load_report() {
var from = document.getElementById('f_from').value;
var to = document.getElementById('f_to').value;
var cat = document.getElementById('f_cat').value;
var dept = document.getElementById('f_department').value || '0';
if (!from || !to) { bootbox.alert('Select both dates.'); return; }
export_data = [];
document.getElementById('vat_tbody').innerHTML =
'<tr><td colspan="10" class="text-center text-muted py-5"><span class="spinner-border spinner-border-sm me-2"></span>Loading...</td></tr>';
document.getElementById('vat_summary').style.display = 'none';
ajax_request({
url: server_url + 'accounting/api/engine/get_vat_report.php',
autoPrepare: true,
checkRequired: 0,
noLoading: true,
action: 'read',
data: { from_date: from, to_date: to, categories: cat ? [cat] : [], department_id: dept },
onSuccess: function(res) {
var d = res.output;
var rows = d.rows || [];
document.getElementById('vat_debit').textContent = format_number(d.total_debit);
document.getElementById('vat_credit').textContent = format_number(d.total_credit);
document.getElementById('vat_net').textContent = format_number(parseFloat(d.total_credit) - parseFloat(d.total_debit));
document.getElementById('vat_summary').style.display = '';
if (rows.length === 0) {
document.getElementById('vat_tbody').innerHTML =
'<tr><td colspan="10" class="text-center text-muted py-5">No VAT entries found.</td></tr>';
return;
}
export_data = rows.map(function(r) {
return {
date: r.entry_date||'', period: r.period||'',
type: src_labels[r.source_type]||r.source_type,
department: r.dept_code||'',
reference: r.reference||'',
account: r.account_code + ' ' + r.account_name,
category: cat_labels[r.account_category]||r.account_category,
description: r.description||'',
debit: parseFloat(r.debit)||'',
credit: parseFloat(r.credit)||'',
};
});
var html = '';
rows.forEach(function(r) {
html += '<tr>' +
'<td class="small">' + escape_html(format_date(r.entry_date)) + '</td>' +
'<td class="small">' + escape_html(r.period) + '</td>' +
'<td class="small"><span class="badge bg-secondary bg-opacity-10 text-secondary">' + escape_html(src_labels[r.source_type] || r.source_type) + '</span></td>' +
'<td class="small">' + (r.dept_code ? escape_html(r.dept_code) : '<span class="text-muted">—</span>') + '</td>' +
'<td class="small">' + escape_html(r.reference || '—') + '</td>' +
'<td class="small">' + escape_html(r.account_code + ' ' + r.account_name) + '</td>' +
'<td class="small"><span class="badge bg-info bg-opacity-10 text-info">' + escape_html(cat_labels[r.account_category] || r.account_category) + '</span></td>' +
'<td class="small text-muted">' + escape_html(r.description || '—') + '</td>' +
'<td class="text-end small">' + (parseFloat(r.debit) ? format_number(r.debit) : '—') + '</td>' +
'<td class="text-end small">' + (parseFloat(r.credit) ? format_number(r.credit) : '—') + '</td>' +
'</tr>';
});
document.getElementById('vat_tbody').innerHTML = html;
}
});
}
function export_report(format) {
if (export_data.length === 0) { bootbox.alert('No data to export. Run the report first.'); return; }
var from = document.getElementById('f_from').value;
var to = document.getElementById('f_to').value;
var filename = 'vat_report_' + from + '_' + to;
if (format === 'csv') {
alasql('SELECT * INTO CSV("' + filename + '.csv",{headers:true}) FROM ?', [export_data]);
} else if (format === 'xlsx') {
alasql('SELECT * INTO XLSX("' + filename + '.xlsx",{headers:true}) FROM ?', [export_data]);
} else if (format === 'pdf') {
var { jsPDF } = window.jspdf;
var doc = new jsPDF({ orientation: 'landscape' });
doc.setFontSize(11);
doc.text('VAT Report ' + from + ' to ' + to, 14, 14);
doc.autoTable({
startY: 20,
head: [['Date','Period','Type','Dept','Reference','Account','Category','Description','Debit','Credit']],
body: export_data.map(function(r){ return [r.date,r.period,r.type,r.department,r.reference,r.account,r.category,r.description,r.debit,r.credit]; }),
styles: { fontSize: 7 },
headStyles: { fillColor: [41,128,185] },
});
doc.save(filename + '.pdf');
}
}
</script>
<script src="<?php echo $server_url?>assets/vendor/xlsx/0.18.5/xlsx.full.min.js"></script>
<script src="<?php echo $server_url?>assets/vendor/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="<?php echo $server_url?>assets/vendor/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
</body>
</html>