Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.00% covered (success)
98.00%
49 / 50
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
GetVisitDashboardQuery
98.00% covered (success)
98.00%
49 / 50
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 execute
98.00% covered (success)
98.00%
49 / 50
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Visits\Application\Queries;
6
7use ImovelZapAi\Visits\Domain\Enums\VisitStatus;
8use ImovelZapAi\Visits\Infrastructure\Persistence\Eloquent\VisitModel;
9
10final class GetVisitDashboardQuery
11{
12    /**
13     * @return array<string, mixed>
14     */
15    public function execute(string $tenantId): array
16    {
17        $base = VisitModel::query()->where('tenant_id', $tenantId);
18
19        $scheduled = (clone $base)->whereIn('status', [
20            VisitStatus::Scheduled,
21            VisitStatus::Confirmed,
22            VisitStatus::Requested,
23        ])->count();
24
25        $completed = (clone $base)->where('status', VisitStatus::Completed)->count();
26        $cancelled = (clone $base)->where('status', VisitStatus::Cancelled)->count();
27        $noShow = (clone $base)->where('status', VisitStatus::NoShow)->count();
28        $inProgress = (clone $base)->where('status', VisitStatus::InProgress)->count();
29
30        $attendanceDenom = $completed + $noShow;
31        $attendanceRate = $attendanceDenom > 0
32            ? round(($completed / $attendanceDenom) * 100, 1)
33            : null;
34
35        $byBroker = VisitModel::query()
36            ->where('tenant_id', $tenantId)
37            ->whereNotNull('responsible_user_id')
38            ->selectRaw('responsible_user_id, count(*) as total')
39            ->groupBy('responsible_user_id')
40            ->orderByDesc('total')
41            ->limit(10)
42            ->get()
43            ->map(static fn ($row) => [
44                'responsible_user_id' => $row->responsible_user_id,
45                'total' => (int) $row->total,
46            ])
47            ->all();
48
49        $byProperty = VisitModel::query()
50            ->where('tenant_id', $tenantId)
51            ->whereNotNull('property_id')
52            ->selectRaw('property_id, count(*) as total')
53            ->groupBy('property_id')
54            ->orderByDesc('total')
55            ->limit(10)
56            ->get()
57            ->map(static fn ($row) => [
58                'property_id' => $row->property_id,
59                'total' => (int) $row->total,
60            ])
61            ->all();
62
63        return [
64            'scheduled' => $scheduled,
65            'completed' => $completed,
66            'cancelled' => $cancelled,
67            'no_show' => $noShow,
68            'in_progress' => $inProgress,
69            'attendance_rate' => $attendanceRate,
70            'by_broker' => $byBroker,
71            'by_property' => $byProperty,
72        ];
73    }
74}