Files
HRM-System/app/Http/Controllers/JobPostingController.php
2026-04-13 08:16:56 +08:00

342 lines
14 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Branch;
use App\Models\CustomQuestion;
use App\Models\Department;
use App\Models\JobLocation;
use App\Models\JobPosting;
use App\Models\JobType;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Inertia\Inertia;
class JobPostingController extends Controller
{
public function index(Request $request)
{
if (Auth::user()->can('manage-job-postings')) {
$query = JobPosting::with(['requisition', 'jobType', 'location', 'department'])->withCount('candidates')->where(function ($q) {
if (Auth::user()->can('manage-any-job-postings')) {
$q->whereIn('created_by', getCompanyAndUsersId());
} elseif (Auth::user()->can('manage-own-job-postings')) {
$q->where('created_by', Auth::id());
} else {
$q->whereRaw('1 = 0');
}
});
if ($request->has('search') && ! empty($request->search)) {
$query->where(function ($q) use ($request) {
$q->where('title', 'like', '%'.$request->search.'%')
->orWhere('job_code', 'like', '%'.$request->search.'%');
});
}
if ($request->has('status') && ! empty($request->status) && $request->status !== 'all') {
$query->where('status', $request->status);
}
if ($request->has('is_published') && $request->is_published !== 'all') {
$query->where('is_published', $request->is_published === 'true');
}
// Handle sorting
$sortField = $request->get('sort_field', 'id');
$sortDirection = $request->get('sort_direction', 'desc');
// Validate sort field to prevent 500 errors
$allowedSortFields = ['job_code', 'title', 'created_at', 'id'];
if (!in_array($sortField, $allowedSortFields)) {
$sortField = 'id';
}
$query->orderBy($sortField, $sortDirection);
$jobPostings = $query->paginate($request->per_page ?? 10);
return Inertia::render('hr/recruitment/job-postings/index', [
'jobPostings' => $jobPostings,
'filters' => $request->all(['search', 'status', 'is_published', 'per_page']),
]);
} else {
return redirect()->back()->with('error', __('Permission Denied.'));
}
}
public function create()
{
if (! Auth::user()->can('create-job-postings')) {
return redirect()->back()->with('error', __('Permission Denied.'));
}
$jobTypes = JobType::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name')
->get();
$locations = JobLocation::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name')
->get();
$branches = Branch::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name')
->get();
$departments = Department::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name', 'branch_id')
->get();
return Inertia::render('hr/recruitment/job-postings/create', [
'jobTypes' => $jobTypes,
'locations' => $locations,
'branches' => $branches,
'departments' => $departments,
'customQuestions' => CustomQuestion::whereIn('created_by', getCompanyAndUsersId())
->select('id', 'question', 'required')
->get(),
]);
}
public function show(JobPosting $jobPosting)
{
if (! Auth::user()->can('view-job-postings')) {
return redirect()->back()->with('error', __('Permission Denied.'));
}
if (! in_array($jobPosting->created_by, getCompanyAndUsersId())) {
return redirect()->back()->with('error', __('You do not have permission to view this job posting'));
}
$jobPosting->load(['requisition', 'jobType', 'location', 'department.branch', 'branch']);
return Inertia::render('hr/recruitment/job-postings/show', [
'jobPosting' => $jobPosting,
'customQuestions' => CustomQuestion::whereIn('created_by', getCompanyAndUsersId())
->select('id', 'question', 'required')
->get(),
]);
}
public function edit(JobPosting $jobPosting)
{
if (! Auth::user()->can('edit-job-postings')) {
return redirect()->back()->with('error', __('Permission Denied.'));
}
if (! in_array($jobPosting->created_by, getCompanyAndUsersId())) {
return redirect()->back()->with('error', __('You do not have permission to edit this job posting'));
}
$jobTypes = JobType::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name')
->get();
$locations = JobLocation::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name')
->get();
$branches = Branch::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name')
->get();
$departments = Department::whereIn('created_by', getCompanyAndUsersId())
->where('status', 'active')
->select('id', 'name', 'branch_id')
->get();
return Inertia::render('hr/recruitment/job-postings/edit', [
'jobPosting' => $jobPosting,
'jobTypes' => $jobTypes,
'locations' => $locations,
'branches' => $branches,
'departments' => $departments,
'customQuestions' => CustomQuestion::whereIn('created_by', getCompanyAndUsersId())
->select('id', 'question', 'required')
->get(),
]);
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'title' => 'required|string|max:255',
'job_type_id' => 'required|exists:job_types,id',
'location_id' => 'required|exists:job_locations,id',
'branch_id' => 'nullable|exists:branches,id',
'department_id' => 'nullable|exists:departments,id',
'priority' => 'nullable|in:Low,Medium,High',
'skills' => 'required|array',
'positions' => 'required|integer|min:1',
'min_experience' => 'required|numeric|min:0',
'max_experience' => 'required|numeric|min:0',
'min_salary' => 'required|numeric|min:0',
'max_salary' => 'required|numeric|min:0',
'description' => 'required|string',
'requirements' => 'required|string',
'benefits' => 'nullable|string',
'start_date' => 'required|date',
'application_deadline' => 'required|date|after:today',
'application_type' => 'required|in:existing,custom',
'application_url' => 'required|string',
'applicant' => 'nullable|array',
'visibility' => 'nullable|array',
'custom_question' => 'nullable|array',
'is_featured' => 'boolean',
]);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
$jobPosting = new JobPosting;
$jobPosting->job_code = JobPosting::generateJobCode(null);
$jobPosting->title = $request->title;
$jobPosting->job_type_id = $request->job_type_id;
$jobPosting->location_id = $request->location_id;
$jobPosting->branch_id = $request->branch_id;
$jobPosting->department_id = $request->department_id;
$jobPosting->priority = $request->priority ?: 'Medium';
$jobPosting->skills = $request->skills;
$jobPosting->positions = $request->positions;
$jobPosting->min_experience = $request->min_experience;
$jobPosting->max_experience = $request->max_experience;
$jobPosting->min_salary = $request->min_salary;
$jobPosting->max_salary = $request->max_salary;
$jobPosting->description = $request->description;
$jobPosting->requirements = $request->requirements;
$jobPosting->benefits = $request->benefits;
$jobPosting->start_date = $request->start_date;
$jobPosting->application_deadline = $request->application_deadline;
$jobPosting->visibility = $request->has('visibility') ? $request->visibility : null;
$jobPosting->custom_question = $request->has('custom_question') ? $request->custom_question : null;
$jobPosting->applicant = $request->has('applicant') ? $request->applicant : null;
$jobPosting->code = uniqid();
$jobPosting->application_type = $request->application_type;
$jobPosting->application_url = $request->application_url;
$jobPosting->is_featured = $request->boolean('is_featured');
$jobPosting->created_by = creatorId();
$jobPosting->save();
return redirect()->route('hr.recruitment.job-postings.index')->with('success', __('Job posting created successfully'));
}
public function update(Request $request, JobPosting $jobPosting)
{
if (! in_array($jobPosting->created_by, getCompanyAndUsersId())) {
return redirect()->back()->with('error', __('You do not have permission to update this job posting'));
}
$validator = Validator::make($request->all(), [
'title' => 'required|string|max:255',
'job_type_id' => 'required|exists:job_types,id',
'location_id' => 'required|exists:job_locations,id',
'branch_id' => 'required|exists:branches,id',
'department_id' => 'nullable|exists:departments,id',
'priority' => 'required|in:Low,Medium,High',
'status' => 'required|in:Draft,Published,Closed',
'positions' => 'required|integer|min:1',
'min_experience' => 'required|numeric|min:0',
'max_experience' => 'nullable|numeric|min:0',
'min_salary' => 'nullable|numeric|min:0',
'max_salary' => 'nullable|numeric|min:0',
'description' => 'nullable|string',
'requirements' => 'nullable|string',
'education' => 'nullable|string',
'benefits' => 'nullable|string',
'start_date' => 'nullable|date',
'application_deadline' => 'nullable|date',
'application_type' => 'required|in:existing,custom',
'application_url' => 'required|string',
'skills' => 'required|array',
'applicant' => 'nullable|array',
'visibility' => 'nullable|array',
'custom_question' => 'nullable|array',
'is_featured' => 'boolean',
]);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator)->withInput();
}
$jobPosting->title = $request->title;
$jobPosting->job_type_id = $request->job_type_id;
$jobPosting->location_id = $request->location_id;
$jobPosting->branch_id = $request->branch_id;
$jobPosting->department_id = $request->department_id;
$jobPosting->priority = $request->priority;
$jobPosting->status = $request->status;
$jobPosting->skills = $request->skills;
$jobPosting->positions = $request->positions;
$jobPosting->min_experience = $request->min_experience;
$jobPosting->max_experience = $request->max_experience;
$jobPosting->min_salary = $request->min_salary;
$jobPosting->max_salary = $request->max_salary;
$jobPosting->description = $request->description;
$jobPosting->requirements = $request->requirements;
$jobPosting->benefits = $request->benefits;
$jobPosting->start_date = $request->start_date;
$jobPosting->application_deadline = $request->application_deadline;
$jobPosting->visibility = $request->has('visibility') ? $request->visibility : null;
$jobPosting->applicant = $request->has('applicant') ? $request->applicant : null;
$jobPosting->custom_question = $request->has('custom_question') ? $request->custom_question : null;
$jobPosting->application_type = $request->application_type;
$jobPosting->application_url = $request->application_url;
$jobPosting->is_featured = $request->boolean('is_featured');
$jobPosting->save();
return redirect()->route('hr.recruitment.job-postings.index')->with('success', __('Job posting updated successfully'));
}
public function destroy(JobPosting $jobPosting)
{
if (! in_array($jobPosting->created_by, getCompanyAndUsersId())) {
return redirect()->back()->with('error', __('You do not have permission to delete this job posting'));
}
if ($jobPosting->candidates()->count() > 0) {
return redirect()->back()->with('error', __('Cannot delete job posting as it has associated candidates'));
}
$jobPosting->delete();
return redirect()->back()->with('success', __('Job posting deleted successfully'));
}
public function publish(JobPosting $jobPosting)
{
if (! in_array($jobPosting->created_by, getCompanyAndUsersId())) {
return redirect()->back()->with('error', __('You do not have permission to publish this job posting'));
}
$jobPosting->update([
'is_published' => true,
'publish_date' => now(),
'status' => 'Published',
]);
return redirect()->back()->with('success', __('Job posting published successfully'));
}
public function unpublish(JobPosting $jobPosting)
{
if (! in_array($jobPosting->created_by, getCompanyAndUsersId())) {
return redirect()->back()->with('error', __('You do not have permission to unpublish this job posting'));
}
$jobPosting->update([
'is_published' => false,
'status' => 'Draft',
]);
return redirect()->back()->with('success', __('Job posting unpublished successfully'));
}
}