Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.97% covered (success)
96.97%
32 / 33
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
LinkOwnerPropertyAction
96.97% covered (success)
96.97%
32 / 33
50.00% covered (danger)
50.00%
1 / 2
4
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
96.88% covered (success)
96.88%
31 / 32
0.00% covered (danger)
0.00%
0 / 1
3
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\ListingHistoryWriter;
10use ImovelZapAi\Owners\Domain\Enums\ListingHistoryEvent;
11use ImovelZapAi\Owners\Domain\Exceptions\OwnerException;
12use ImovelZapAi\Owners\Infrastructure\Persistence\Eloquent\ListingOpportunityModel;
13use ImovelZapAi\Owners\Infrastructure\Persistence\Eloquent\OwnerModel;
14use ImovelZapAi\Properties\Infrastructure\Persistence\Eloquent\PropertyModel;
15
16final class LinkOwnerPropertyAction
17{
18    public function __construct(
19        private readonly ListingHistoryWriter $history,
20    ) {}
21
22    public function execute(
23        string $tenantId,
24        User $actor,
25        string $ownerId,
26        string $propertyId,
27        bool $isPrimary = true,
28        ?float $ownershipShare = null,
29        ?string $opportunityId = null,
30    ): void {
31        DB::transaction(function () use ($tenantId, $actor, $ownerId, $propertyId, $isPrimary, $ownershipShare, $opportunityId): void {
32            OwnerModel::query()->where('tenant_id', $tenantId)->whereKey($ownerId)->firstOrFail();
33            PropertyModel::query()->where('tenant_id', $tenantId)->whereKey($propertyId)->firstOrFail();
34
35            /** @var OwnerModel $owner */
36            $owner = OwnerModel::query()->findOrFail($ownerId);
37            $owner->properties()->syncWithoutDetaching([
38                $propertyId => [
39                    'tenant_id' => $tenantId,
40                    'is_primary' => $isPrimary,
41                    'ownership_share' => $ownershipShare,
42                ],
43            ]);
44
45            if ($opportunityId !== null) {
46                $opportunity = ListingOpportunityModel::query()
47                    ->where('tenant_id', $tenantId)
48                    ->whereKey($opportunityId)
49                    ->firstOrFail();
50
51                if ($opportunity->isClosed()) {
52                    throw OwnerException::invalidState('oportunidade encerrada.');
53                }
54
55                $opportunity->forceFill([
56                    'property_id' => $propertyId,
57                    'last_activity_at' => now(),
58                ])->save();
59            }
60
61            $this->history->write(
62                $tenantId,
63                ListingHistoryEvent::PropertyLinked,
64                opportunityId: $opportunityId,
65                ownerId: $ownerId,
66                actorUserId: (int) $actor->id,
67                after: ['property_id' => $propertyId],
68                message: 'Imóvel vinculado ao proprietário.',
69            );
70        });
71    }
72}