<?php
namespace App\Actions\Complaint;
use App\Models\Client;
use App\Models\Complaint;
use App\Models\ComplaintActivity;
use App\Models\User;
use App\Notifications\NewComplaintSubmitted;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Notification;
class CreateComplaintAction
{
/**
* Store a guest-submitted complaint: generate its ticket number, log the
* creation, and notify every admin. Price is intentionally left unset —
* admin decides the invoice amount per ticket once it's resolved (§14/§16),
* not auto-copied from the client's rate at submission time.
*
* @param array{client_id: string, application_id?: string|null, subject: string, description: string, report_by: string, priority?: string} $data
* @param array<int, UploadedFile> $photos
*/
public function handle(array $data, array $photos = []): Complaint
{
$client = Client::findOrFail($data['client_id']);
$photoPaths = array_map(
fn ($photo) => $photo->store('complaint-photos', 'public'),
$photos,
);
$complaint = DB::transaction(function () use ($data, $client, $photoPaths) {
$complaint = Complaint::create([
'ticket_number' => $this->generateTicketNumber(),
'subject' => $data['subject'],
'description' => $data['description'],
'report_by' => $data['report_by'],
'client_id' => $client->id,
'application_id' => $data['application_id'] ?? null,
'priority' => $data['priority'] ?? 'normal',
'photo' => $photoPaths,
'report_date' => now(),
'status' => 'open',
]);
ComplaintActivity::create([
'complaint_id' => $complaint->id,
'causer_id' => null,
'action' => 'created',
'note' => "Tiket dibuat oleh {$data['report_by']} untuk instansi {$client->name}.",
]);
return $complaint;
});
$admins = User::query()->where('role', 'admin')->where('is_active', true)->get();
Notification::send($admins, new NewComplaintSubmitted($complaint));
return $complaint;
}
/**
* Build a daily-sequential ticket number, e.g. TCK-20260922-0001.
*/
private function generateTicketNumber(): string
{
$prefix = 'TCK-'.now()->format('Ymd').'-';
$todayCount = Complaint::query()
->where('ticket_number', 'like', $prefix.'%')
->count();
return $prefix.str_pad((string) ($todayCount + 1), 4, '0', STR_PAD_LEFT);
}
}