first
This commit is contained in:
152
app/Services/Public/KtmVacancyService.php
Normal file
152
app/Services/Public/KtmVacancyService.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Public;
|
||||
|
||||
use App\Models\Application;
|
||||
use App\Models\Position;
|
||||
use App\Models\PositionQuota;
|
||||
use App\Models\PusatMengundi;
|
||||
use App\Models\SaluranMengundi;
|
||||
use App\Models\StaffAssignment;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class KtmVacancyService
|
||||
{
|
||||
private const RESERVED_APPLICATION_STATUSES = [
|
||||
'submitted',
|
||||
'under_ppm_review',
|
||||
'approved',
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array<int, string> $roleCodes
|
||||
* @return array<string, array<int, array{id: int, label: string, remaining: int}>>
|
||||
*/
|
||||
public function optionsForRoles(PusatMengundi $pusatMengundi, array $roleCodes = ['KP', 'KPDP'], ?int $ignoreApplicationId = null): array
|
||||
{
|
||||
$options = [];
|
||||
|
||||
foreach ($roleCodes as $roleCode) {
|
||||
$options[$roleCode] = $this->availableKtmAssignments($pusatMengundi, $roleCode, $ignoreApplicationId)
|
||||
->map(function (StaffAssignment $assignment) use ($roleCode, $ignoreApplicationId): array {
|
||||
$user = $assignment->user;
|
||||
$saluranMengundi = $assignment->saluranMengundi;
|
||||
|
||||
return [
|
||||
'id' => $assignment->id,
|
||||
'label' => trim(
|
||||
($user instanceof User ? $user->name : 'KTM tanpa nama')
|
||||
.' - Saluran '
|
||||
.($saluranMengundi instanceof SaluranMengundi ? $saluranMengundi->number : '-'),
|
||||
),
|
||||
'remaining' => $this->remainingVacancy($assignment, $roleCode, $ignoreApplicationId),
|
||||
];
|
||||
})
|
||||
->values()
|
||||
->all();
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
public function hasVacancyForAssignment(int $assignmentId, PusatMengundi $pusatMengundi, string $roleCode, ?int $ignoreApplicationId = null): bool
|
||||
{
|
||||
$ktmPosition = Position::query()->where('code', 'KTM')->first();
|
||||
|
||||
if ($ktmPosition === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$assignment = StaffAssignment::query()
|
||||
->with(['saluranMengundi', 'user'])
|
||||
->where('id', $assignmentId)
|
||||
->where('election_id', $pusatMengundi->election_id)
|
||||
->where('pusat_mengundi_id', $pusatMengundi->id)
|
||||
->where('position_id', $ktmPosition->id)
|
||||
->where('status', 'active')
|
||||
->whereNotNull('saluran_mengundi_id')
|
||||
->first();
|
||||
|
||||
return $assignment instanceof StaffAssignment
|
||||
&& $this->remainingVacancy($assignment, $roleCode, $ignoreApplicationId) > 0;
|
||||
}
|
||||
|
||||
public function remainingForAssignment(StaffAssignment $assignment, string $roleCode, ?int $ignoreApplicationId = null): int
|
||||
{
|
||||
return $this->remainingVacancy($assignment, $roleCode, $ignoreApplicationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, StaffAssignment>
|
||||
*/
|
||||
private function availableKtmAssignments(PusatMengundi $pusatMengundi, string $roleCode, ?int $ignoreApplicationId = null): Collection
|
||||
{
|
||||
return $this->ktmAssignments($pusatMengundi)
|
||||
->filter(fn (StaffAssignment $assignment): bool => $this->remainingVacancy($assignment, $roleCode, $ignoreApplicationId) > 0)
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EloquentCollection<int, StaffAssignment>
|
||||
*/
|
||||
private function ktmAssignments(PusatMengundi $pusatMengundi): EloquentCollection
|
||||
{
|
||||
$ktmPosition = Position::query()->where('code', 'KTM')->first();
|
||||
|
||||
if ($ktmPosition === null) {
|
||||
return new EloquentCollection;
|
||||
}
|
||||
|
||||
return StaffAssignment::query()
|
||||
->with(['saluranMengundi', 'user'])
|
||||
->where('election_id', $pusatMengundi->election_id)
|
||||
->where('pusat_mengundi_id', $pusatMengundi->id)
|
||||
->where('position_id', $ktmPosition->id)
|
||||
->where('status', 'active')
|
||||
->whereNotNull('saluran_mengundi_id')
|
||||
->whereNotNull('user_id')
|
||||
->orderBy('saluran_mengundi_id')
|
||||
->get();
|
||||
}
|
||||
|
||||
private function remainingVacancy(StaffAssignment $ktmAssignment, string $roleCode, ?int $ignoreApplicationId = null): int
|
||||
{
|
||||
$position = Position::query()->where('code', $roleCode)->first();
|
||||
|
||||
if ($position === null || $ktmAssignment->saluran_mengundi_id === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$quota = PositionQuota::query()
|
||||
->where('election_id', $ktmAssignment->election_id)
|
||||
->where('pusat_mengundi_id', $ktmAssignment->pusat_mengundi_id)
|
||||
->where('saluran_mengundi_id', $ktmAssignment->saluran_mengundi_id)
|
||||
->where('position_id', $position->id)
|
||||
->value('quota');
|
||||
|
||||
if ($quota === null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$assignedCount = StaffAssignment::query()
|
||||
->where('reports_to_assignment_id', $ktmAssignment->id)
|
||||
->where('position_id', $position->id)
|
||||
->where('status', 'active')
|
||||
->count();
|
||||
|
||||
$reservedQuery = Application::query()
|
||||
->where('selected_ktm_assignment_id', $ktmAssignment->id)
|
||||
->where('requested_position_id', $position->id)
|
||||
->whereIn('status', self::RESERVED_APPLICATION_STATUSES);
|
||||
|
||||
if ($ignoreApplicationId !== null) {
|
||||
$reservedQuery->where('id', '!=', $ignoreApplicationId);
|
||||
}
|
||||
|
||||
$reservedCount = $reservedQuery->count();
|
||||
|
||||
return max(0, (int) $quota - $assignedCount - $reservedCount);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user