where('tenant_id', $tenantId)->count(); if ($existing > 0) { $this->command->info(' ⚠ salaries: 이미 '.$existing.'개 존재 (스킵)'); return; } // 테넌트 소속 사용자 조회 $userIds = DB::table('user_tenants') ->where('tenant_id', $tenantId) ->where('is_active', true) ->pluck('user_id') ->toArray(); if (empty($userIds)) { $this->command->warn(' ⚠ salaries: 테넌트에 연결된 사용자가 없습니다'); return; } // 사용자 정보 조회 $users = User::whereIn('id', $userIds)->get(); // 부서별 사용자 매핑 (급여 차등용) $userDepartments = DB::table('department_user') ->join('departments', 'departments.id', '=', 'department_user.department_id') ->whereIn('department_user.user_id', $userIds) ->where('department_user.tenant_id', $tenantId) ->pluck('departments.name', 'department_user.user_id') ->toArray(); // 직급별 기본급 설정 $rankSalaries = [ '사원' => ['base' => 3000000, 'position_allowance' => 0], '대리' => ['base' => 3500000, 'position_allowance' => 100000], '과장' => ['base' => 4200000, 'position_allowance' => 200000], '차장' => ['base' => 5000000, 'position_allowance' => 300000], '부장' => ['base' => 6000000, 'position_allowance' => 500000], '이사' => ['base' => 7500000, 'position_allowance' => 800000], ]; // 직급 배정 (인덱스 기반으로 분배) $ranks = array_keys($rankSalaries); $count = 0; $year = 2025; $month = 12; foreach ($users as $index => $user) { // 직급 결정 (순환 분배, 사원이 가장 많도록 가중치) $rankIndex = $this->getRankIndex($index, count($users)); $rank = $ranks[$rankIndex]; $salaryConfig = $rankSalaries[$rank]; // 기본급 $baseSalary = $salaryConfig['base']; // 수당 계산 $positionAllowance = $salaryConfig['position_allowance']; $overtimeHours = rand(0, 30); $overtimeAllowance = $overtimeHours * 15000; // 시간당 15,000원 $mealAllowance = 200000; // 식대 (비과세) $transportAllowance = 100000; // 교통비 $otherAllowance = rand(0, 5) * 50000; // 기타수당 $totalAllowance = $positionAllowance + $mealAllowance + $transportAllowance + $otherAllowance; $totalOvertime = $overtimeAllowance; $totalBonus = ($index % 5 === 0) ? $baseSalary * 0.5 : 0; // 5번째마다 상여 // 공제 계산 (과세 대상 급여 기준) $taxableIncome = $baseSalary + $positionAllowance + $overtimeAllowance + $totalBonus; $nationalPension = round($taxableIncome * 0.045); // 국민연금 4.5% $healthInsurance = round($taxableIncome * 0.03545); // 건강보험 3.545% $longTermCare = round($healthInsurance * 0.1281); // 장기요양 12.81% $employmentInsurance = round($taxableIncome * 0.009); // 고용보험 0.9% $incomeTax = $this->calculateIncomeTax($taxableIncome); $localIncomeTax = round($incomeTax * 0.1); // 지방소득세 10% $otherDeduction = 0; $totalDeduction = $nationalPension + $healthInsurance + $longTermCare + $employmentInsurance + $incomeTax + $localIncomeTax + $otherDeduction; // 실지급액 $netPayment = $baseSalary + $totalAllowance + $totalOvertime + $totalBonus - $totalDeduction; // 지급 상태 결정 (80%는 완료, 20%는 예정) $status = (rand(1, 10) <= 8) ? 'completed' : 'scheduled'; $paymentDate = ($status === 'completed') ? '2025-12-25' : '2025-12-31'; Salary::create([ 'tenant_id' => $tenantId, 'employee_id' => $user->id, 'year' => $year, 'month' => $month, 'base_salary' => $baseSalary, 'total_allowance' => $totalAllowance, 'total_overtime' => $totalOvertime, 'total_bonus' => $totalBonus, 'total_deduction' => $totalDeduction, 'net_payment' => $netPayment, 'allowance_details' => [ 'position_allowance' => $positionAllowance, 'overtime_allowance' => $overtimeAllowance, 'meal_allowance' => $mealAllowance, 'transport_allowance' => $transportAllowance, 'other_allowance' => $otherAllowance, ], 'deduction_details' => [ 'national_pension' => $nationalPension, 'health_insurance' => $healthInsurance, 'long_term_care' => $longTermCare, 'employment_insurance' => $employmentInsurance, 'income_tax' => $incomeTax, 'local_income_tax' => $localIncomeTax, 'other_deduction' => $otherDeduction, ], 'payment_date' => $paymentDate, 'status' => $status, 'created_by' => $userId, ]); $count++; } $this->command->info(' ✓ salaries: '.$count.'개 생성 (2025년 12월)'); } /** * 인덱스 기반 직급 결정 (사원이 가장 많도록) */ private function getRankIndex(int $index, int $total): int { // 배분: 사원 40%, 대리 25%, 과장 15%, 차장 10%, 부장 7%, 이사 3% $ratio = $index / $total; if ($ratio < 0.40) { return 0; } // 사원 if ($ratio < 0.65) { return 1; } // 대리 if ($ratio < 0.80) { return 2; } // 과장 if ($ratio < 0.90) { return 3; } // 차장 if ($ratio < 0.97) { return 4; } // 부장 return 5; // 이사 } /** * 간이세액표 기반 소득세 계산 (간략화) */ private function calculateIncomeTax(float $taxableIncome): int { // 월 급여 기준 간이세액 (부양가족 1인 기준, 간략화) if ($taxableIncome <= 1500000) { return 0; } if ($taxableIncome <= 2000000) { return round($taxableIncome * 0.02); } if ($taxableIncome <= 3000000) { return round($taxableIncome * 0.03); } if ($taxableIncome <= 4500000) { return round($taxableIncome * 0.05); } if ($taxableIncome <= 6000000) { return round($taxableIncome * 0.08); } if ($taxableIncome <= 8000000) { return round($taxableIncome * 0.12); } return round($taxableIncome * 0.15); } }