561 lines
25 KiB
PHP
561 lines
25 KiB
PHP
<?php
|
|
namespace app\Models;
|
|
|
|
use PDO;
|
|
|
|
class PayrollModel extends Model {
|
|
|
|
/**
|
|
* Get all payroll months with their years
|
|
*/
|
|
public function getAllPayrollPeriods() {
|
|
$sql = "
|
|
SELECT sm.*, sy.year_no
|
|
FROM salary_month sm
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
ORDER BY sy.year_no DESC, sm.month_no DESC
|
|
";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->execute();
|
|
return $stmt->fetchAll();
|
|
}
|
|
|
|
/**
|
|
* Check if a specific month and year already exists
|
|
*/
|
|
public function checkPeriodExists($yearNo, $monthNo) {
|
|
$sql = "
|
|
SELECT sm.id
|
|
FROM salary_month sm
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
WHERE sy.year_no = :yearNo AND sm.month_no = :monthNo
|
|
LIMIT 1
|
|
";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->bindParam(':yearNo', $yearNo, PDO::PARAM_INT);
|
|
$stmt->bindParam(':monthNo', $monthNo, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
return $stmt->fetch() !== false;
|
|
}
|
|
|
|
/**
|
|
* Create a new payroll period
|
|
*/
|
|
public function createPayrollPeriod($yearNo, $monthNo) {
|
|
try {
|
|
$this->db->beginTransaction();
|
|
|
|
// 1. Ensure Year Exists
|
|
$stmtYear = $this->db->prepare("SELECT id FROM salary_year WHERE year_no = :yearNo LIMIT 1");
|
|
$stmtYear->bindParam(':yearNo', $yearNo, PDO::PARAM_INT);
|
|
$stmtYear->execute();
|
|
$yearRow = $stmtYear->fetch();
|
|
|
|
if ($yearRow) {
|
|
$yearId = $yearRow['id'];
|
|
} else {
|
|
$stmtInsertYear = $this->db->prepare("INSERT INTO salary_year (year_no) VALUES (:yearNo)");
|
|
$stmtInsertYear->bindParam(':yearNo', $yearNo, PDO::PARAM_INT);
|
|
$stmtInsertYear->execute();
|
|
$yearId = $this->db->lastInsertId();
|
|
}
|
|
|
|
// 2. Create Month (Draft)
|
|
$stmtInsertMonth = $this->db->prepare("INSERT INTO salary_month (year_id, month_no, status) VALUES (:yearId, :monthNo, 'Draft')");
|
|
$stmtInsertMonth->bindParam(':yearId', $yearId, PDO::PARAM_INT);
|
|
$stmtInsertMonth->bindParam(':monthNo', $monthNo, PDO::PARAM_INT);
|
|
$stmtInsertMonth->execute();
|
|
|
|
$this->db->commit();
|
|
return true;
|
|
|
|
} catch (\PDOException $e) {
|
|
error_log("Error creating payroll period: " . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the previous salary month ID relative to the given year and month
|
|
*/
|
|
public function getPreviousSalaryMonth($yearNo, $monthNo) {
|
|
$prevMonth = $monthNo - 1;
|
|
$prevYear = $yearNo;
|
|
if ($prevMonth < 1) {
|
|
$prevMonth = 12;
|
|
$prevYear--;
|
|
}
|
|
|
|
$sql = "SELECT m.id
|
|
FROM salary_month m
|
|
JOIN salary_year y ON m.year_id = y.id
|
|
WHERE y.year_no = :yearNo AND m.month_no = :monthNo";
|
|
try {
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->execute(['yearNo' => $prevYear, 'monthNo' => $prevMonth]);
|
|
$result = $stmt->fetch();
|
|
return $result ? $result['id'] : false;
|
|
} catch (\PDOException $e) {
|
|
error_log("Error getting previous salary month: " . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Copy employees and their recurring items from previous month
|
|
*/
|
|
public function copyFromPreviousMonth($currentMonthId, $previousMonthId) {
|
|
try {
|
|
$this->beginTransaction();
|
|
|
|
// 1. Get ALL employees from previous month
|
|
$sqlEmployees = "SELECT * FROM employee_salary WHERE salary_month_id = :prev_id";
|
|
$stmtEmp = $this->db->prepare($sqlEmployees);
|
|
$stmtEmp->execute(['prev_id' => $previousMonthId]);
|
|
$prevEmployees = $stmtEmp->fetchAll();
|
|
|
|
$copiedCount = 0;
|
|
$mergedCount = 0;
|
|
|
|
// Prepare statements for inserting NEW employee
|
|
$stmtInsertEmp = $this->db->prepare("
|
|
INSERT INTO employee_salary (
|
|
salary_month_id, employee_code, national_id, first_name, last_name,
|
|
position, department, base_salary, total_income, total_deduction, net_salary
|
|
) VALUES (
|
|
:salary_month_id, :employee_code, :national_id, :first_name, :last_name,
|
|
:position, :department, :base_salary, :total_income, :total_deduction, :net_salary
|
|
)
|
|
");
|
|
|
|
// Prepare statements for getting items from previous month
|
|
$stmtGetIncomes = $this->db->prepare("
|
|
SELECT si.income_master_id, si.amount, im.fund_source
|
|
FROM salary_income si
|
|
JOIN income_master im ON si.income_master_id = im.id
|
|
WHERE si.employee_salary_id = ?
|
|
");
|
|
$stmtGetDeductions = $this->db->prepare("
|
|
SELECT sd.deduction_master_id, sd.amount, dm.fund_source
|
|
FROM salary_deduction sd
|
|
JOIN deduction_master dm ON sd.deduction_master_id = dm.id
|
|
WHERE sd.employee_salary_id = ?
|
|
");
|
|
|
|
// Prepare statements for inserting items
|
|
$stmtInsertIncome = $this->db->prepare("INSERT INTO salary_income (employee_salary_id, income_master_id, amount) VALUES (?, ?, ?)");
|
|
$stmtInsertDeduction = $this->db->prepare("INSERT INTO salary_deduction (employee_salary_id, deduction_master_id, amount) VALUES (?, ?, ?)");
|
|
|
|
// Prepare statements for checking existing items (to prevent duplicates)
|
|
$stmtCheckIncome = $this->db->prepare("SELECT 1 FROM salary_income WHERE employee_salary_id = ? AND income_master_id = ?");
|
|
$stmtCheckDeduction = $this->db->prepare("SELECT 1 FROM salary_deduction WHERE employee_salary_id = ? AND deduction_master_id = ?");
|
|
|
|
// Prepare statement for updating totals of existing employee
|
|
$stmtUpdateTotals = $this->db->prepare("
|
|
UPDATE employee_salary
|
|
SET total_income = total_income + ?,
|
|
total_deduction = total_deduction + ?,
|
|
net_salary = net_salary + ? - ?
|
|
WHERE id = ?
|
|
");
|
|
|
|
// Prepare statement to check if employee already exists in current month
|
|
$stmtCheckEmp = $this->db->prepare("SELECT id FROM employee_salary WHERE salary_month_id = ? AND national_id = ?");
|
|
|
|
foreach ($prevEmployees as $emp) {
|
|
// Check if employee already exists in current month
|
|
$stmtCheckEmp->execute([$currentMonthId, $emp['national_id']]);
|
|
$existingEmp = $stmtCheckEmp->fetch();
|
|
|
|
if (!$existingEmp) {
|
|
// --- CASE 1: Employee DOES NOT exist in current month (Fully copy) ---
|
|
$stmtInsertEmp->execute([
|
|
'salary_month_id' => $currentMonthId,
|
|
'employee_code' => $emp['employee_code'],
|
|
'national_id' => $emp['national_id'],
|
|
'first_name' => $emp['first_name'],
|
|
'last_name' => $emp['last_name'],
|
|
'position' => $emp['position'],
|
|
'department' => $emp['department'],
|
|
'base_salary' => $emp['base_salary'],
|
|
'total_income' => $emp['total_income'],
|
|
'total_deduction' => $emp['total_deduction'],
|
|
'net_salary' => $emp['net_salary']
|
|
]);
|
|
$newEmpId = $this->db->lastInsertId();
|
|
|
|
// Copy ALL incomes
|
|
$stmtGetIncomes->execute([$emp['id']]);
|
|
$incomes = $stmtGetIncomes->fetchAll();
|
|
foreach ($incomes as $inc) {
|
|
$stmtInsertIncome->execute([$newEmpId, $inc['income_master_id'], $inc['amount']]);
|
|
}
|
|
|
|
// Copy ALL deductions
|
|
$stmtGetDeductions->execute([$emp['id']]);
|
|
$deductions = $stmtGetDeductions->fetchAll();
|
|
foreach ($deductions as $ded) {
|
|
$stmtInsertDeduction->execute([$newEmpId, $ded['deduction_master_id'], $ded['amount']]);
|
|
}
|
|
|
|
$copiedCount++;
|
|
} else {
|
|
// --- CASE 2: Employee EXISTS in current month (Merge HOSPITAL items) ---
|
|
$currEmpId = $existingEmp['id'];
|
|
$addedIncomeAmount = 0;
|
|
$addedDeductionAmount = 0;
|
|
|
|
// Copy ONLY HOSPITAL incomes
|
|
$stmtGetIncomes->execute([$emp['id']]);
|
|
$incomes = $stmtGetIncomes->fetchAll();
|
|
foreach ($incomes as $inc) {
|
|
if (strtoupper($inc['fund_source']) === 'HOSPITAL') {
|
|
// Prevent duplicate insertion
|
|
$stmtCheckIncome->execute([$currEmpId, $inc['income_master_id']]);
|
|
if (!$stmtCheckIncome->fetch()) {
|
|
$stmtInsertIncome->execute([$currEmpId, $inc['income_master_id'], $inc['amount']]);
|
|
$addedIncomeAmount += $inc['amount'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Copy ONLY HOSPITAL deductions
|
|
$stmtGetDeductions->execute([$emp['id']]);
|
|
$deductions = $stmtGetDeductions->fetchAll();
|
|
foreach ($deductions as $ded) {
|
|
if (strtoupper($ded['fund_source']) === 'HOSPITAL') {
|
|
// Prevent duplicate insertion
|
|
$stmtCheckDeduction->execute([$currEmpId, $ded['deduction_master_id']]);
|
|
if (!$stmtCheckDeduction->fetch()) {
|
|
$stmtInsertDeduction->execute([$currEmpId, $ded['deduction_master_id'], $ded['amount']]);
|
|
$addedDeductionAmount += $ded['amount'];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update employee totals if anything was added
|
|
if ($addedIncomeAmount > 0 || $addedDeductionAmount > 0) {
|
|
$stmtUpdateTotals->execute([
|
|
$addedIncomeAmount,
|
|
$addedDeductionAmount,
|
|
$addedIncomeAmount, // Add to net
|
|
$addedDeductionAmount, // Subtract from net
|
|
$currEmpId
|
|
]);
|
|
}
|
|
|
|
$mergedCount++;
|
|
}
|
|
}
|
|
|
|
$this->commit();
|
|
return ['copied' => $copiedCount, 'merged' => $mergedCount];
|
|
|
|
} catch (\PDOException $e) {
|
|
$this->rollBack();
|
|
error_log("Error copying from previous month: " . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// --- Methods for Import ---
|
|
|
|
public function beginTransaction() {
|
|
if (!$this->db->inTransaction()) {
|
|
$this->db->beginTransaction();
|
|
}
|
|
}
|
|
|
|
public function commit() {
|
|
if ($this->db->inTransaction()) {
|
|
$this->db->commit();
|
|
}
|
|
}
|
|
|
|
public function rollBack() {
|
|
if ($this->db->inTransaction()) {
|
|
$this->db->rollBack();
|
|
}
|
|
}
|
|
|
|
public function getSalaryMonthById($id) {
|
|
$stmt = $this->db->prepare("SELECT sm.*, sy.year_no FROM salary_month sm JOIN salary_year sy ON sm.year_id = sy.id WHERE sm.id = ?");
|
|
$stmt->execute([$id]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function updateSalaryMonthStatus($id, $status) {
|
|
$stmt = $this->db->prepare("UPDATE salary_month SET status = ? WHERE id = ?");
|
|
return $stmt->execute([$status, $id]);
|
|
}
|
|
|
|
public function logImportHistory($userId, $salaryMonthId, $fileName, $total, $success, $error, $status = 'success') {
|
|
$sql = "INSERT INTO import_history (user_id, salary_month_id, file_name, status, total_records, success_records, error_records)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->execute([$userId, $salaryMonthId, $fileName, $status, $total, $success, $error]);
|
|
return $this->db->lastInsertId();
|
|
}
|
|
|
|
public function insertEmployeeSalary($data) {
|
|
$check = $this->db->prepare("SELECT id FROM employee_salary WHERE salary_month_id = ? AND employee_code = ?");
|
|
$check->execute([$data['salary_month_id'], $data['employee_code']]);
|
|
$existing = $check->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if ($existing) {
|
|
$sql = "UPDATE employee_salary SET national_id = ?, first_name = ?, last_name = ?,
|
|
position = ?, department = ?, base_salary = ?, total_income = ?, total_deduction = ?, net_salary = ?
|
|
WHERE id = ?";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->execute([
|
|
$data['national_id'], $data['first_name'], $data['last_name'],
|
|
$data['position'] ?? null, $data['department'] ?? null,
|
|
$data['base_salary'], $data['total_income'], $data['total_deduction'], $data['net_salary'],
|
|
$existing['id']
|
|
]);
|
|
|
|
// Delete old details
|
|
$this->db->prepare("DELETE FROM salary_income WHERE employee_salary_id = ?")->execute([$existing['id']]);
|
|
$this->db->prepare("DELETE FROM salary_deduction WHERE employee_salary_id = ?")->execute([$existing['id']]);
|
|
|
|
return $existing['id'];
|
|
} else {
|
|
$sql = "INSERT INTO employee_salary (salary_month_id, employee_code, national_id, first_name, last_name, position, department, base_salary, total_income, total_deduction, net_salary)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->execute([
|
|
$data['salary_month_id'], $data['employee_code'], $data['national_id'],
|
|
$data['first_name'], $data['last_name'], $data['position'] ?? null, $data['department'] ?? null, $data['base_salary'],
|
|
$data['total_income'], $data['total_deduction'], $data['net_salary']
|
|
]);
|
|
return $this->db->lastInsertId();
|
|
}
|
|
}
|
|
|
|
public function insertSalaryIncome($employeeSalaryId, $incomeMasterId, $amount) {
|
|
$sql = "INSERT INTO salary_income (employee_salary_id, income_master_id, amount) VALUES (?, ?, ?)";
|
|
$stmt = $this->db->prepare($sql);
|
|
return $stmt->execute([$employeeSalaryId, $incomeMasterId, $amount]);
|
|
}
|
|
|
|
public function insertSalaryDeduction($employeeSalaryId, $deductionMasterId, $amount) {
|
|
$sql = "INSERT INTO salary_deduction (employee_salary_id, deduction_master_id, amount) VALUES (?, ?, ?)";
|
|
$stmt = $this->db->prepare($sql);
|
|
return $stmt->execute([$employeeSalaryId, $deductionMasterId, $amount]);
|
|
}
|
|
|
|
public function getPeriodStats($salaryMonthId) {
|
|
$stmt = $this->db->prepare("SELECT COUNT(id) as total_emp, SUM(net_salary) as total_net FROM employee_salary WHERE salary_month_id = ?");
|
|
$stmt->execute([$salaryMonthId]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function clearDataForPeriod($salaryMonthId) {
|
|
try {
|
|
$this->beginTransaction();
|
|
// Delete all employee salaries for this month (cascade will delete salary_income, salary_deduction, slip logs)
|
|
$stmt = $this->db->prepare("DELETE FROM employee_salary WHERE salary_month_id = ?");
|
|
$stmt->execute([$salaryMonthId]);
|
|
|
|
// Update status back to Draft
|
|
$this->updateSalaryMonthStatus($salaryMonthId, 'Draft');
|
|
|
|
$this->commit();
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
$this->rollBack();
|
|
error_log("Error clearing data: " . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function getEmployeesBySalaryMonthId($salaryMonthId) {
|
|
$stmt = $this->db->prepare("SELECT * FROM employee_salary WHERE salary_month_id = ? ORDER BY first_name ASC");
|
|
$stmt->execute([$salaryMonthId]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function deleteEmployeeSalary($id) {
|
|
try {
|
|
$this->beginTransaction();
|
|
// Delete incomes and deductions first
|
|
$this->db->prepare("DELETE FROM salary_income WHERE employee_salary_id = ?")->execute([$id]);
|
|
$this->db->prepare("DELETE FROM salary_deduction WHERE employee_salary_id = ?")->execute([$id]);
|
|
|
|
// Delete main record
|
|
$stmt = $this->db->prepare("DELETE FROM employee_salary WHERE id = ?");
|
|
$stmt->execute([$id]);
|
|
|
|
$this->commit();
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
$this->rollBack();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function getEmployeeSalaryById($id) {
|
|
$stmt = $this->db->prepare("SELECT * FROM employee_salary WHERE id = ?");
|
|
$stmt->execute([$id]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function getEmployeeIncomes($employeeSalaryId) {
|
|
$stmt = $this->db->prepare("SELECT si.*, im.name, im.code, im.fund_source
|
|
FROM salary_income si
|
|
JOIN income_master im ON si.income_master_id = im.id
|
|
WHERE si.employee_salary_id = ?");
|
|
$stmt->execute([$employeeSalaryId]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function getEmployeeDeductions($employeeSalaryId) {
|
|
$stmt = $this->db->prepare("SELECT sd.*, dm.name, dm.code, dm.fund_source
|
|
FROM salary_deduction sd
|
|
JOIN deduction_master dm ON sd.deduction_master_id = dm.id
|
|
WHERE sd.employee_salary_id = ?");
|
|
$stmt->execute([$employeeSalaryId]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function updateEmployeeSalaryDetails($id, $baseSalary, $incomes, $deductions, $totalIncome, $totalDeduction, $netSalary) {
|
|
try {
|
|
$this->beginTransaction();
|
|
|
|
// 1. Update main record
|
|
$stmt = $this->db->prepare("UPDATE employee_salary
|
|
SET base_salary = ?, total_income = ?, total_deduction = ?, net_salary = ?
|
|
WHERE id = ?");
|
|
$stmt->execute([$baseSalary, $totalIncome, $totalDeduction, $netSalary, $id]);
|
|
|
|
// 2. Delete old incomes and deductions
|
|
$this->db->prepare("DELETE FROM salary_income WHERE employee_salary_id = ?")->execute([$id]);
|
|
$this->db->prepare("DELETE FROM salary_deduction WHERE employee_salary_id = ?")->execute([$id]);
|
|
|
|
// 3. Insert new incomes
|
|
if (!empty($incomes)) {
|
|
$stmtInc = $this->db->prepare("INSERT INTO salary_income (employee_salary_id, income_master_id, amount) VALUES (?, ?, ?)");
|
|
foreach ($incomes as $inc) {
|
|
$stmtInc->execute([$id, $inc['id'], $inc['amount']]);
|
|
}
|
|
}
|
|
|
|
// 4. Insert new deductions
|
|
if (!empty($deductions)) {
|
|
$stmtDed = $this->db->prepare("INSERT INTO salary_deduction (employee_salary_id, deduction_master_id, amount) VALUES (?, ?, ?)");
|
|
foreach ($deductions as $ded) {
|
|
$stmtDed->execute([$id, $ded['id'], $ded['amount']]);
|
|
}
|
|
}
|
|
|
|
$this->commit();
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
$this->rollBack();
|
|
error_log("Error updating employee salary: " . $e->getMessage());
|
|
return false;
|
|
}
|
|
}
|
|
public function getSalariesByPeriod($month, $year) {
|
|
$stmt = $this->db->prepare("SELECT es.*, sm.month_no as month, sy.year_no as year
|
|
FROM employee_salary es
|
|
JOIN salary_month sm ON es.salary_month_id = sm.id
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
WHERE sm.month_no = ? AND sy.year_no = ?
|
|
ORDER BY es.first_name ASC");
|
|
$stmt->execute([$month, $year]);
|
|
return $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function getSalaryByNationalId($nationalId, $month, $year) {
|
|
$stmt = $this->db->prepare("SELECT es.*, sm.month_no as month, sy.year_no as year
|
|
FROM employee_salary es
|
|
JOIN salary_month sm ON es.salary_month_id = sm.id
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
WHERE REPLACE(es.national_id, '-', '') = ? AND sm.month_no = ? AND sy.year_no = ?");
|
|
$stmt->execute([$nationalId, $month, $year]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function getYearlyTaxSummary($nationalId, $year) {
|
|
$stmt = $this->db->prepare("
|
|
SELECT
|
|
SUM(es.total_income) as total_income,
|
|
SUM(
|
|
(SELECT SUM(si.amount) FROM salary_income si
|
|
JOIN income_master im ON si.income_master_id = im.id
|
|
WHERE si.employee_salary_id = es.id AND im.is_taxable = 1)
|
|
) as total_taxable_income,
|
|
SUM(
|
|
(SELECT SUM(sd.amount) FROM salary_deduction sd
|
|
JOIN deduction_master dm ON sd.deduction_master_id = dm.id
|
|
WHERE sd.employee_salary_id = es.id AND dm.code = 'TAX')
|
|
) as total_tax,
|
|
SUM(
|
|
(SELECT SUM(sd.amount) FROM salary_deduction sd
|
|
JOIN deduction_master dm ON sd.deduction_master_id = dm.id
|
|
WHERE sd.employee_salary_id = es.id AND dm.code IN ('FUND_A', 'FUND_B'))
|
|
) as total_ssf
|
|
FROM employee_salary es
|
|
JOIN salary_month sm ON es.salary_month_id = sm.id
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
WHERE REPLACE(es.national_id, '-', '') = ? AND sy.year_no = ? AND sm.status IN ('Locked', 'Published')
|
|
");
|
|
$stmt->execute([$nationalId, $year]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function getYearlySummary($year) {
|
|
$sql = "SELECT sm.month_no AS month,
|
|
SUM(e.total_income) AS sum_income,
|
|
SUM(e.total_deduction) AS sum_deduction
|
|
FROM salary_month sm
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
LEFT JOIN employee_salary e ON sm.id = e.salary_month_id
|
|
WHERE sy.year_no = :year
|
|
GROUP BY sm.month_no
|
|
ORDER BY sm.month_no ASC";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->bindParam(':year', $year, \PDO::PARAM_STR);
|
|
$stmt->execute();
|
|
|
|
$results = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
|
|
$summary = [];
|
|
foreach($results as $row) {
|
|
$summary[$row['month']] = [
|
|
'income' => (float)($row['sum_income'] ?? 0),
|
|
'deduction' => (float)($row['sum_deduction'] ?? 0)
|
|
];
|
|
}
|
|
return $summary;
|
|
}
|
|
|
|
public function getAvailableSlipsByNationalId($nationalId) {
|
|
$sql = "SELECT sm.month_no, sy.year_no
|
|
FROM employee_salary es
|
|
JOIN salary_month sm ON es.salary_month_id = sm.id
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
WHERE REPLACE(es.national_id, '-', '') = :nationalId AND sm.status IN ('Locked', 'Published')
|
|
ORDER BY sy.year_no DESC, sm.month_no DESC";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->bindParam(':nationalId', $nationalId, \PDO::PARAM_STR);
|
|
$stmt->execute();
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
public function getAvailableTaxesByNationalId($nationalId) {
|
|
$sql = "SELECT DISTINCT sy.year_no
|
|
FROM employee_salary es
|
|
JOIN salary_month sm ON es.salary_month_id = sm.id
|
|
JOIN salary_year sy ON sm.year_id = sy.id
|
|
WHERE REPLACE(es.national_id, '-', '') = :nationalId AND sm.status IN ('Locked', 'Published')
|
|
ORDER BY sy.year_no DESC";
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->bindParam(':nationalId', $nationalId, \PDO::PARAM_STR);
|
|
$stmt->execute();
|
|
return $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
}
|
|
}
|
|
?>
|