395 lines
13 KiB
PHP
395 lines
13 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Enums\DecisionAdmin;
|
|
use App\Enums\VerificationStatus;
|
|
use App\Filament\Pages\Company as PagesCompany;
|
|
use App\Filament\Pages\Media;
|
|
use App\Filament\Resources\Manage\Journalists\Pages\ManageJournalists;
|
|
use App\Models\Company;
|
|
use App\Models\VerificationRequest;
|
|
use App\Models\VerificationReview;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class VerificationService
|
|
{
|
|
/**
|
|
* Check if all required data is complete for verification
|
|
*/
|
|
public function isDataComplete(?Company $company): bool
|
|
{
|
|
return $company !== null
|
|
&& $company->partnerMedia !== null
|
|
&& $company->partnerMedia?->journalists !== null
|
|
&& $company->partnerMedia->journalists->count() > 0;
|
|
}
|
|
|
|
/**
|
|
* Get missing data items for verification
|
|
*/
|
|
public function getMissingData(?Company $company): array
|
|
{
|
|
$missing = [];
|
|
|
|
if (! $company) {
|
|
$missing[] = 'Data Perusahaan';
|
|
}
|
|
|
|
if ($company && ! $company->partnerMedia) {
|
|
$missing[] = 'Data Media';
|
|
}
|
|
|
|
if ($company && $company->partnerMedia && ($company->partnerMedia?->journalists === null || $company->partnerMedia?->journalists?->count() === 0)) {
|
|
$missing[] = 'Data Jurnalis (minimal 1)';
|
|
}
|
|
|
|
return $missing;
|
|
}
|
|
|
|
/**
|
|
* Check if user can submit verification
|
|
*/
|
|
public function canSubmit(?Company $company, ?VerificationRequest $verificationRequest): bool
|
|
{
|
|
if (! $this->isDataComplete($company)) {
|
|
return false;
|
|
}
|
|
|
|
// No verification yet - can submit
|
|
if (! $verificationRequest) {
|
|
return true;
|
|
}
|
|
|
|
// Can resubmit only if status is NEED_REVISION
|
|
return $verificationRequest->status === VerificationStatus::NEED_REVISION;
|
|
}
|
|
|
|
/**
|
|
* Determine the current step based on status
|
|
*/
|
|
public function resolveStep(?Company $company, ?VerificationRequest $verificationRequest): int
|
|
{
|
|
if (! $this->isDataComplete($company)) {
|
|
return 1; // Data belum lengkap
|
|
}
|
|
|
|
if (! $verificationRequest) {
|
|
return 1; // Belum submit
|
|
}
|
|
|
|
return match ($verificationRequest->status) {
|
|
VerificationStatus::PENDING,
|
|
VerificationStatus::NEED_REVISION => 2, // In review or needs revision
|
|
|
|
VerificationStatus::APPROVED,
|
|
VerificationStatus::REJECTED => 3, // Final decision
|
|
|
|
default => 1, // Draft / not submitted yet
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the latest review notes
|
|
*/
|
|
public function getLatestReviewNotes(?VerificationRequest $verificationRequest): ?string
|
|
{
|
|
if (! $verificationRequest) {
|
|
return null;
|
|
}
|
|
|
|
$latestReview = $verificationRequest->reviews()
|
|
->whereIn('decision', [DecisionAdmin::NEED_REVISION, DecisionAdmin::REJECTED])
|
|
->latest()
|
|
->first();
|
|
|
|
return $latestReview?->note;
|
|
}
|
|
|
|
/**
|
|
* Get all reviews history
|
|
*/
|
|
public function getReviewHistory(?VerificationRequest $verificationRequest): Collection
|
|
{
|
|
if (! $verificationRequest) {
|
|
return collect();
|
|
}
|
|
|
|
return $verificationRequest->reviews()
|
|
->with('reviewer')
|
|
->latest()
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Get unified verification progress data
|
|
*/
|
|
public function getVerificationProgress(?Company $company, ?VerificationRequest $verificationRequest): array
|
|
{
|
|
$currentStep = $this->resolveStep($company, $verificationRequest);
|
|
$isComplete = $this->isDataComplete($company);
|
|
$missingData = $this->getMissingData($company);
|
|
|
|
$status = $verificationRequest?->status;
|
|
|
|
return [
|
|
'currentStep' => $currentStep,
|
|
'isDataComplete' => $isComplete,
|
|
'missingData' => $missingData,
|
|
'canSubmit' => $this->canSubmit($company, $verificationRequest),
|
|
'verification' => $verificationRequest,
|
|
'status' => [
|
|
'label' => $status?->getLabel() ?? 'Belum Mengajukan',
|
|
'color' => $status?->getColor() ?? 'gray',
|
|
],
|
|
'isApproved' => $status === VerificationStatus::APPROVED,
|
|
'isRejected' => $status === VerificationStatus::REJECTED,
|
|
'isPending' => $status === VerificationStatus::PENDING,
|
|
'needsRevision' => $status === VerificationStatus::NEED_REVISION,
|
|
'latestNotes' => $this->getLatestReviewNotes($verificationRequest),
|
|
'reviewHistory' => $this->getReviewHistory($verificationRequest),
|
|
'company' => $company,
|
|
'partnerMedia' => $company?->partnerMedia,
|
|
'journalists' => $company?->partnerMedia?->journalists ?? collect(),
|
|
'steps' => $this->getSteps($verificationRequest, $isComplete, $missingData),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get steps array for stepper
|
|
*/
|
|
protected function getSteps(?VerificationRequest $verificationRequest, bool $isComplete, array $missingData): array
|
|
{
|
|
$status = $verificationRequest?->status;
|
|
|
|
return [
|
|
[
|
|
'title' => 'Pengajuan',
|
|
'description' => $isComplete
|
|
? 'Data sudah lengkap, silakan ajukan verifikasi'
|
|
: 'Silakan lengkapi data',
|
|
],
|
|
[
|
|
'title' => 'Verifikasi',
|
|
'description' => match ($status) {
|
|
VerificationStatus::NEED_REVISION => 'Perlu perbaikan data',
|
|
VerificationStatus::PENDING => 'Sedang diverifikasi admin',
|
|
default => 'Menunggu pengajuan',
|
|
},
|
|
],
|
|
[
|
|
'title' => 'Selesai',
|
|
'description' => match ($status) {
|
|
VerificationStatus::APPROVED => 'Verifikasi disetujui',
|
|
VerificationStatus::REJECTED => 'Verifikasi ditolak',
|
|
default => 'Menunggu keputusan',
|
|
},
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Submit unified verification
|
|
*/
|
|
public function submitVerification(Company $company, ?VerificationRequest $existingRequest): VerificationRequest
|
|
{
|
|
if ($existingRequest && $existingRequest->status === VerificationStatus::NEED_REVISION) {
|
|
// Resubmit - update existing request
|
|
$existingRequest->update([
|
|
'status' => VerificationStatus::PENDING,
|
|
]);
|
|
|
|
return $existingRequest->fresh(['reviews.reviewer']);
|
|
}
|
|
|
|
// New submission
|
|
return VerificationRequest::create([
|
|
'company_id' => $company->id,
|
|
'submitted_by' => Auth::id(),
|
|
'status' => VerificationStatus::PENDING,
|
|
])->load(['reviews.reviewer']);
|
|
}
|
|
|
|
/**
|
|
* Process review decision - unified for Company, Media, and Journalists
|
|
*/
|
|
public function processReview(VerificationRequest $verificationRequest, DecisionAdmin $decision, ?string $note): void
|
|
{
|
|
$verificationRequest->load(['company.partnerMedia.journalists']);
|
|
|
|
DB::beginTransaction();
|
|
|
|
try {
|
|
// Create review record
|
|
VerificationReview::create([
|
|
'verification_request_id' => $verificationRequest->id,
|
|
'reviewer_id' => Auth::id(),
|
|
'decision' => $decision,
|
|
'note' => $note,
|
|
]);
|
|
|
|
// Update verification request status
|
|
$newStatus = match ($decision) {
|
|
DecisionAdmin::APPROVED => VerificationStatus::APPROVED,
|
|
DecisionAdmin::NEED_REVISION => VerificationStatus::NEED_REVISION,
|
|
DecisionAdmin::REJECTED => VerificationStatus::REJECTED,
|
|
};
|
|
|
|
$verificationRequest->update([
|
|
'status' => $newStatus,
|
|
]);
|
|
|
|
// Update Company status
|
|
$company = $verificationRequest->company;
|
|
if ($company) {
|
|
$company->update(['status' => $newStatus]);
|
|
|
|
// Update Media status
|
|
$media = $company->partnerMedia;
|
|
if ($media) {
|
|
$media->update(['status' => $newStatus]);
|
|
|
|
// Update all Journalists status
|
|
$media->journalists()->update(['status' => $newStatus]);
|
|
}
|
|
}
|
|
|
|
DB::commit();
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get company name from verification request
|
|
*/
|
|
public function getCompanyName(VerificationRequest $request): string
|
|
{
|
|
return $request->company?->name ?? 'Data tidak ditemukan';
|
|
}
|
|
|
|
/**
|
|
* Get verification summary data for admin
|
|
*/
|
|
public function getVerificationSummary(VerificationRequest $request): array
|
|
{
|
|
$company = $request->company;
|
|
$media = $company?->partnerMedia;
|
|
$journalists = $media?->journalists ?? collect();
|
|
|
|
return [
|
|
'company' => [
|
|
'name' => $company?->name ?? 'Belum diisi',
|
|
'email' => $company?->email ?? '-',
|
|
'exists' => $company !== null,
|
|
],
|
|
'media' => [
|
|
'name' => $media?->name ?? 'Belum diisi',
|
|
'type' => $media?->type?->getLabel() ?? '-',
|
|
'exists' => $media !== null,
|
|
],
|
|
'journalists' => [
|
|
'count' => $journalists->count(),
|
|
'names' => $journalists->pluck('name')->take(3)->toArray(),
|
|
'exists' => $journalists->count() > 0,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get alert data for verification status
|
|
*/
|
|
public function getAlertData(?VerificationRequest $verificationRequest): ?array
|
|
{
|
|
if (! $verificationRequest) {
|
|
return null;
|
|
}
|
|
|
|
$status = $verificationRequest->status;
|
|
$latestNotes = $this->getLatestReviewNotes($verificationRequest);
|
|
|
|
if ($status === VerificationStatus::NEED_REVISION && $latestNotes) {
|
|
return [
|
|
'type' => 'revision',
|
|
'icon' => 'exclamation-triangle',
|
|
'title' => 'Catatan Revisi dari Admin',
|
|
'message' => $latestNotes,
|
|
'color' => 'warning',
|
|
];
|
|
}
|
|
|
|
if ($status === VerificationStatus::REJECTED && $latestNotes) {
|
|
return [
|
|
'type' => 'rejected',
|
|
'icon' => 'x-circle',
|
|
'title' => 'Pengajuan Ditolak',
|
|
'message' => $latestNotes,
|
|
'color' => 'danger',
|
|
];
|
|
}
|
|
|
|
if ($status === VerificationStatus::APPROVED) {
|
|
return [
|
|
'type' => 'approved',
|
|
'icon' => 'check-circle',
|
|
'title' => 'Verifikasi Diterima',
|
|
'message' => 'Verifikasi lengkap Anda telah diterima dan disetujui oleh admin. Seluruh data (Perusahaan, Media, dan Jurnalis) telah terverifikasi.',
|
|
'color' => 'success',
|
|
];
|
|
}
|
|
|
|
if ($status === VerificationStatus::PENDING) {
|
|
return [
|
|
'type' => 'pending',
|
|
'icon' => 'clock',
|
|
'title' => 'Menunggu Verifikasi',
|
|
'message' => 'Data Anda sedang dalam proses verifikasi oleh admin. Mohon tunggu.',
|
|
'color' => 'info',
|
|
'animate' => true,
|
|
];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get missing data buttons configuration
|
|
*/
|
|
public function getMissingDataButtons(?Company $company): array
|
|
{
|
|
$buttons = [];
|
|
|
|
if (! $company) {
|
|
$buttons[] = [
|
|
'label' => 'Lengkapi Data Perusahaan',
|
|
'url' => PagesCompany::getUrl(),
|
|
'icon' => 'building-office-2',
|
|
'color' => 'warning',
|
|
];
|
|
}
|
|
|
|
if ($company && ! $company->partnerMedia) {
|
|
$buttons[] = [
|
|
'label' => 'Lengkapi Data Media',
|
|
'url' => Media::getUrl(),
|
|
'icon' => 'newspaper',
|
|
'color' => 'warning',
|
|
];
|
|
}
|
|
|
|
if ($company && $company->partnerMedia && ($company->partnerMedia->journalists === null || $company->partnerMedia->journalists->count() === 0)) {
|
|
$buttons[] = [
|
|
'label' => 'Lengkapi Data Jurnalis',
|
|
'url' => ManageJournalists::getUrl(),
|
|
'icon' => 'user-circle',
|
|
'color' => 'warning',
|
|
];
|
|
}
|
|
|
|
return $buttons;
|
|
}
|
|
}
|