Files
sam-api/app/Services/Stats/HrStatService.php

88 lines
3.5 KiB
PHP
Raw Normal View History

<?php
namespace App\Services\Stats;
use App\Models\Stats\Daily\StatHrAttendanceDaily;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
class HrStatService implements StatDomainServiceInterface
{
public function aggregateDaily(int $tenantId, Carbon $date): int
{
$dateStr = $date->format('Y-m-d');
// 전체 직원 수 (tenant_user_profiles 기준)
$totalEmployees = DB::connection('mysql')
->table('user_tenants')
->where('tenant_id', $tenantId)
->where('is_active', true)
->count();
// 근태 (attendances)
$attendanceStats = DB::connection('mysql')
->table('attendances')
->where('tenant_id', $tenantId)
->where('base_date', $dateStr)
->whereNull('deleted_at')
->selectRaw("
COUNT(*) as total_count,
SUM(CASE WHEN status = 'onTime' THEN 1 ELSE 0 END) as on_time_count,
SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late_count,
SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent_count,
SUM(CASE WHEN status = 'overtime' THEN 1 ELSE 0 END) as overtime_count
")
->first();
$attendanceCount = ($attendanceStats->on_time_count ?? 0)
+ ($attendanceStats->late_count ?? 0)
+ ($attendanceStats->overtime_count ?? 0);
$attendanceRate = $totalEmployees > 0 ? ($attendanceCount / $totalEmployees) * 100 : 0;
// 휴가 (leaves)
$leaveStats = DB::connection('mysql')
->table('leaves')
->where('tenant_id', $tenantId)
->where('start_date', '<=', $dateStr)
->where('end_date', '>=', $dateStr)
->where('status', 'approved')
->whereNull('deleted_at')
->selectRaw("
COUNT(*) as total_count,
SUM(CASE WHEN leave_type = 'annual' THEN 1 ELSE 0 END) as annual_count,
SUM(CASE WHEN leave_type = 'sick' THEN 1 ELSE 0 END) as sick_count,
SUM(CASE WHEN leave_type NOT IN ('annual', 'sick') THEN 1 ELSE 0 END) as other_count
")
->first();
// 초과근무 (attendances status = 'overtime')
$overtimeCount = $attendanceStats->overtime_count ?? 0;
StatHrAttendanceDaily::updateOrCreate(
['tenant_id' => $tenantId, 'stat_date' => $dateStr],
[
'total_employees' => $totalEmployees,
'attendance_count' => $attendanceCount,
'late_count' => $attendanceStats->late_count ?? 0,
'absent_count' => $attendanceStats->absent_count ?? 0,
'attendance_rate' => $attendanceRate,
'leave_count' => $leaveStats->total_count ?? 0,
'leave_annual_count' => $leaveStats->annual_count ?? 0,
'leave_sick_count' => $leaveStats->sick_count ?? 0,
'leave_other_count' => $leaveStats->other_count ?? 0,
'overtime_hours' => 0, // attendances에 시간 정보 없음
'overtime_employee_count' => $overtimeCount,
'total_labor_cost' => 0, // 일간 인건비는 급여 정산 시 계산
]
);
return 1;
}
public function aggregateMonthly(int $tenantId, int $year, int $month): int
{
// 인사 도메인은 일간 테이블만 운영 (월간은 Phase 4에서 필요시 추가)
return 0;
}
}