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 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 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); } }