Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
CreateListingOpportunityAction
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
2 / 2
2
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%
41 / 41
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Owners\Application\Actions;
6
7use App\Models\User;
8use Illuminate\Support\Facades\DB;
9use ImovelZapAi\Owners\Application\Services\DefaultListingPipelineSeeder;
10use ImovelZapAi\Owners\Application\Services\ListingHistoryWriter;
11use ImovelZapAi\Owners\Domain\Enums\ListingHistoryEvent;
12use ImovelZapAi\Owners\Domain\Enums\ListingStageKey;
13use ImovelZapAi\Owners\Infrastructure\Persistence\Eloquent\ListingOpportunityModel;
14use ImovelZapAi\Owners\Infrastructure\Persistence\Eloquent\OwnerModel;
15
16final class CreateListingOpportunityAction
17{
18    public function __construct(
19        private readonly DefaultListingPipelineSeeder $pipelineSeeder,
20        private readonly ListingHistoryWriter $history,
21    ) {}
22
23    /**
24     * @param  array{
25     *     owner_id: string,
26     *     title?: string|null,
27     *     property_id?: string|null,
28     *     source?: string|null,
29     *     stage_key?: string|null,
30     *     owner_asking_price?: float|string|null,
31     *     agency_recommended_price?: float|string|null,
32     *     listed_price?: float|string|null,
33     *     conservation_state?: string|null,
34     *     pending_documents?: string|null,
35     *     sale_potential?: string|null,
36     *     evaluation_notes?: string|null,
37     *     responsible_user_id?: int|null,
38     * }  $data
39     */
40    public function execute(string $tenantId, User $actor, array $data): ListingOpportunityModel
41    {
42        return DB::transaction(function () use ($tenantId, $actor, $data): ListingOpportunityModel {
43            $owner = OwnerModel::query()
44                ->where('tenant_id', $tenantId)
45                ->whereKey($data['owner_id'])
46                ->firstOrFail();
47
48            $pipeline = $this->pipelineSeeder->ensureForTenant($tenantId);
49            $stage = $this->pipelineSeeder->stageByKey(
50                $tenantId,
51                $data['stage_key'] ?? ListingStageKey::NewContact->value,
52                $pipeline->id,
53            );
54
55            $opportunity = ListingOpportunityModel::query()->create([
56                'tenant_id' => $tenantId,
57                'pipeline_id' => $pipeline->id,
58                'stage_id' => $stage->id,
59                'owner_id' => $owner->id,
60                'property_id' => $data['property_id'] ?? null,
61                'responsible_user_id' => $data['responsible_user_id'] ?? $actor->id,
62                'created_by' => $actor->id,
63                'title' => $data['title'] ?? ('Captação — '.$owner->name),
64                'source' => $data['source'] ?? null,
65                'owner_asking_price' => $data['owner_asking_price'] ?? null,
66                'agency_recommended_price' => $data['agency_recommended_price'] ?? null,
67                'listed_price' => $data['listed_price'] ?? null,
68                'conservation_state' => $data['conservation_state'] ?? null,
69                'pending_documents' => $data['pending_documents'] ?? null,
70                'sale_potential' => $data['sale_potential'] ?? null,
71                'evaluation_notes' => $data['evaluation_notes'] ?? null,
72                'stage_entered_at' => now(),
73                'last_activity_at' => now(),
74            ]);
75
76            $this->history->write(
77                $tenantId,
78                ListingHistoryEvent::OpportunityCreated,
79                opportunityId: $opportunity->id,
80                ownerId: $owner->id,
81                actorUserId: (int) $actor->id,
82                message: 'Oportunidade de captação criada.',
83            );
84
85            return $opportunity->fresh(['stage', 'owner', 'property']);
86        });
87    }
88}