152 lines
6.5 KiB
PHP
152 lines
6.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Admin\Management;
|
|
|
|
use App\Models\Application;
|
|
use App\Models\Election;
|
|
use App\Models\Position;
|
|
use App\Models\PusatMengundi;
|
|
use App\Models\SaluranMengundi;
|
|
use App\Models\StaffAssignment;
|
|
use App\Services\Admin\OperationalAccountService;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class AdminAssignmentManagementService
|
|
{
|
|
public function __construct(
|
|
private readonly AdminPostCloseNoteService $postCloseNoteService,
|
|
private readonly OperationalAccountService $operationalAccountService,
|
|
) {}
|
|
|
|
/**
|
|
* @param array<string, mixed> $data
|
|
*/
|
|
public function update(StaffAssignment $assignment, User $actor, array $data): StaffAssignment
|
|
{
|
|
return DB::transaction(function () use ($assignment, $actor, $data): StaffAssignment {
|
|
$assignment->loadMissing(['election', 'position']);
|
|
$election = $assignment->election;
|
|
if (! $election instanceof Election) {
|
|
throw ValidationException::withMessages([
|
|
'election_id' => 'Pilihanraya tugasan tidak sah.',
|
|
]);
|
|
}
|
|
$this->postCloseNoteService->requireIfClosed($election, $data['note'] ?? null);
|
|
|
|
/** @var Position $position */
|
|
$position = Position::query()->findOrFail($data['position_id']);
|
|
/** @var PusatMengundi $pusat */
|
|
$pusat = PusatMengundi::query()->findOrFail($data['pusat_mengundi_id']);
|
|
|
|
if ((int) $pusat->election_id !== (int) $election->id) {
|
|
throw ValidationException::withMessages([
|
|
'pusat_mengundi_id' => 'Pusat Mengundi tidak berada dalam pilihanraya yang sama.',
|
|
]);
|
|
}
|
|
|
|
$before = [
|
|
'position_id' => $assignment->position_id,
|
|
'pusat_mengundi_id' => $assignment->pusat_mengundi_id,
|
|
'saluran_mengundi_id' => $assignment->saluran_mengundi_id,
|
|
'reports_to_assignment_id' => $assignment->reports_to_assignment_id,
|
|
'status' => $assignment->status,
|
|
];
|
|
|
|
$reportsToAssignmentId = $data['reports_to_assignment_id'] ?? null;
|
|
$saluranMengundiId = $data['saluran_mengundi_id'] ?? null;
|
|
|
|
if ($saluranMengundiId) {
|
|
/** @var SaluranMengundi $saluran */
|
|
$saluran = SaluranMengundi::query()->findOrFail($saluranMengundiId);
|
|
if ((int) $saluran->pusat_mengundi_id !== (int) $pusat->id) {
|
|
throw ValidationException::withMessages([
|
|
'saluran_mengundi_id' => 'Saluran Mengundi tidak berada di bawah Pusat Mengundi yang dipilih.',
|
|
]);
|
|
}
|
|
}
|
|
|
|
if ($reportsToAssignmentId) {
|
|
/** @var StaffAssignment $ktmAssignment */
|
|
$ktmAssignment = StaffAssignment::query()
|
|
->with('position')
|
|
->whereKey($reportsToAssignmentId)
|
|
->where('election_id', $election->id)
|
|
->where('pusat_mengundi_id', $pusat->id)
|
|
->where('status', 'active')
|
|
->firstOrFail();
|
|
|
|
$ktmPosition = $ktmAssignment->position;
|
|
if (! $ktmPosition instanceof Position || $ktmPosition->code !== 'KTM') {
|
|
throw ValidationException::withMessages([
|
|
'reports_to_assignment_id' => 'Ketua rujukan mestilah tugasan KTM aktif.',
|
|
]);
|
|
}
|
|
|
|
if ((int) $ktmAssignment->id === (int) $assignment->id) {
|
|
throw ValidationException::withMessages([
|
|
'reports_to_assignment_id' => 'KTM tidak boleh melapor kepada tugasan sendiri.',
|
|
]);
|
|
}
|
|
|
|
$saluranMengundiId = $ktmAssignment->saluran_mengundi_id;
|
|
}
|
|
|
|
$assignment->forceFill([
|
|
'position_id' => $position->id,
|
|
'pusat_mengundi_id' => $pusat->id,
|
|
'saluran_mengundi_id' => $saluranMengundiId,
|
|
'reports_to_assignment_id' => $reportsToAssignmentId,
|
|
'status' => $data['status'],
|
|
'assigned_by_user_id' => $actor->id,
|
|
'assigned_at' => now(),
|
|
'source' => 'admin_update',
|
|
])->save();
|
|
|
|
$assignment->histories()->create([
|
|
'from_position_id' => $before['position_id'],
|
|
'to_position_id' => $position->id,
|
|
'from_pusat_mengundi_id' => $before['pusat_mengundi_id'],
|
|
'to_pusat_mengundi_id' => $pusat->id,
|
|
'from_saluran_mengundi_id' => $before['saluran_mengundi_id'],
|
|
'to_saluran_mengundi_id' => $saluranMengundiId,
|
|
'from_reports_to_assignment_id' => $before['reports_to_assignment_id'],
|
|
'to_reports_to_assignment_id' => $reportsToAssignmentId,
|
|
'changed_by_user_id' => $actor->id,
|
|
'note' => $data['note'] ?? 'Assignment updated by Admin.',
|
|
]);
|
|
|
|
$application = $assignment->application;
|
|
if ($application instanceof Application) {
|
|
$application->forceFill([
|
|
'pusat_mengundi_id' => $pusat->id,
|
|
'approved_position_id' => $position->id,
|
|
'selected_ktm_assignment_id' => $reportsToAssignmentId,
|
|
'status' => $data['status'] === 'active' ? 'assigned' : $application->status,
|
|
])->save();
|
|
}
|
|
|
|
$this->operationalAccountService->provisionForAssignment($assignment, $position);
|
|
|
|
$this->postCloseNoteService->recordIfClosed($election, $assignment, $actor, $data['note'] ?? null, 'admin_assignment_edit_after_close');
|
|
|
|
activity('admin_management')
|
|
->performedOn($assignment)
|
|
->causedBy($actor)
|
|
->withProperties([
|
|
'before' => $before,
|
|
'after' => [
|
|
'position_id' => $assignment->position_id,
|
|
'pusat_mengundi_id' => $assignment->pusat_mengundi_id,
|
|
'saluran_mengundi_id' => $assignment->saluran_mengundi_id,
|
|
'reports_to_assignment_id' => $assignment->reports_to_assignment_id,
|
|
'status' => $assignment->status,
|
|
],
|
|
])
|
|
->log('staff_assignment_updated_by_admin');
|
|
|
|
return $assignment;
|
|
});
|
|
}
|
|
}
|