- 마이그레이션: payrolls, payroll_settings 테이블 생성 - 모델: Payroll (상태관리 draft→confirmed→paid), PayrollSetting - 서비스: PayrollService (4대보험 계산, 급여명세서) - 컨트롤러: PayrollController + FormRequest 5개 - API 엔드포인트 13개: - 급여 CRUD + confirm/pay/payslip - 일괄 계산/확정 (calculate, bulk-confirm) - 설정 관리 (settings/payroll) - Swagger 문서: PayrollApi.php - i18n: error.php, message.php, validation.php 키 추가
192 lines
5.7 KiB
PHP
192 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace App\Models\Tenants;
|
|
|
|
use App\Traits\BelongsToTenant;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
|
|
/**
|
|
* 급여 설정 모델
|
|
*
|
|
* @property int $id
|
|
* @property int $tenant_id
|
|
* @property float $income_tax_rate
|
|
* @property float $resident_tax_rate
|
|
* @property float $health_insurance_rate
|
|
* @property float $long_term_care_rate
|
|
* @property float $pension_rate
|
|
* @property float $employment_insurance_rate
|
|
* @property float $pension_max_salary
|
|
* @property float $pension_min_salary
|
|
* @property int $pay_day
|
|
* @property bool $auto_calculate
|
|
* @property array|null $allowance_types
|
|
* @property array|null $deduction_types
|
|
*/
|
|
class PayrollSetting extends Model
|
|
{
|
|
use BelongsToTenant;
|
|
|
|
protected $table = 'payroll_settings';
|
|
|
|
public $timestamps = true;
|
|
|
|
protected $casts = [
|
|
'income_tax_rate' => 'decimal:2',
|
|
'resident_tax_rate' => 'decimal:2',
|
|
'health_insurance_rate' => 'decimal:3',
|
|
'long_term_care_rate' => 'decimal:4',
|
|
'pension_rate' => 'decimal:3',
|
|
'employment_insurance_rate' => 'decimal:3',
|
|
'pension_max_salary' => 'decimal:2',
|
|
'pension_min_salary' => 'decimal:2',
|
|
'pay_day' => 'integer',
|
|
'auto_calculate' => 'boolean',
|
|
'allowance_types' => 'array',
|
|
'deduction_types' => 'array',
|
|
];
|
|
|
|
protected $fillable = [
|
|
'tenant_id',
|
|
'income_tax_rate',
|
|
'resident_tax_rate',
|
|
'health_insurance_rate',
|
|
'long_term_care_rate',
|
|
'pension_rate',
|
|
'employment_insurance_rate',
|
|
'pension_max_salary',
|
|
'pension_min_salary',
|
|
'pay_day',
|
|
'auto_calculate',
|
|
'allowance_types',
|
|
'deduction_types',
|
|
];
|
|
|
|
protected $attributes = [
|
|
'income_tax_rate' => 0,
|
|
'resident_tax_rate' => 10,
|
|
'health_insurance_rate' => 3.545,
|
|
'long_term_care_rate' => 0.9082,
|
|
'pension_rate' => 4.5,
|
|
'employment_insurance_rate' => 0.9,
|
|
'pension_max_salary' => 5900000,
|
|
'pension_min_salary' => 370000,
|
|
'pay_day' => 25,
|
|
'auto_calculate' => false,
|
|
];
|
|
|
|
// =========================================================================
|
|
// 기본 수당 유형
|
|
// =========================================================================
|
|
|
|
public const DEFAULT_ALLOWANCE_TYPES = [
|
|
['code' => 'meal', 'name' => '식대', 'is_taxable' => false],
|
|
['code' => 'transport', 'name' => '교통비', 'is_taxable' => false],
|
|
['code' => 'position', 'name' => '직책수당', 'is_taxable' => true],
|
|
['code' => 'skill', 'name' => '기술수당', 'is_taxable' => true],
|
|
['code' => 'family', 'name' => '가족수당', 'is_taxable' => true],
|
|
['code' => 'housing', 'name' => '주거수당', 'is_taxable' => true],
|
|
];
|
|
|
|
// =========================================================================
|
|
// 기본 공제 유형
|
|
// =========================================================================
|
|
|
|
public const DEFAULT_DEDUCTION_TYPES = [
|
|
['code' => 'loan', 'name' => '대출상환'],
|
|
['code' => 'union', 'name' => '조합비'],
|
|
['code' => 'savings', 'name' => '저축'],
|
|
['code' => 'etc', 'name' => '기타공제'],
|
|
];
|
|
|
|
// =========================================================================
|
|
// 관계 정의
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 테넌트
|
|
*/
|
|
public function tenant(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Tenant::class);
|
|
}
|
|
|
|
// =========================================================================
|
|
// 헬퍼 메서드
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 수당 유형 목록 (기본값 포함)
|
|
*/
|
|
public function getAllowanceTypesWithDefaultAttribute(): array
|
|
{
|
|
return $this->allowance_types ?? self::DEFAULT_ALLOWANCE_TYPES;
|
|
}
|
|
|
|
/**
|
|
* 공제 유형 목록 (기본값 포함)
|
|
*/
|
|
public function getDeductionTypesWithDefaultAttribute(): array
|
|
{
|
|
return $this->deduction_types ?? self::DEFAULT_DEDUCTION_TYPES;
|
|
}
|
|
|
|
/**
|
|
* 건강보험료 계산
|
|
*/
|
|
public function calculateHealthInsurance(float $salary): float
|
|
{
|
|
return round($salary * ($this->health_insurance_rate / 100), 0);
|
|
}
|
|
|
|
/**
|
|
* 장기요양보험료 계산 (건강보험료의 %)
|
|
*/
|
|
public function calculateLongTermCare(float $healthInsurance): float
|
|
{
|
|
return round($healthInsurance * ($this->long_term_care_rate / 100), 0);
|
|
}
|
|
|
|
/**
|
|
* 국민연금 계산
|
|
*/
|
|
public function calculatePension(float $salary): float
|
|
{
|
|
// 기준소득월액 상/하한 적용
|
|
$standardSalary = min(max($salary, $this->pension_min_salary), $this->pension_max_salary);
|
|
|
|
return round($standardSalary * ($this->pension_rate / 100), 0);
|
|
}
|
|
|
|
/**
|
|
* 고용보험료 계산
|
|
*/
|
|
public function calculateEmploymentInsurance(float $salary): float
|
|
{
|
|
return round($salary * ($this->employment_insurance_rate / 100), 0);
|
|
}
|
|
|
|
/**
|
|
* 주민세 계산 (소득세의 10%)
|
|
*/
|
|
public function calculateResidentTax(float $incomeTax): float
|
|
{
|
|
return round($incomeTax * ($this->resident_tax_rate / 100), 0);
|
|
}
|
|
|
|
/**
|
|
* 테넌트별 설정 가져오기 또는 생성
|
|
*/
|
|
public static function getOrCreate(int $tenantId): self
|
|
{
|
|
return self::firstOrCreate(
|
|
['tenant_id' => $tenantId],
|
|
[
|
|
'allowance_types' => self::DEFAULT_ALLOWANCE_TYPES,
|
|
'deduction_types' => self::DEFAULT_DEDUCTION_TYPES,
|
|
]
|
|
);
|
|
}
|
|
}
|