Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,221 @@
<?php require_once APP_ROOT . '/app/Views/layouts/header.php'; ?>
<div class="mb-6 flex justify-between items-start md:items-center flex-col md:flex-row gap-4">
<div>
<h2 class="text-2xl font-bold text-slate-800 dark:text-white">ระบบสืบค้นและพิมพ์สลิปเงินเดือน / 50 ทวิ</h2>
<p class="text-slate-500 dark:text-slate-400 text-sm mt-1">ค้นหารายการจ่ายเงินเดือนเพื่อสั่งพิมพ์สลิปเงินเดือน (รายเดือน) หรือใบเสียภาษี (50 ทวิ - รายปี)</p>
</div>
<div class="flex flex-col items-end gap-2">
<label class="inline-flex items-center cursor-pointer mb-2">
<input type="checkbox" id="togglePrefix" class="w-4 h-4 text-indigo-600 bg-slate-100 border-slate-300 rounded focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:ring-offset-slate-800 focus:ring-2 dark:bg-slate-700 dark:border-slate-600">
<span class="ml-2 text-sm font-medium text-slate-700 dark:text-slate-300">แสดงคำนำหน้าชื่อ</span>
</label>
<label class="inline-flex items-center cursor-pointer">
<input type="checkbox" id="groupByLetter" class="w-4 h-4 text-indigo-600 bg-slate-100 border-slate-300 rounded focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:ring-offset-slate-800 focus:ring-2 dark:bg-slate-700 dark:border-slate-600">
<span class="ml-2 text-sm font-medium text-slate-700 dark:text-slate-300">จัดกลุ่มตามตัวอักษร (มีใบปะหน้า)</span>
</label>
<div>
<form id="bulkTaxForm" action="<?= BASE_URL ?>/reports/taxBulk" method="POST" target="_blank" class="hidden">
<input type="hidden" name="year" value="<?= htmlspecialchars($year ?? date('Y')) ?>">
<input type="hidden" name="group_by_letter" id="formGroupByLetter" value="0">
<div id="bulkTaxFormContainer"></div>
</form>
<button type="button" id="bulkPrintBtn" class="inline-flex items-center justify-center px-4 py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white text-sm font-medium rounded-xl transition-colors shadow-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-5 h-5 mr-2"><path stroke-linecap="round" stroke-linejoin="round" d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0 1 10.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0 .229 2.523a1.125 1.125 0 0 1-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0 0 21 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 0 0-1.913-.247M6.34 18H5.25A2.25 2.25 0 0 1 3 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 0 1 1.913-.247m10.5 0a48.536 48.536 0 0 0-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5Zm-3 0h.008v.008H15V10.5Z" /></svg>
พิมพ์ 50 ทวิ ที่เลือก (Bulk Print)
</button>
</div>
</div>
</div>
<!-- Filter Section -->
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-sm border border-slate-100 dark:border-slate-700 p-6 mb-6">
<form action="<?= BASE_URL ?>/reports" method="GET" class="flex flex-col md:flex-row gap-4 items-end">
<div class="w-full md:w-1/3">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">เลือกปี (พ.ศ.)</label>
<select name="year" class="block w-full rounded-xl border-0 py-2.5 px-3 text-slate-900 dark:text-white shadow-sm ring-1 ring-inset ring-slate-300 dark:ring-slate-600 focus:ring-2 focus:ring-sky-500 bg-slate-50 dark:bg-slate-900 sm:text-sm">
<?php
$currentYear = date('Y');
for($y = $currentYear + 1; $y >= $currentYear - 5; $y--):
$thaiYear = $y + 543;
?>
<option value="<?= $y ?>" <?= (isset($year) && $year == $y) ? 'selected' : '' ?>><?= $thaiYear ?></option>
<?php endfor; ?>
</select>
</div>
<div class="w-full md:w-1/3">
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">เลือกเดือน</label>
<select name="month" class="block w-full rounded-xl border-0 py-2.5 px-3 text-slate-900 dark:text-white shadow-sm ring-1 ring-inset ring-slate-300 dark:ring-slate-600 focus:ring-2 focus:ring-sky-500 bg-slate-50 dark:bg-slate-900 sm:text-sm">
<?php
$thaiMonths = [
'01' => 'มกราคม', '02' => 'กุมภาพันธ์', '03' => 'มีนาคม', '04' => 'เมษายน',
'05' => 'พฤษภาคม', '06' => 'มิถุนายน', '07' => 'กรกฎาคม', '08' => 'สิงหาคม',
'09' => 'กันยายน', '10' => 'ตุลาคม', '11' => 'พฤศจิกายน', '12' => 'ธันวาคม'
];
foreach($thaiMonths as $mNum => $mName):
?>
<option value="<?= $mNum ?>" <?= (isset($month) && $month == $mNum) ? 'selected' : '' ?>><?= $mName ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="w-full md:w-1/3">
<button type="submit" class="w-full inline-flex items-center justify-center px-4 py-2.5 bg-sky-500 hover:bg-sky-600 text-white text-sm font-medium rounded-xl transition-colors shadow-sm">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4 mr-2"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" /></svg>
ค้นหา
</button>
</div>
</form>
</div>
<!-- Results DataTables -->
<link rel="stylesheet" href="https://cdn.datatables.net/2.0.8/css/dataTables.tailwindcss.css">
<style>
/* DataTables Dark Mode Overrides */
.dark .dt-container { color: #cbd5e1; }
.dark .dt-length select, .dark .dt-search input { background-color: #1e293b; border-color: #334155; color: #f8fafc; border-radius: 0.5rem; padding: 0.25rem 0.5rem; }
.dark .dt-info, .dark .dt-paging-button { color: #94a3b8 !important; }
.dark .dt-paging-button.current { background: #38bdf8 !important; color: #0f172a !important; border-color: #38bdf8 !important; }
.dark .dt-paging-button:hover { background: #334155 !important; color: #f8fafc !important; }
table.dataTable.no-footer { border-bottom: 1px solid #334155 !important; }
</style>
<div class="bg-white dark:bg-slate-800 rounded-2xl shadow-sm border border-slate-100 dark:border-slate-700 overflow-hidden p-6">
<div class="overflow-x-hidden">
<table id="reportTable" class="w-full text-left text-sm text-slate-600 dark:text-slate-300 display">
<thead class="bg-slate-50 dark:bg-slate-900/50 text-slate-500 dark:text-slate-400 text-xs uppercase font-semibold">
<tr>
<th class="px-4 py-4 w-10 text-center">
<input type="checkbox" id="selectAllCheckbox" class="w-4 h-4 text-sky-600 bg-slate-100 border-slate-300 rounded focus:ring-sky-500 dark:focus:ring-sky-600 dark:ring-offset-slate-800 focus:ring-2 dark:bg-slate-700 dark:border-slate-600 cursor-pointer">
</th>
<th class="px-4 py-4">รูป</th>
<th class="px-6 py-4">ชื่อ-สกุล</th>
<th class="px-6 py-4">ตำแหน่ง/หน่วยงาน</th>
<th class="px-6 py-4 text-center">พิมพ์สลิป (รายเดือน)</th>
<th class="px-6 py-4 text-center">พิมพ์ 50 ทวิ (รายปี)</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 dark:divide-slate-700">
<?php foreach ($payrollData as $row): ?>
<tr class="hover:bg-slate-50 dark:hover:bg-slate-700/50 transition-colors">
<td class="px-4 py-4 text-center">
<input type="checkbox" value="<?= htmlspecialchars($row['national_id']) ?>" class="tax-checkbox w-4 h-4 text-sky-600 bg-slate-100 border-slate-300 rounded focus:ring-sky-500 dark:focus:ring-sky-600 dark:ring-offset-slate-800 focus:ring-2 dark:bg-slate-700 dark:border-slate-600 cursor-pointer">
</td>
<td class="px-4 py-4">
<div class="w-10 h-10 rounded-full overflow-hidden bg-slate-200 dark:bg-slate-700 border-2 border-white dark:border-slate-600 shadow-sm flex items-center justify-center">
<img src="<?= BASE_URL ?>/employee/image/<?= urlencode($row['national_id']) ?>" alt="Profile" class="w-full h-full object-cover" onerror="this.style.display='none'">
</div>
</td>
<?php
$rawName = trim($row['hr_fname'] ?? $row['first_name']);
$prefix = '';
$bodyName = $rawName;
if (preg_match('/^(นาย|นางสาว|นาง|ว่าที่ร้อยตรี|น\.ส\.|นพ\.|พญ\.|ดร\.)\s*(.*)$/u', $rawName, $matches)) {
$prefix = $matches[1];
$bodyName = $matches[2];
}
?>
<td class="px-6 py-4 font-medium text-slate-800 dark:text-slate-200" data-sort="<?= htmlspecialchars($bodyName) ?>">
<span class="name-prefix hidden"><?= htmlspecialchars($prefix) ?></span><?= htmlspecialchars($bodyName) ?> <?= htmlspecialchars($row['hr_lname'] ?? $row['last_name']) ?>
</td>
<td class="px-6 py-4">
<div class="text-slate-800 dark:text-slate-200"><?= htmlspecialchars($row['hr_position'] ?? 'N/A') ?></div>
<div class="text-xs text-slate-500 dark:text-slate-400"><?= htmlspecialchars($row['hr_department'] ?? 'N/A') ?></div>
</td>
<td class="px-6 py-4 text-center">
<a href="<?= BASE_URL ?>/reports/slip/<?= urlencode($row['national_id']) ?>/<?= $month ?>/<?= $year ?>" target="_blank" class="inline-flex items-center px-3 py-1.5 bg-emerald-50 text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400 border border-emerald-200 dark:border-emerald-800 rounded-lg text-xs font-medium hover:bg-emerald-100 dark:hover:bg-emerald-900/50 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M6.72 13.829c-.24.03-.48.062-.72.096m.72-.096a42.415 42.415 0 0 1 10.56 0m-10.56 0L6.34 18m10.94-4.171c.24.03.48.062.72.096m-.72-.096L17.66 18m0 0 .229 2.523a1.125 1.125 0 0 1-1.12 1.227H7.231c-.662 0-1.18-.568-1.12-1.227L6.34 18m11.318 0h1.091A2.25 2.25 0 0 0 21 15.75V9.456c0-1.081-.768-2.015-1.837-2.175a48.055 48.055 0 0 0-1.913-.247M6.34 18H5.25A2.25 2.25 0 0 1 3 15.75V9.456c0-1.081.768-2.015 1.837-2.175a48.041 48.041 0 0 1 1.913-.247m10.5 0a48.536 48.536 0 0 0-10.5 0m10.5 0V3.375c0-.621-.504-1.125-1.125-1.125h-8.25c-.621 0-1.125.504-1.125 1.125v3.659M18 10.5h.008v.008H18V10.5Zm-3 0h.008v.008H15V10.5Z" /></svg>
สลิปเดือนนี้
</a>
</td>
<td class="px-6 py-4 text-center">
<a href="<?= BASE_URL ?>/reports/tax/<?= urlencode($row['national_id']) ?>/<?= $year ?>" target="_blank" class="inline-flex items-center px-3 py-1.5 bg-indigo-50 text-indigo-600 dark:bg-indigo-900/30 dark:text-indigo-400 border border-indigo-200 dark:border-indigo-800 rounded-lg text-xs font-medium hover:bg-indigo-100 dark:hover:bg-indigo-900/50 transition-colors">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4 mr-1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z" /></svg>
50 ทวิ (ทั้งปี)
</a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- jQuery and DataTables JS -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.datatables.net/2.0.8/js/dataTables.js"></script>
<script src="https://cdn.datatables.net/2.0.8/js/dataTables.tailwindcss.js"></script>
<script>
$(document).ready(function() {
$('#reportTable').DataTable({
"language": {
"sProcessing": "กำลังดำเนินการ...",
"sLengthMenu": "แสดง _MENU_ เรคคอร์ด",
"sZeroRecords": "ไม่พบข้อมูล",
"sInfo": "แสดง _START_ ถึง _END_ จาก _TOTAL_ เรคคอร์ด",
"sInfoEmpty": "แสดง 0 ถึง 0 จาก 0 เรคคอร์ด",
"sInfoFiltered": "(กรองข้อมูล _MAX_ ทุกเรคคอร์ด)",
"sSearch": "ค้นหา:",
"oPaginate": {
"sFirst": "แรกสุด",
"sPrevious": "ก่อนหน้า",
"sNext": "ถัดไป",
"sLast": "สุดท้าย"
}
},
"pageLength": 50,
"columnDefs": [
{ "orderable": false, "targets": [0, 1, 4, 5] } // Disable sorting on Checkbox, Image, and Print Action columns
]
});
// Checkbox toggle prefix
$('#togglePrefix').on('change', function() {
if ($(this).is(':checked')) {
$('.name-prefix').removeClass('hidden');
} else {
$('.name-prefix').addClass('hidden');
}
});
// Handle Select All Checkbox
$('#selectAllCheckbox').on('click', function() {
var isChecked = this.checked;
// Get all rows in DataTables (including those on other pages)
var tableNodes = $('#reportTable').DataTable().rows().nodes();
$('input.tax-checkbox', tableNodes).prop('checked', isChecked);
});
// Handle Bulk Print Button
$('#bulkPrintBtn').on('click', function(e) {
e.preventDefault();
var table = $('#reportTable').DataTable();
var checkedBoxes = table.$('input.tax-checkbox:checked');
if (checkedBoxes.length === 0) {
alert('กรุณาเลือกรายชื่ออย่างน้อย 1 รายการเพื่อพิมพ์');
return;
}
// Set group_by_letter value
$('#formGroupByLetter').val($('#groupByLetter').is(':checked') ? '1' : '0');
// Clear old hidden inputs in form
$('#bulkTaxFormContainer').empty();
// Create hidden inputs for each selected ID
checkedBoxes.each(function() {
$('#bulkTaxFormContainer').append($('<input>').attr({
type: 'hidden',
name: 'national_ids[]',
value: $(this).val()
}));
});
$('#bulkTaxForm').submit();
});
});
</script>
<?php require_once APP_ROOT . '/app/Views/layouts/footer.php'; ?>