tenantId(); $now = Carbon::now(); // 기본값 설정 $year = $year ?? $now->year; $limitType = $limitType ?? 'quarterly'; $calculationType = $calculationType ?? 'fixed'; $fixedAmountPerMonth = $fixedAmountPerMonth ?? 200000; $ratio = $ratio ?? 0.05; $quarter = $quarter ?? $now->quarter; // 기간 범위 계산 if ($limitType === 'annual') { $startDate = Carbon::create($year, 1, 1)->format('Y-m-d'); $endDate = Carbon::create($year, 12, 31)->format('Y-m-d'); $periodLabel = "{$year}년"; $monthCount = 12; } else { $startDate = Carbon::create($year, ($quarter - 1) * 3 + 1, 1)->format('Y-m-d'); $endDate = Carbon::create($year, $quarter * 3, 1)->endOfMonth()->format('Y-m-d'); $periodLabel = "{$quarter}사분기"; $monthCount = 3; } // 직원 수 조회 $employeeCount = $this->getEmployeeCount($tenantId); // 한도 계산 if ($calculationType === 'fixed') { $annualLimit = $fixedAmountPerMonth * 12 * $employeeCount; } else { // 급여 총액 기반 비율 계산 $totalSalary = $this->getTotalSalary($tenantId, $year); $annualLimit = $totalSalary * $ratio; } $periodLimit = $limitType === 'annual' ? $annualLimit : ($annualLimit / 4); // 복리후생비 사용액 조회 $usedAmount = $this->getUsedAmount($tenantId, $startDate, $endDate); // 잔여 한도 $remainingLimit = max(0, $periodLimit - $usedAmount); // 카드 데이터 구성 $cards = [ [ 'id' => 'wf_annual_limit', 'label' => '당해년도 복리후생비 한도', 'amount' => (int) $annualLimit, ], [ 'id' => 'wf_period_limit', 'label' => "{{$periodLabel}} 복리후생비 총 한도", 'amount' => (int) $periodLimit, ], [ 'id' => 'wf_remaining', 'label' => "{{$periodLabel}} 복리후생비 잔여한도", 'amount' => (int) $remainingLimit, ], [ 'id' => 'wf_used', 'label' => "{{$periodLabel}} 복리후생비 사용금액", 'amount' => (int) $usedAmount, ], ]; // 체크포인트 생성 $checkPoints = $this->generateCheckPoints( $tenantId, $employeeCount, $usedAmount, $monthCount, $startDate, $endDate ); return [ 'cards' => $cards, 'check_points' => $checkPoints, ]; } /** * 직원 수 조회 */ private function getEmployeeCount(int $tenantId): int { $count = DB::table('users') ->join('user_tenants', 'users.id', '=', 'user_tenants.user_id') ->where('user_tenants.tenant_id', $tenantId) ->where('user_tenants.is_active', true) ->whereNull('users.deleted_at') ->count(); return $count ?: 50; // 임시 기본값 } /** * 연간 급여 총액 조회 */ private function getTotalSalary(int $tenantId, int $year): float { // TODO: 실제 급여 테이블에서 조회 // payroll 또는 salary_histories에서 연간 급여 합계 return 2000000000; // 임시 기본값 (20억) } /** * 복리후생비 사용액 조회 */ private function getUsedAmount(int $tenantId, string $startDate, string $endDate): float { // TODO: 실제 복리후생비 계정과목에서 조회 $amount = DB::table('expense_accounts') ->where('tenant_id', $tenantId) ->where('account_type', 'welfare') ->whereBetween('expense_date', [$startDate, $endDate]) ->whereNull('deleted_at') ->sum('amount'); return $amount ?: 5123000; // 임시 기본값 } /** * 월 식대 조회 */ private function getMonthlyMealAmount(int $tenantId, string $startDate, string $endDate): float { // TODO: 식대 항목 조회 $amount = DB::table('expense_accounts') ->where('tenant_id', $tenantId) ->where('account_type', 'welfare') ->where('sub_type', 'meal') ->whereBetween('expense_date', [$startDate, $endDate]) ->whereNull('deleted_at') ->sum('amount'); return $amount ?: 0; } /** * 체크포인트 생성 */ private function generateCheckPoints( int $tenantId, int $employeeCount, float $usedAmount, int $monthCount, string $startDate, string $endDate ): array { $checkPoints = []; // 1인당 월 복리후생비 계산 $perPersonMonthly = $employeeCount > 0 && $monthCount > 0 ? $usedAmount / $employeeCount / $monthCount : 0; $perPersonFormatted = number_format($perPersonMonthly / 10000); // 업계 평균 비교 if ($perPersonMonthly >= self::INDUSTRY_AVG_MIN && $perPersonMonthly <= self::INDUSTRY_AVG_MAX) { $checkPoints[] = [ 'id' => 'wf_cp_normal', 'type' => 'success', 'message' => "1인당 월 복리후생비 {$perPersonFormatted}만원. 업계 평균(15~25만원) 내 정상 운영 중입니다.", 'highlights' => [ ['text' => "1인당 월 복리후생비 {$perPersonFormatted}만원", 'color' => 'green'], ], ]; } elseif ($perPersonMonthly < self::INDUSTRY_AVG_MIN) { $checkPoints[] = [ 'id' => 'wf_cp_low', 'type' => 'warning', 'message' => "1인당 월 복리후생비 {$perPersonFormatted}만원. 업계 평균(15~25만원) 대비 낮습니다.", 'highlights' => [ ['text' => "1인당 월 복리후생비 {$perPersonFormatted}만원", 'color' => 'orange'], ], ]; } else { $checkPoints[] = [ 'id' => 'wf_cp_high', 'type' => 'warning', 'message' => "1인당 월 복리후생비 {$perPersonFormatted}만원. 업계 평균(15~25만원) 대비 높습니다.", 'highlights' => [ ['text' => "1인당 월 복리후생비 {$perPersonFormatted}만원", 'color' => 'orange'], ], ]; } // 식대 비과세 한도 체크 $mealAmount = $this->getMonthlyMealAmount($tenantId, $startDate, $endDate); $perPersonMeal = $employeeCount > 0 ? $mealAmount / $employeeCount : 0; if ($perPersonMeal > self::TAX_FREE_MEAL_LIMIT) { $mealFormatted = number_format($perPersonMeal / 10000); $limitFormatted = number_format(self::TAX_FREE_MEAL_LIMIT / 10000); $checkPoints[] = [ 'id' => 'wf_cp_meal', 'type' => 'error', 'message' => "식대가 월 {$mealFormatted}만원으로 비과세 한도({$limitFormatted}만원)를 초과했습니다. 초과분은 근로소득 과세됩니다.", 'highlights' => [ ['text' => "식대가 월 {$mealFormatted}만원으로", 'color' => 'red'], ['text' => '초과', 'color' => 'red'], ], ]; } return $checkPoints; } }