149 lines
4.2 KiB
PHP
149 lines
4.2 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Services\HR;
|
||
|
|
|
||
|
|
use App\Models\HR\Attendance;
|
||
|
|
use App\Models\HR\AttendanceRequest;
|
||
|
|
use Carbon\CarbonPeriod;
|
||
|
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
|
||
|
|
class AttendanceRequestService
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* 신청 목록 조회
|
||
|
|
*/
|
||
|
|
public function getRequests(array $filters = [], int $perPage = 20): LengthAwarePaginator
|
||
|
|
{
|
||
|
|
$tenantId = session('selected_tenant_id');
|
||
|
|
|
||
|
|
$query = AttendanceRequest::query()
|
||
|
|
->with(['user', 'user.tenantProfiles' => fn ($q) => $q->where('tenant_id', $tenantId), 'approver'])
|
||
|
|
->forTenant($tenantId)
|
||
|
|
->orderByRaw("FIELD(status, 'pending', 'approved', 'rejected')")
|
||
|
|
->orderBy('created_at', 'desc');
|
||
|
|
|
||
|
|
if (! empty($filters['status'])) {
|
||
|
|
$query->where('status', $filters['status']);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (! empty($filters['user_id'])) {
|
||
|
|
$query->where('user_id', $filters['user_id']);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $query->paginate($perPage);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 신청 등록
|
||
|
|
*/
|
||
|
|
public function storeRequest(array $data): AttendanceRequest
|
||
|
|
{
|
||
|
|
$tenantId = session('selected_tenant_id');
|
||
|
|
|
||
|
|
return AttendanceRequest::create([
|
||
|
|
'tenant_id' => $tenantId,
|
||
|
|
'user_id' => $data['user_id'],
|
||
|
|
'request_type' => $data['request_type'],
|
||
|
|
'start_date' => $data['start_date'],
|
||
|
|
'end_date' => $data['end_date'],
|
||
|
|
'reason' => $data['reason'] ?? null,
|
||
|
|
'status' => 'pending',
|
||
|
|
'json_details' => $data['json_details'] ?? null,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 승인 처리
|
||
|
|
*/
|
||
|
|
public function approve(int $id): ?AttendanceRequest
|
||
|
|
{
|
||
|
|
$tenantId = session('selected_tenant_id');
|
||
|
|
|
||
|
|
$request = AttendanceRequest::query()
|
||
|
|
->forTenant($tenantId)
|
||
|
|
->where('status', 'pending')
|
||
|
|
->find($id);
|
||
|
|
|
||
|
|
if (! $request) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
return DB::transaction(function () use ($request, $tenantId) {
|
||
|
|
$request->update([
|
||
|
|
'status' => 'approved',
|
||
|
|
'approved_by' => auth()->id(),
|
||
|
|
'approved_at' => now(),
|
||
|
|
]);
|
||
|
|
|
||
|
|
// 승인 시 해당 기간의 근태 레코드 자동 생성
|
||
|
|
$this->createAttendanceRecords($request, $tenantId);
|
||
|
|
|
||
|
|
return $request->fresh(['user', 'approver']);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 반려 처리
|
||
|
|
*/
|
||
|
|
public function reject(int $id, ?string $reason = null): ?AttendanceRequest
|
||
|
|
{
|
||
|
|
$tenantId = session('selected_tenant_id');
|
||
|
|
|
||
|
|
$request = AttendanceRequest::query()
|
||
|
|
->forTenant($tenantId)
|
||
|
|
->where('status', 'pending')
|
||
|
|
->find($id);
|
||
|
|
|
||
|
|
if (! $request) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
$request->update([
|
||
|
|
'status' => 'rejected',
|
||
|
|
'approved_by' => auth()->id(),
|
||
|
|
'approved_at' => now(),
|
||
|
|
'reject_reason' => $reason,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $request->fresh(['user', 'approver']);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 승인 후 근태 레코드 자동 생성
|
||
|
|
*/
|
||
|
|
private function createAttendanceRecords(AttendanceRequest $request, int $tenantId): void
|
||
|
|
{
|
||
|
|
$statusMap = [
|
||
|
|
'vacation' => 'vacation',
|
||
|
|
'businessTrip' => 'businessTrip',
|
||
|
|
'remote' => 'remote',
|
||
|
|
'fieldWork' => 'fieldWork',
|
||
|
|
];
|
||
|
|
|
||
|
|
$status = $statusMap[$request->request_type] ?? $request->request_type;
|
||
|
|
|
||
|
|
$period = CarbonPeriod::create($request->start_date, $request->end_date);
|
||
|
|
|
||
|
|
foreach ($period as $date) {
|
||
|
|
// 주말 제외
|
||
|
|
if ($date->isWeekend()) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
Attendance::updateOrCreate(
|
||
|
|
[
|
||
|
|
'tenant_id' => $tenantId,
|
||
|
|
'user_id' => $request->user_id,
|
||
|
|
'base_date' => $date->toDateString(),
|
||
|
|
],
|
||
|
|
[
|
||
|
|
'status' => $status,
|
||
|
|
'remarks' => $request->reason ? mb_substr($request->reason, 0, 100) : null,
|
||
|
|
'updated_by' => auth()->id(),
|
||
|
|
]
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|