Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
54 / 54 |
|
100.00% |
1 / 1 |
CRAP | |
100.00% |
1 / 1 |
| GetOwnerDashboardQuery | |
100.00% |
54 / 54 |
|
100.00% |
1 / 1 |
2 | |
100.00% |
1 / 1 |
| execute | |
100.00% |
54 / 54 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace ImovelZapAi\Owners\Application\Queries; |
| 6 | |
| 7 | use ImovelZapAi\Owners\Domain\Enums\ListingAgreementStatus; |
| 8 | use ImovelZapAi\Owners\Domain\Enums\ListingAgreementType; |
| 9 | use ImovelZapAi\Owners\Domain\Enums\ListingStageKey; |
| 10 | use ImovelZapAi\Owners\Infrastructure\Persistence\Eloquent\ListingAgreementModel; |
| 11 | use ImovelZapAi\Owners\Infrastructure\Persistence\Eloquent\ListingOpportunityModel; |
| 12 | |
| 13 | final class GetOwnerDashboardQuery |
| 14 | { |
| 15 | /** |
| 16 | * @return array<string, mixed> |
| 17 | */ |
| 18 | public function execute(string $tenantId): array |
| 19 | { |
| 20 | $openCapture = ListingOpportunityModel::query() |
| 21 | ->where('tenant_id', $tenantId) |
| 22 | ->whereNull('closed_at') |
| 23 | ->count(); |
| 24 | |
| 25 | $expiringDays = (int) config('owners.agreement_expiry_alert_days', 30); |
| 26 | $expiringAgreements = ListingAgreementModel::query() |
| 27 | ->where('tenant_id', $tenantId) |
| 28 | ->where('status', ListingAgreementStatus::Active) |
| 29 | ->whereDate('ends_on', '<=', now()->addDays($expiringDays)->toDateString()) |
| 30 | ->whereDate('ends_on', '>=', now()->toDateString()) |
| 31 | ->count(); |
| 32 | |
| 33 | $exclusives = ListingAgreementModel::query() |
| 34 | ->where('tenant_id', $tenantId) |
| 35 | ->where('status', ListingAgreementStatus::Active) |
| 36 | ->where('type', ListingAgreementType::Exclusive) |
| 37 | ->count(); |
| 38 | |
| 39 | $awaitingPublish = ListingOpportunityModel::query() |
| 40 | ->where('tenant_id', $tenantId) |
| 41 | ->whereNull('closed_at') |
| 42 | ->whereHas('stage', fn ($q) => $q->where('key', ListingStageKey::Captured->value)) |
| 43 | ->count(); |
| 44 | |
| 45 | $published = ListingOpportunityModel::query() |
| 46 | ->where('tenant_id', $tenantId) |
| 47 | ->whereHas('stage', fn ($q) => $q->where('key', ListingStageKey::Published->value)) |
| 48 | ->count(); |
| 49 | |
| 50 | $lost = ListingOpportunityModel::query() |
| 51 | ->where('tenant_id', $tenantId) |
| 52 | ->whereNotNull('lost_at') |
| 53 | ->count(); |
| 54 | |
| 55 | $closed = $published + $lost; |
| 56 | $conversion = $closed > 0 ? round(($published / $closed) * 100, 1) : null; |
| 57 | |
| 58 | $byBroker = ListingOpportunityModel::query() |
| 59 | ->where('tenant_id', $tenantId) |
| 60 | ->whereNotNull('responsible_user_id') |
| 61 | ->selectRaw('responsible_user_id, count(*) as total') |
| 62 | ->groupBy('responsible_user_id') |
| 63 | ->orderByDesc('total') |
| 64 | ->limit(10) |
| 65 | ->get() |
| 66 | ->map(fn ($row) => [ |
| 67 | 'responsible_user_id' => $row->responsible_user_id, |
| 68 | 'total' => (int) $row->total, |
| 69 | ]) |
| 70 | ->all(); |
| 71 | |
| 72 | return [ |
| 73 | 'open_captures' => $openCapture, |
| 74 | 'expiring_agreements' => $expiringAgreements, |
| 75 | 'exclusive_agreements' => $exclusives, |
| 76 | 'awaiting_publish' => $awaitingPublish, |
| 77 | 'published' => $published, |
| 78 | 'lost' => $lost, |
| 79 | 'conversion_rate' => $conversion, |
| 80 | 'by_broker' => $byBroker, |
| 81 | ]; |
| 82 | } |
| 83 | } |