Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
CancelVisitAction
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
2 / 2
3
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Visits\Application\Actions;
6
7use App\Models\User;
8use Illuminate\Support\Facades\DB;
9use ImovelZapAi\Visits\Application\Services\VisitLogWriter;
10use ImovelZapAi\Visits\Application\Services\VisitReminderScheduler;
11use ImovelZapAi\Visits\Application\Services\VisitSnapshotter;
12use ImovelZapAi\Visits\Domain\Enums\VisitLogEvent;
13use ImovelZapAi\Visits\Domain\Enums\VisitStatus;
14use ImovelZapAi\Visits\Domain\Events\VisitCancelled;
15use ImovelZapAi\Visits\Domain\Exceptions\VisitException;
16use ImovelZapAi\Visits\Infrastructure\Persistence\Eloquent\VisitModel;
17
18final class CancelVisitAction
19{
20    public function __construct(
21        private readonly VisitReminderScheduler $reminderScheduler,
22        private readonly VisitLogWriter $logWriter,
23        private readonly VisitSnapshotter $snapshotter,
24    ) {}
25
26    public function execute(VisitModel $visit, User $actor, ?string $reason = null): VisitModel
27    {
28        if (! $visit->status->canCancel()) {
29            throw VisitException::invalidState($visit->status->value, 'cancel');
30        }
31
32        return DB::transaction(function () use ($visit, $actor, $reason): VisitModel {
33            $before = $this->snapshotter->snapshot($visit);
34
35            $visit->forceFill([
36                'status' => VisitStatus::Cancelled,
37                'cancelled_at' => now(),
38                'cancellation_reason' => $reason,
39            ])->save();
40
41            $this->reminderScheduler->cancelPending($visit->id);
42
43            $this->logWriter->write(
44                $visit->tenant_id,
45                $visit->id,
46                VisitLogEvent::Cancelled,
47                actorUserId: (int) $actor->id,
48                before: $before,
49                after: $this->snapshotter->snapshot($visit->fresh()),
50                message: $reason ?? 'Visita cancelada.',
51            );
52
53            VisitCancelled::dispatch($visit->tenant_id, $visit->id);
54
55            return $visit->fresh();
56        });
57    }
58}