feat: 휴가 사용현황 전체 직원 목록 API 추가
- GET /api/v1/leaves/balances 엔드포인트 추가 - LeaveService.getAllBalances() 메서드 구현 - TenantUserProfile 기준 전체 활성 직원 조회 - LeaveBalance 서브쿼리로 연차 정보 LEFT JOIN - 부서/검색/정렬 필터링 및 페이지네이션 지원 - User 모델에 tenantProfiles/tenantProfile 관계 추가
This commit is contained in:
@@ -105,6 +105,17 @@ public function cancel(int $id, Request $request): JsonResponse
|
||||
}, __('message.leave.cancelled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 전체 직원 휴가 사용현황 목록
|
||||
* GET /v1/leaves/balances
|
||||
*/
|
||||
public function balances(Request $request): JsonResponse
|
||||
{
|
||||
return ApiResponse::handle(function () use ($request) {
|
||||
return $this->service->getAllBalances($request->all());
|
||||
}, __('message.fetched'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 내 잔여 휴가 조회
|
||||
* GET /v1/leaves/balance
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Models\Commons\File;
|
||||
use App\Models\Tenants\Tenant;
|
||||
use App\Models\Tenants\TenantUserProfile;
|
||||
use App\Traits\ModelTrait;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -77,4 +78,21 @@ public function tenantsMembership(): BelongsToMany
|
||||
->withPivot(['is_active', 'is_default', 'joined_at', 'left_at', 'deleted_at'])
|
||||
->wherePivotNull('deleted_at'); // 소프트삭제 제외
|
||||
}
|
||||
|
||||
/**
|
||||
* 테넌트별 사용자 프로필 (전체)
|
||||
*/
|
||||
public function tenantProfiles()
|
||||
{
|
||||
return $this->hasMany(TenantUserProfile::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 테넌트의 사용자 프로필
|
||||
* 주의: 조회 시 tenant_id 조건 추가 필요
|
||||
*/
|
||||
public function tenantProfile()
|
||||
{
|
||||
return $this->hasOne(TenantUserProfile::class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use App\Models\Tenants\Leave;
|
||||
use App\Models\Tenants\LeaveBalance;
|
||||
use App\Models\Tenants\TenantUserProfile;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
@@ -307,6 +308,66 @@ public function cancel(int $id, ?string $reason = null): Leave
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 전체 직원 휴가 사용현황 목록 조회
|
||||
* TenantUserProfile 기준으로 전체 직원 조회 후 LeaveBalance LEFT JOIN
|
||||
*/
|
||||
public function getAllBalances(array $params): LengthAwarePaginator
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$year = $params['year'] ?? now()->year;
|
||||
|
||||
$query = TenantUserProfile::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('employee_status', 'active')
|
||||
->with([
|
||||
'user:id,name,email',
|
||||
'department:id,name',
|
||||
])
|
||||
->addSelect([
|
||||
'tenant_user_profiles.*',
|
||||
'leave_balance_total' => LeaveBalance::selectRaw('total_days')
|
||||
->whereColumn('leave_balances.user_id', 'tenant_user_profiles.user_id')
|
||||
->where('leave_balances.tenant_id', $tenantId)
|
||||
->where('leave_balances.year', $year)
|
||||
->limit(1),
|
||||
'leave_balance_used' => LeaveBalance::selectRaw('used_days')
|
||||
->whereColumn('leave_balances.user_id', 'tenant_user_profiles.user_id')
|
||||
->where('leave_balances.tenant_id', $tenantId)
|
||||
->where('leave_balances.year', $year)
|
||||
->limit(1),
|
||||
]);
|
||||
|
||||
// 부서 필터
|
||||
if (! empty($params['department_id'])) {
|
||||
$query->where('department_id', $params['department_id']);
|
||||
}
|
||||
|
||||
// 검색 (사용자명)
|
||||
if (! empty($params['search'])) {
|
||||
$query->whereHas('user', function ($q) use ($params) {
|
||||
$q->where('name', 'like', '%'.$params['search'].'%');
|
||||
});
|
||||
}
|
||||
|
||||
// 정렬
|
||||
$sortBy = $params['sort_by'] ?? 'user_id';
|
||||
$sortDir = $params['sort_dir'] ?? 'asc';
|
||||
|
||||
if ($sortBy === 'user_id') {
|
||||
$query->orderBy('user_id', $sortDir);
|
||||
} elseif ($sortBy === 'department') {
|
||||
$query->orderBy('department_id', $sortDir);
|
||||
} else {
|
||||
$query->orderBy($sortBy, $sortDir);
|
||||
}
|
||||
|
||||
// 페이지네이션
|
||||
$perPage = $params['per_page'] ?? 20;
|
||||
|
||||
return $query->paginate($perPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 내 잔여 휴가 조회
|
||||
*/
|
||||
|
||||
@@ -304,6 +304,7 @@
|
||||
Route::prefix('leaves')->group(function () {
|
||||
Route::get('', [LeaveController::class, 'index'])->name('v1.leaves.index');
|
||||
Route::post('', [LeaveController::class, 'store'])->name('v1.leaves.store');
|
||||
Route::get('/balances', [LeaveController::class, 'balances'])->name('v1.leaves.balances');
|
||||
Route::get('/balance', [LeaveController::class, 'balance'])->name('v1.leaves.balance');
|
||||
Route::get('/balance/{userId}', [LeaveController::class, 'userBalance'])->name('v1.leaves.userBalance');
|
||||
Route::put('/balance', [LeaveController::class, 'setBalance'])->name('v1.leaves.setBalance');
|
||||
|
||||
Reference in New Issue
Block a user