428 lines
18 KiB
PHP
428 lines
18 KiB
PHP
<?php
|
|
namespace app\Controllers;
|
|
|
|
use app\Models\PayrollModel;
|
|
use app\Models\HrPersonModel;
|
|
use app\Models\IncomeMasterModel;
|
|
use app\Models\DeductionMasterModel;
|
|
use app\Models\OfficerTypeModel;
|
|
|
|
class ReportController extends Controller {
|
|
|
|
public function __construct() {
|
|
if (empty($_SESSION['user_id'])) {
|
|
$_SESSION['error'] = 'กรุณาเข้าสู่ระบบก่อนใช้งาน';
|
|
header('Location: ' . BASE_URL . '/login');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
public function index() {
|
|
$payrollModel = new PayrollModel();
|
|
|
|
// Get filter inputs
|
|
$month = $_GET['month'] ?? date('m');
|
|
$year = $_GET['year'] ?? date('Y');
|
|
|
|
// Fetch payroll data for the selected month/year
|
|
$payrollData = $payrollModel->getSalariesByPeriod($month, $year);
|
|
|
|
// Fetch matching HR data
|
|
$hrModel = new HrPersonModel();
|
|
$nationalIds = array_column($payrollData, 'national_id');
|
|
$hrData = $hrModel->getPersonsByNationalIds($nationalIds);
|
|
|
|
// Combine data
|
|
foreach ($payrollData as &$row) {
|
|
$nid = $row['national_id'];
|
|
if (isset($hrData[$nid])) {
|
|
$row['hr_fname'] = $hrData[$nid]['HR_FNAME'];
|
|
$row['hr_lname'] = $hrData[$nid]['HR_LNAME'];
|
|
$row['hr_position'] = $hrData[$nid]['HR_POSITION_NAME'];
|
|
$row['hr_department'] = $hrData[$nid]['HR_DEPARTMENT_SUB_SUB_NAME'];
|
|
}
|
|
}
|
|
|
|
$this->view('reports/index', [
|
|
'title' => 'ระบบสืบค้นและพิมพ์สลิปเงินเดือน | ' . APP_NAME,
|
|
'activeMenu' => 'reports',
|
|
'month' => $month,
|
|
'year' => $year,
|
|
'payrollData' => $payrollData
|
|
]);
|
|
}
|
|
|
|
public function printSlip() {
|
|
$nationalId = $_GET['national_id'] ?? null;
|
|
$month = $_GET['month'] ?? null;
|
|
$year = $_GET['year'] ?? null;
|
|
|
|
if (!$nationalId || !$month || !$year) {
|
|
die('ข้อมูลไม่ครบถ้วน');
|
|
}
|
|
|
|
$payrollModel = new PayrollModel();
|
|
$salary = $payrollModel->getSalaryByNationalId($nationalId, $month, $year);
|
|
|
|
if (!$salary) {
|
|
die('ไม่พบข้อมูลเงินเดือนของบุคคลนี้ในงวดที่เลือก');
|
|
}
|
|
|
|
$incomes = $payrollModel->getEmployeeIncomes($salary['id']);
|
|
$deductions = $payrollModel->getEmployeeDeductions($salary['id']);
|
|
|
|
$hrModel = new HrPersonModel();
|
|
$hrData = $hrModel->getPersonByNationalId($nationalId);
|
|
|
|
$profileModel = new \app\Models\EmployeeProfileModel();
|
|
$bankProfile = $profileModel->getProfile($nationalId);
|
|
|
|
$settingModel = new \app\Models\SystemSettingModel();
|
|
$signatureName = $settingModel->getSetting('signature_name', '( นางณัฐฐิณี เรืองทอง )');
|
|
$signaturePosition = $settingModel->getSetting('signature_position', 'นักวิชาการเงินและบัญชี');
|
|
$signatureScale = $settingModel->getSetting('signature_scale', '100');
|
|
$slipFontSize = $settingModel->getSetting('slip_font_size', '11pt');
|
|
$signaturePosX = $settingModel->getSetting('signature_pos_x', '0');
|
|
$signaturePosY = $settingModel->getSetting('signature_pos_y', '0');
|
|
|
|
$this->view('reports/slip', [
|
|
'salary' => $salary,
|
|
'incomes' => $incomes,
|
|
'deductions' => $deductions,
|
|
'hrData' => $hrData,
|
|
'bankProfile' => $bankProfile,
|
|
'signatureName' => $signatureName,
|
|
'signaturePosition' => $signaturePosition,
|
|
'signatureScale' => $signatureScale,
|
|
'slipFontSize' => $slipFontSize,
|
|
'signaturePosX' => $signaturePosX,
|
|
'signaturePosY' => $signaturePosY,
|
|
'month' => $month,
|
|
'year' => $year
|
|
]);
|
|
}
|
|
|
|
public function printTax() {
|
|
$nationalId = $_GET['national_id'] ?? null;
|
|
$year = $_GET['year'] ?? null;
|
|
|
|
if (!$nationalId || !$year) {
|
|
die('ข้อมูลไม่ครบถ้วน');
|
|
}
|
|
|
|
$payrollModel = new PayrollModel();
|
|
$yearlySummary = $payrollModel->getYearlyTaxSummary($nationalId, $year);
|
|
|
|
if (!$yearlySummary || $yearlySummary['total_income'] == 0) {
|
|
die('ไม่พบข้อมูลรายได้ในปีที่เลือก');
|
|
}
|
|
|
|
$hrModel = new HrPersonModel();
|
|
$hrData = $hrModel->getPersonByNationalId($nationalId);
|
|
|
|
$settingModel = new \app\Models\SystemSettingModel();
|
|
$orgTaxId = $settingModel->getSetting('org_tax_id', '');
|
|
|
|
$taxSignatureName = $settingModel->getSetting('tax_signature_name', '');
|
|
$taxSignaturePosition = $settingModel->getSetting('tax_signature_position', '');
|
|
$taxSignatureScale = $settingModel->getSetting('tax_signature_scale', '100');
|
|
$taxSignaturePosX = $settingModel->getSetting('tax_signature_pos_x', '0');
|
|
$taxSignaturePosY = $settingModel->getSetting('tax_signature_pos_y', '0');
|
|
$taxFontSize = $settingModel->getSetting('tax_font_size', '11pt');
|
|
$orgAddress = $settingModel->getSetting('org_address', 'ต.อ่างทอง อ.เกาะสมุย จ.สุราษฎร์ธานี 84140');
|
|
$taxPayeeAddress = $settingModel->getSetting('tax_payee_address', 'ต.อ่างทอง อ.เกาะสมุย จ.สุราษฎร์ธานี 84140');
|
|
|
|
$this->view('reports/tax', [
|
|
'yearlySummary' => $yearlySummary,
|
|
'hrData' => $hrData,
|
|
'year' => $year,
|
|
'nationalId' => $nationalId,
|
|
'orgTaxId' => $orgTaxId,
|
|
'taxSignatureName' => $taxSignatureName,
|
|
'taxSignaturePosition' => $taxSignaturePosition,
|
|
'taxSignatureScale' => $taxSignatureScale,
|
|
'taxSignaturePosX' => $taxSignaturePosX,
|
|
'taxSignaturePosY' => $taxSignaturePosY,
|
|
'taxFontSize' => $taxFontSize,
|
|
'orgAddress' => $orgAddress,
|
|
'taxPayeeAddress' => $taxPayeeAddress
|
|
]);
|
|
}
|
|
|
|
public function printTaxBulk() {
|
|
$nationalIds = $_POST['national_ids'] ?? [];
|
|
$year = $_POST['year'] ?? null;
|
|
$groupByLetter = isset($_POST['group_by_letter']) && $_POST['group_by_letter'] == '1';
|
|
|
|
if (empty($nationalIds) || !$year) {
|
|
die('ข้อมูลไม่ครบถ้วน กรุณาเลือกพนักงานอย่างน้อย 1 รายการ');
|
|
}
|
|
|
|
$payrollModel = new PayrollModel();
|
|
$hrModel = new HrPersonModel();
|
|
|
|
$bulkData = [];
|
|
|
|
foreach ($nationalIds as $nationalId) {
|
|
$yearlySummary = $payrollModel->getYearlyTaxSummary($nationalId, $year);
|
|
if ($yearlySummary && $yearlySummary['total_income'] > 0) {
|
|
$hrData = $hrModel->getPersonByNationalId($nationalId);
|
|
$bulkData[] = [
|
|
'nationalId' => $nationalId,
|
|
'yearlySummary' => $yearlySummary,
|
|
'hrData' => $hrData
|
|
];
|
|
}
|
|
}
|
|
|
|
if (empty($bulkData)) {
|
|
die('ไม่พบข้อมูลรายได้ในปีที่เลือกของพนักงานที่เลือกทั้งหมด');
|
|
}
|
|
|
|
// Sort data by First Name if grouping by letter is enabled
|
|
if ($groupByLetter) {
|
|
usort($bulkData, function($a, $b) {
|
|
$nameA = $a['hrData']['HR_FNAME'] ?? '';
|
|
$nameB = $b['hrData']['HR_FNAME'] ?? '';
|
|
return strcmp($nameA, $nameB);
|
|
});
|
|
}
|
|
|
|
$settingModel = new \app\Models\SystemSettingModel();
|
|
|
|
$orgTaxId = $settingModel->getSetting('org_tax_id', '');
|
|
$taxSignatureName = $settingModel->getSetting('tax_signature_name', '');
|
|
$taxSignaturePosition = $settingModel->getSetting('tax_signature_position', '');
|
|
$taxSignatureScale = $settingModel->getSetting('tax_signature_scale', '100');
|
|
$taxSignaturePosX = $settingModel->getSetting('tax_signature_pos_x', '0');
|
|
$taxSignaturePosY = $settingModel->getSetting('tax_signature_pos_y', '0');
|
|
$taxFontSize = $settingModel->getSetting('tax_font_size', '11pt');
|
|
$orgAddress = $settingModel->getSetting('org_address', 'ต.อ่างทอง อ.เกาะสมุย จ.สุราษฎร์ธานี 84140');
|
|
$taxPayeeAddress = $settingModel->getSetting('tax_payee_address', 'ต.อ่างทอง อ.เกาะสมุย จ.สุราษฎร์ธานี 84140');
|
|
|
|
$this->view('reports/tax_bulk', [
|
|
'bulkData' => $bulkData,
|
|
'year' => $year,
|
|
'groupByLetter' => $groupByLetter,
|
|
'orgTaxId' => $orgTaxId,
|
|
'taxSignatureName' => $taxSignatureName,
|
|
'taxSignaturePosition' => $taxSignaturePosition,
|
|
'taxSignatureScale' => $taxSignatureScale,
|
|
'taxSignaturePosX' => $taxSignaturePosX,
|
|
'taxSignaturePosY' => $taxSignaturePosY,
|
|
'taxFontSize' => $taxFontSize,
|
|
'orgAddress' => $orgAddress,
|
|
'taxPayeeAddress' => $taxPayeeAddress
|
|
]);
|
|
}
|
|
|
|
public function salaryReport() {
|
|
$payrollModel = new PayrollModel();
|
|
$hrModel = new HrPersonModel();
|
|
$officerTypeModel = new OfficerTypeModel();
|
|
|
|
$month = $_GET['month'] ?? date('m');
|
|
$year = $_GET['year'] ?? date('Y');
|
|
$typeId = $_GET['type_id'] ?? '';
|
|
|
|
$officerTypes = $officerTypeModel->getActive();
|
|
$selectedTypeName = '';
|
|
if ($typeId) {
|
|
foreach ($officerTypes as $type) {
|
|
if ($type['id'] == $typeId) {
|
|
$selectedTypeName = $type['name'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$payrollData = $payrollModel->getSalariesByPeriod($month, $year);
|
|
|
|
$nationalIds = array_column($payrollData, 'national_id');
|
|
$hrData = $hrModel->getPersonsByNationalIds($nationalIds);
|
|
|
|
$reportData = [];
|
|
foreach ($payrollData as $row) {
|
|
$nid = $row['national_id'];
|
|
if (isset($hrData[$nid])) {
|
|
$personType = $hrData[$nid]['HR_PERSON_TYPE_NAME'] ?? '';
|
|
|
|
// Filter by type if selected
|
|
if ($typeId && $personType !== $selectedTypeName) {
|
|
continue;
|
|
}
|
|
|
|
$row['hr_prefix'] = $hrData[$nid]['HR_PREFIX_NAME'] ?? '';
|
|
$row['hr_fname'] = $hrData[$nid]['HR_FNAME'] ?? '';
|
|
$row['hr_lname'] = $hrData[$nid]['HR_LNAME'] ?? '';
|
|
$row['hr_position'] = $hrData[$nid]['HR_POSITION_NAME'] ?? '';
|
|
$row['hr_department'] = $hrData[$nid]['HR_DEPARTMENT_SUB_SUB_NAME'] ?? '';
|
|
$row['person_type'] = $personType;
|
|
|
|
// Fetch incomes and deductions to display sums or details if needed
|
|
// But for performance, we can just use the cached totals if available.
|
|
// Wait, if we need specific columns for Excel, we should fetch details.
|
|
// In this case, we fetch them here or in export mode.
|
|
|
|
$reportData[] = $row;
|
|
}
|
|
}
|
|
|
|
// Sort by first name (ignoring prefix)
|
|
usort($reportData, function($a, $b) {
|
|
return strcmp($a['hr_fname'], $b['hr_fname']);
|
|
});
|
|
|
|
$this->view('reports/salary_report', [
|
|
'title' => 'รายงานเงินเดือน | ' . APP_NAME,
|
|
'activeMenu' => 'report_salary',
|
|
'month' => $month,
|
|
'year' => $year,
|
|
'typeId' => $typeId,
|
|
'officerTypes' => $officerTypes,
|
|
'reportData' => $reportData
|
|
]);
|
|
}
|
|
|
|
public function exportExcel() {
|
|
require_once APP_ROOT . '/app/Libraries/SimpleXLSXGen.php';
|
|
|
|
$payrollModel = new PayrollModel();
|
|
$hrModel = new HrPersonModel();
|
|
$officerTypeModel = new OfficerTypeModel();
|
|
$incomeModel = new IncomeMasterModel();
|
|
$deductionModel = new DeductionMasterModel();
|
|
|
|
$month = $_GET['month'] ?? date('m');
|
|
$year = $_GET['year'] ?? date('Y');
|
|
$typeId = $_GET['type_id'] ?? '';
|
|
|
|
$officerTypes = $officerTypeModel->getActive();
|
|
$selectedTypeName = 'ทั้งหมด';
|
|
if ($typeId) {
|
|
foreach ($officerTypes as $type) {
|
|
if ($type['id'] == $typeId) {
|
|
$selectedTypeName = $type['name'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$payrollData = $payrollModel->getSalariesByPeriod($month, $year);
|
|
$nationalIds = array_column($payrollData, 'national_id');
|
|
$hrData = $hrModel->getPersonsByNationalIds($nationalIds);
|
|
|
|
// Fetch all income/deduction codes to build dynamic columns
|
|
$allIncomes = $incomeModel->getAllIncomes();
|
|
$allDeductions = $deductionModel->getAllDeductions();
|
|
|
|
$incomeCols = [];
|
|
foreach ($allIncomes as $inc) {
|
|
$incomeCols[$inc['code']] = $inc['name'];
|
|
}
|
|
|
|
$deductionCols = [];
|
|
foreach ($allDeductions as $ded) {
|
|
$deductionCols[$ded['code']] = $ded['name'];
|
|
}
|
|
|
|
$reportData = [];
|
|
foreach ($payrollData as $row) {
|
|
$nid = $row['national_id'];
|
|
if (isset($hrData[$nid])) {
|
|
$personType = $hrData[$nid]['HR_PERSON_TYPE_NAME'] ?? '';
|
|
|
|
if ($typeId && $personType !== $selectedTypeName) {
|
|
continue;
|
|
}
|
|
|
|
$row['hr_prefix'] = $hrData[$nid]['HR_PREFIX_NAME'] ?? '';
|
|
$row['hr_fname'] = $hrData[$nid]['HR_FNAME'] ?? '';
|
|
$row['hr_lname'] = $hrData[$nid]['HR_LNAME'] ?? '';
|
|
|
|
// Fetch details
|
|
$incomes = $payrollModel->getEmployeeIncomes($row['id']);
|
|
$deductions = $payrollModel->getEmployeeDeductions($row['id']);
|
|
|
|
$row['incomes_detail'] = [];
|
|
foreach ($incomes as $inc) {
|
|
$row['incomes_detail'][$inc['income_code']] = $inc['amount'];
|
|
}
|
|
|
|
$row['deductions_detail'] = [];
|
|
foreach ($deductions as $ded) {
|
|
$row['deductions_detail'][$ded['deduction_code']] = $ded['amount'];
|
|
}
|
|
|
|
$reportData[] = $row;
|
|
}
|
|
}
|
|
|
|
usort($reportData, function($a, $b) {
|
|
return strcmp($a['hr_fname'], $b['hr_fname']);
|
|
});
|
|
|
|
$monthNames = [
|
|
'01' => 'มกราคม', '02' => 'กุมภาพันธ์', '03' => 'มีนาคม', '04' => 'เมษายน',
|
|
'05' => 'พฤษภาคม', '06' => 'มิถุนายน', '07' => 'กรกฎาคม', '08' => 'สิงหาคม',
|
|
'09' => 'กันยายน', '10' => 'ตุลาคม', '11' => 'พฤศจิกายน', '12' => 'ธันวาคม'
|
|
];
|
|
$monthName = $monthNames[$month] ?? $month;
|
|
$thaiYear = $year + 543;
|
|
|
|
$excelData = [];
|
|
|
|
// Header
|
|
$excelData[] = ["รายงานเงินเดือนเจ้าหน้าที่โรงพยาบาล"];
|
|
$excelData[] = ["ประจำเดือน: $monthName $thaiYear", "", "ประเภท: $selectedTypeName"];
|
|
$excelData[] = [];
|
|
|
|
// Columns
|
|
$headerRow = ["ลำดับ", "ชื่อ-สกุล", "เงินเดือนหลัก"];
|
|
foreach ($incomeCols as $code => $name) {
|
|
$headerRow[] = $name;
|
|
}
|
|
$headerRow[] = "รวมรายรับ";
|
|
foreach ($deductionCols as $code => $name) {
|
|
$headerRow[] = $name;
|
|
}
|
|
$headerRow[] = "รวมรายจ่าย";
|
|
$headerRow[] = "รับสุทธิ";
|
|
|
|
$excelData[] = $headerRow;
|
|
|
|
// Data Rows
|
|
$idx = 1;
|
|
foreach ($reportData as $row) {
|
|
$fullName = trim($row['hr_prefix']) . trim($row['hr_fname']) . ' ' . trim($row['hr_lname']);
|
|
$dataRow = [
|
|
$idx++,
|
|
$fullName,
|
|
$row['base_salary']
|
|
];
|
|
|
|
// Incomes
|
|
foreach ($incomeCols as $code => $name) {
|
|
$dataRow[] = $row['incomes_detail'][$code] ?? 0;
|
|
}
|
|
$dataRow[] = $row['total_income'];
|
|
|
|
// Deductions
|
|
foreach ($deductionCols as $code => $name) {
|
|
$dataRow[] = $row['deductions_detail'][$code] ?? 0;
|
|
}
|
|
$dataRow[] = $row['total_deduction'];
|
|
$dataRow[] = $row['net_salary'];
|
|
|
|
$excelData[] = $dataRow;
|
|
}
|
|
|
|
$xlsx = \Shuchkin\SimpleXLSXGen::fromArray($excelData);
|
|
$xlsx->freezePanes('A5');
|
|
|
|
$filename = "รายงานเงินเดือนเจ้าหน้าที่_{$month}_{$year}.xlsx";
|
|
$xlsx->downloadAs($filename);
|
|
exit;
|
|
}
|
|
}
|