Files
sam-manage/app/Services/HR/AttendanceRequestService.php

149 lines
4.2 KiB
PHP
Raw Normal View History

<?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(),
]
);
}
}
}