feat: [hr] 인사관리 사원관리 Phase 1 구현
- Employee, Position 모델 생성 (tenant_user_profiles, positions 테이블) - EmployeeService 생성 (CRUD, 통계, 필터/검색/페이지네이션) - 뷰 컨트롤러(HR/EmployeeController) + API 컨트롤러 생성 - Blade 뷰: index(통계카드+HTMX테이블), create, edit, show, partials/table - 라우트: web.php(/hr/employees/*), api.php(/admin/hr/employees/*)
This commit is contained in:
166
app/Models/HR/Employee.php
Normal file
166
app/Models/HR/Employee.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\HR;
|
||||
|
||||
use App\Models\Tenants\Department;
|
||||
use App\Models\User;
|
||||
use App\Traits\ModelTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Employee extends Model
|
||||
{
|
||||
use ModelTrait;
|
||||
|
||||
protected $table = 'tenant_user_profiles';
|
||||
|
||||
protected $fillable = [
|
||||
'tenant_id',
|
||||
'user_id',
|
||||
'department_id',
|
||||
'position_key',
|
||||
'job_title_key',
|
||||
'work_location_key',
|
||||
'employment_type_key',
|
||||
'employee_status',
|
||||
'manager_user_id',
|
||||
'json_extra',
|
||||
'profile_photo_path',
|
||||
'display_name',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'json_extra' => 'array',
|
||||
'tenant_id' => 'int',
|
||||
'user_id' => 'int',
|
||||
'department_id' => 'int',
|
||||
'manager_user_id' => 'int',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'employee_code',
|
||||
'hire_date',
|
||||
'position_label',
|
||||
'job_title_label',
|
||||
];
|
||||
|
||||
// =========================================================================
|
||||
// 관계 정의
|
||||
// =========================================================================
|
||||
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
public function department(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Department::class, 'department_id');
|
||||
}
|
||||
|
||||
public function manager(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'manager_user_id');
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// json_extra Accessor
|
||||
// =========================================================================
|
||||
|
||||
public function getEmployeeCodeAttribute(): ?string
|
||||
{
|
||||
return $this->json_extra['employee_code'] ?? null;
|
||||
}
|
||||
|
||||
public function getHireDateAttribute(): ?string
|
||||
{
|
||||
return $this->json_extra['hire_date'] ?? null;
|
||||
}
|
||||
|
||||
public function getAddressAttribute(): ?string
|
||||
{
|
||||
return $this->json_extra['address'] ?? null;
|
||||
}
|
||||
|
||||
public function getEmergencyContactAttribute(): ?string
|
||||
{
|
||||
return $this->json_extra['emergency_contact'] ?? null;
|
||||
}
|
||||
|
||||
public function getPositionLabelAttribute(): ?string
|
||||
{
|
||||
if (! $this->position_key || ! $this->tenant_id) {
|
||||
return $this->position_key;
|
||||
}
|
||||
|
||||
$position = Position::where('tenant_id', $this->tenant_id)
|
||||
->where('type', Position::TYPE_RANK)
|
||||
->where('key', $this->position_key)
|
||||
->first();
|
||||
|
||||
return $position?->name ?? $this->position_key;
|
||||
}
|
||||
|
||||
public function getJobTitleLabelAttribute(): ?string
|
||||
{
|
||||
if (! $this->job_title_key || ! $this->tenant_id) {
|
||||
return $this->job_title_key;
|
||||
}
|
||||
|
||||
$position = Position::where('tenant_id', $this->tenant_id)
|
||||
->where('type', Position::TYPE_TITLE)
|
||||
->where('key', $this->job_title_key)
|
||||
->first();
|
||||
|
||||
return $position?->name ?? $this->job_title_key;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// json_extra 헬퍼
|
||||
// =========================================================================
|
||||
|
||||
public function getJsonExtraValue(string $key, mixed $default = null): mixed
|
||||
{
|
||||
return $this->json_extra[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function setJsonExtraValue(string $key, mixed $value): void
|
||||
{
|
||||
$extra = $this->json_extra ?? [];
|
||||
if ($value === null) {
|
||||
unset($extra[$key]);
|
||||
} else {
|
||||
$extra[$key] = $value;
|
||||
}
|
||||
$this->json_extra = $extra;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// 스코프
|
||||
// =========================================================================
|
||||
|
||||
public function scopeForTenant($query, ?int $tenantId = null)
|
||||
{
|
||||
$tenantId = $tenantId ?? session('selected_tenant_id');
|
||||
if ($tenantId) {
|
||||
return $query->where('tenant_id', $tenantId);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function scopeActiveEmployees($query)
|
||||
{
|
||||
return $query->where('employee_status', 'active');
|
||||
}
|
||||
|
||||
public function scopeOnLeave($query)
|
||||
{
|
||||
return $query->where('employee_status', 'leave');
|
||||
}
|
||||
|
||||
public function scopeResigned($query)
|
||||
{
|
||||
return $query->where('employee_status', 'resigned');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user