Files
HRM-System/app/Http/Controllers/ThirteenthMonthController.php

200 lines
7.3 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Branch;
use App\Models\ThirteenthMonthRun;
use App\Models\ThirteenthMonthEntry;
use App\Services\ThirteenthMonthService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Inertia\Inertia;
class ThirteenthMonthController extends Controller
{
protected $service;
public function __construct(ThirteenthMonthService $service)
{
$this->service = $service;
}
/**
* Display the 13th Month Pay management index page.
*/
public function index(Request $request)
{
$currentYear = (int) date('Y');
$startYear = $request->input('start_year') ? (int) $request->input('start_year') : $currentYear;
$startMonth = $request->input('start_month') ? (int) $request->input('start_month') : 1;
$endYear = $request->input('end_year') ? (int) $request->input('end_year') : $currentYear;
$endMonth = $request->input('end_month') ? (int) $request->input('end_month') : 12;
$selectedBranchId = $request->input('branch_id') ? (int) $request->input('branch_id') : null;
// Available years for back-year filtering (last 5 years up to next year)
$availableYears = range($currentYear - 5, $currentYear + 1);
$branches = Branch::all(['id', 'name']);
// Check if an existing run matches these range parameters
$existingRun = ThirteenthMonthRun::where('start_year', $startYear)
->where('start_month', $startMonth)
->where('end_year', $endYear)
->where('end_month', $endMonth)
->when($selectedBranchId, function ($q) use ($selectedBranchId) {
$q->where('branch_id', $selectedBranchId);
}, function ($q) {
$q->whereNull('branch_id');
})
->with(['entries.employee.user', 'entries.employee.designation', 'entries.employee.department', 'branch', 'creator'])
->first();
if (!$existingRun) {
// Generate dynamic run preview on the fly
$existingRun = $this->service->generateRun($startYear, $startMonth, $endYear, $endMonth, $selectedBranchId, null, Auth::id());
}
// Fetch historical runs list
$pastRuns = ThirteenthMonthRun::with(['branch', 'creator'])
->orderBy('year', 'desc')
->orderBy('created_at', 'desc')
->get();
return Inertia::render('hr/thirteenth-month/index', [
'activeRun' => $existingRun,
'pastRuns' => $pastRuns,
'branches' => $branches,
'availableYears' => array_values($availableYears),
'filters' => [
'start_year' => $startYear,
'start_month' => $startMonth,
'end_year' => $endYear,
'end_month' => $endMonth,
'branch_id' => $selectedBranchId,
],
]);
}
/**
* Generate or recalculate a 13th month batch run with custom date ranges.
*/
public function store(Request $request)
{
$request->validate([
'start_year' => 'required|integer|min:2020|max:2035',
'start_month' => 'required|integer|min:1|max:12',
'end_year' => 'required|integer|min:2020|max:2035',
'end_month' => 'required|integer|min:1|max:12',
'branch_id' => 'nullable|exists:branches,id',
]);
$startYear = (int) $request->start_year;
$startMonth = (int) $request->start_month;
$endYear = (int) $request->end_year;
$endMonth = (int) $request->end_month;
$branchId = $request->branch_id ? (int) $request->branch_id : null;
$run = $this->service->generateRun($startYear, $startMonth, $endYear, $endMonth, $branchId, null, Auth::id());
return redirect()->back()->with('success', '13th Month Pay range calculated successfully!');
}
/**
* Update an individual employee's adjustment, monthly earnings breakdown, or notes.
*/
public function updateEntry(Request $request, $id)
{
$request->validate([
'adjustment_amount' => 'nullable|numeric',
'monthly_earnings' => 'nullable|array',
'notes' => 'nullable|string|max:255',
]);
$entry = ThirteenthMonthEntry::findOrFail($id);
if ($request->has('adjustment_amount')) {
$entry->adjustment_amount = (float) $request->adjustment_amount;
}
if ($request->has('monthly_earnings')) {
$monthlyEarnings = $request->monthly_earnings;
$entry->monthly_earnings = $monthlyEarnings;
// Recalculate employee total base earned, computed amount, and final payout
$totalBase = array_sum(array_map('floatval', $monthlyEarnings));
$entry->total_base_earned = round($totalBase, 2);
$entry->computed_amount = round($totalBase / 12, 2);
}
$entry->final_payout = round($entry->computed_amount + $entry->adjustment_amount, 2);
if ($request->has('notes')) {
$entry->notes = $request->notes;
}
$entry->save();
// Recalculate parent run totals
$run = $entry->run;
if ($run) {
$run->total_base_earnings = round($run->entries()->sum('total_base_earned'), 2);
$run->total_payout = round($run->entries()->sum('final_payout'), 2);
$run->save();
}
return redirect()->back()->with('success', '13th Month entry updated successfully.');
}
/**
* Approve and lock the 13th Month Pay run.
*/
public function approveRun(Request $request, $id)
{
$run = ThirteenthMonthRun::findOrFail($id);
$run->status = 'approved';
$run->save();
return redirect()->back()->with('success', '13th Month Pay run has been approved!');
}
/**
* Export 13th Month Payout Schedule as Bank CSV.
*/
public function exportCsv($id)
{
$run = ThirteenthMonthRun::with(['entries.employee.user', 'entries.employee.department', 'branch'])->findOrFail($id);
$filename = "13th_Month_Pay_{$run->start_year}_{$run->start_month}_to_{$run->end_year}_{$run->end_month}_Export.csv";
$headers = [
'Content-Type' => 'text/csv',
'Content-Disposition' => "attachment; filename=\"{$filename}\"",
];
$callback = function () use ($run) {
$file = fopen('php://output', 'w');
fputcsv($file, ['Employee Code', 'Employee Name', 'Department', 'Total Base Earned', 'Computed 13th Month', 'Adjustment', 'Final Net Payout']);
foreach ($run->entries as $entry) {
$empCode = $entry->employee->employee_code ?? "EMP-{$entry->employee_id}";
$empName = $entry->employee->user->name ?? 'Staff';
$dept = $entry->employee->department->name ?? 'General';
fputcsv($file, [
$empCode,
$empName,
$dept,
number_format($entry->total_base_earned, 2, '.', ''),
number_format($entry->computed_amount, 2, '.', ''),
number_format($entry->adjustment_amount, 2, '.', ''),
number_format($entry->final_payout, 2, '.', ''),
]);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
}