Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.49% covered (success)
91.49%
43 / 47
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
GetClientPortalDashboardQuery
91.49% covered (success)
91.49%
43 / 47
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 1
 execute
91.49% covered (success)
91.49%
43 / 47
0.00% covered (danger)
0.00%
0 / 1
2.00
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\ClientPortal\Application\Queries;
6
7use ImovelZapAi\ClientPortal\Domain\Enums\PortalStatus;
8use ImovelZapAi\ClientPortal\Domain\Enums\RequestedDocumentStatus;
9use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\ClientPortalModel;
10use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\PortalActivityModel;
11use ImovelZapAi\ClientPortal\Infrastructure\Persistence\Eloquent\RequestedDocumentModel;
12
13final class GetClientPortalDashboardQuery
14{
15    /**
16     * @return array<string, mixed>
17     */
18    public function execute(string $tenantId): array
19    {
20        $active = ClientPortalModel::query()
21            ->where('tenant_id', $tenantId)
22            ->where('status', PortalStatus::Active)
23            ->count();
24
25        $expired = ClientPortalModel::query()
26            ->where('tenant_id', $tenantId)
27            ->where(function ($q): void {
28                $q->where('status', PortalStatus::Expired)
29                    ->orWhere(function ($q2): void {
30                        $q2->where('status', PortalStatus::Active)
31                            ->whereNotNull('expires_at')
32                            ->where('expires_at', '<', now());
33                    });
34            })
35            ->count();
36
37        $uploadedToday = PortalActivityModel::query()
38            ->where('tenant_id', $tenantId)
39            ->where('event', 'document_uploaded')
40            ->whereDate('created_at', now()->toDateString())
41            ->count();
42
43        $pendingReview = RequestedDocumentModel::query()
44            ->where('tenant_id', $tenantId)
45            ->whereIn('status', [
46                RequestedDocumentStatus::UnderReview->value,
47                RequestedDocumentStatus::UnderAnalysis->value,
48                RequestedDocumentStatus::Uploaded->value,
49            ])
50            ->count();
51
52        $completed = ClientPortalModel::query()
53            ->where('tenant_id', $tenantId)
54            ->where('status', PortalStatus::Completed)
55            ->whereNotNull('completed_at')
56            ->whereNotNull('created_at')
57            ->get(['created_at', 'completed_at']);
58
59        $avgHours = null;
60        if ($completed->isNotEmpty()) {
61            $avgHours = round(
62                $completed->avg(fn (ClientPortalModel $p) => $p->created_at->diffInMinutes($p->completed_at) / 60),
63                1,
64            );
65        }
66
67        return [
68            'active_portals' => $active,
69            'uploaded_today' => $uploadedToday,
70            'pending_review' => $pendingReview,
71            'expired_portals' => $expired,
72            'avg_completion_hours' => $avgHours,
73        ];
74    }
75}