Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
90.70% covered (success)
90.70%
39 / 43
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
UpdateDealAction
90.70% covered (success)
90.70%
39 / 43
50.00% covered (danger)
50.00%
1 / 2
14.16
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
90.48% covered (success)
90.48%
38 / 42
0.00% covered (danger)
0.00%
0 / 1
13.15
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Sales\Application\Actions;
6
7use App\Models\User;
8use Carbon\Carbon;
9use Illuminate\Support\Facades\DB;
10use ImovelZapAi\Sales\Application\Services\DealActivityRecorder;
11use ImovelZapAi\Sales\Application\Services\DealHistoryWriter;
12use ImovelZapAi\Sales\Domain\Enums\DealActivityType;
13use ImovelZapAi\Sales\Domain\Enums\DealHistoryEvent;
14use ImovelZapAi\Sales\Domain\Enums\DealPriority;
15use ImovelZapAi\Sales\Domain\Enums\DealTaskType;
16use ImovelZapAi\Sales\Domain\Exceptions\DealException;
17use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;
18
19final class UpdateDealAction
20{
21    public function __construct(
22        private readonly DealActivityRecorder $activities,
23        private readonly DealHistoryWriter $history,
24    ) {}
25
26    /**
27     * @param  array{
28     *     title?: string|null,
29     *     amount?: float|string|null,
30     *     priority?: string|null,
31     *     responsible_user_id?: int|null,
32     *     property_id?: string|null,
33     *     next_action_at?: string|null,
34     *     next_action_type?: string|null,
35     *     next_action_notes?: string|null,
36     * }  $data
37     */
38    public function execute(DealModel $deal, User $actor, array $data): DealModel
39    {
40        if ($deal->isClosed()) {
41            throw DealException::alreadyClosed();
42        }
43
44        return DB::transaction(function () use ($deal, $actor, $data): DealModel {
45            $before = $deal->only([
46                'title', 'amount', 'priority', 'responsible_user_id', 'property_id',
47                'next_action_at', 'next_action_type', 'next_action_notes',
48            ]);
49
50            $fill = [];
51            foreach (['title', 'amount', 'property_id', 'next_action_notes'] as $field) {
52                if (array_key_exists($field, $data)) {
53                    $fill[$field] = $data[$field];
54                }
55            }
56            if (array_key_exists('priority', $data) && $data['priority'] !== null) {
57                $fill['priority'] = DealPriority::from((string) $data['priority']);
58            }
59            if (array_key_exists('responsible_user_id', $data)) {
60                $fill['responsible_user_id'] = $data['responsible_user_id'];
61            }
62            if (array_key_exists('next_action_at', $data)) {
63                $fill['next_action_at'] = $data['next_action_at']
64                    ? Carbon::parse((string) $data['next_action_at'])
65                    : null;
66            }
67            if (array_key_exists('next_action_type', $data)) {
68                $fill['next_action_type'] = $data['next_action_type']
69                    ? DealTaskType::from((string) $data['next_action_type'])
70                    : null;
71            }
72
73            $deal->forceFill($fill)->save();
74
75            if (isset($fill['next_action_at']) || isset($fill['next_action_type'])) {
76                $this->activities->record(
77                    $deal,
78                    DealActivityType::NextActionSet,
79                    'Próxima ação atualizada',
80                    actorUserId: (int) $actor->id,
81                );
82            }
83
84            $this->history->write(
85                $deal->tenant_id,
86                $deal->id,
87                DealHistoryEvent::Updated,
88                actorUserId: (int) $actor->id,
89                before: $before,
90                after: $deal->only(array_keys($before)),
91                message: 'Oportunidade atualizada.',
92            );
93
94            return $deal->fresh(['stage', 'contact', 'property', 'responsible']);
95        });
96    }
97}