177 lines
6.1 KiB
PHP
177 lines
6.1 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)
|
|
{
|
|
$selectedYear = (int) $request->input('year', date('Y'));
|
|
$selectedBranchId = $request->input('branch_id') ? (int) $request->input('branch_id') : null;
|
|
$startMonth = (int) $request->input('start_month', 1);
|
|
$endMonth = (int) $request->input('end_month', 12);
|
|
|
|
// Fetch available years for back-year filtering (last 5 years up to next year)
|
|
$currentYear = (int) date('Y');
|
|
$availableYears = range($currentYear - 4, $currentYear + 1);
|
|
|
|
// Fetch all branches
|
|
$branches = Branch::all(['id', 'name']);
|
|
|
|
// Check if there is an existing run saved for this year and branch
|
|
$existingRun = ThirteenthMonthRun::where('year', $selectedYear)
|
|
->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 preview run on the fly (not saved to DB yet)
|
|
$existingRun = $this->service->generateRun($selectedYear, $selectedBranchId, $startMonth, $endMonth, null, Auth::id());
|
|
}
|
|
|
|
// Fetch historical saved 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' => [
|
|
'year' => $selectedYear,
|
|
'branch_id' => $selectedBranchId,
|
|
'start_month' => $startMonth,
|
|
'end_month' => $endMonth,
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Generate or recalculate a 13th month batch run.
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
$request->validate([
|
|
'year' => 'required|integer|min:2020|max:2035',
|
|
'branch_id' => 'nullable|exists:branches,id',
|
|
'start_month' => 'required|integer|min:1|max:12',
|
|
'end_month' => 'required|integer|min:1|max:12',
|
|
]);
|
|
|
|
$year = (int) $request->year;
|
|
$branchId = $request->branch_id ? (int) $request->branch_id : null;
|
|
$startMonth = (int) $request->start_month;
|
|
$endMonth = (int) $request->end_month;
|
|
|
|
$run = $this->service->generateRun($year, $branchId, $startMonth, $endMonth, null, Auth::id());
|
|
|
|
return redirect()->back()->with('success', "13th Month Pay for {$year} generated successfully!");
|
|
}
|
|
|
|
/**
|
|
* Update an individual employee's adjustment or note.
|
|
*/
|
|
public function updateEntry(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'adjustment_amount' => 'required|numeric',
|
|
'notes' => 'nullable|string|max:255',
|
|
]);
|
|
|
|
$entry = ThirteenthMonthEntry::findOrFail($id);
|
|
$adjustment = (float) $request->adjustment_amount;
|
|
|
|
$entry->adjustment_amount = $adjustment;
|
|
$entry->final_payout = round($entry->computed_amount + $adjustment, 2);
|
|
if ($request->has('notes')) {
|
|
$entry->notes = $request->notes;
|
|
}
|
|
$entry->save();
|
|
|
|
// Recalculate parent run totals
|
|
$run = $entry->run;
|
|
if ($run) {
|
|
$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 for {$run->year} 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->year}_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);
|
|
}
|
|
}
|