Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
89 / 89
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
GetDealTimelineQuery
100.00% covered (success)
100.00%
89 / 89
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
1 / 1
 execute
100.00% covered (success)
100.00%
89 / 89
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Sales\Application\Queries;
6
7use ImovelZapAi\Conversations\Infrastructure\Persistence\Eloquent\MessageModel;
8use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealActivityModel;
9use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealModel;
10use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealNoteModel;
11use ImovelZapAi\Sales\Infrastructure\Persistence\Eloquent\DealTaskModel;
12use ImovelZapAi\Visits\Infrastructure\Persistence\Eloquent\VisitModel;
13
14final class GetDealTimelineQuery
15{
16    /**
17     * @return list<array<string, mixed>>
18     */
19    public function execute(DealModel $deal): array
20    {
21        $items = [];
22
23        DealActivityModel::query()
24            ->where('deal_id', $deal->id)
25            ->orderBy('occurred_at')
26            ->get()
27            ->each(function (DealActivityModel $a) use (&$items): void {
28                $items[] = [
29                    'kind' => 'activity',
30                    'type' => $a->type->value ?? $a->type,
31                    'title' => $a->title,
32                    'body' => $a->body,
33                    'at' => $a->occurred_at?->toIso8601String(),
34                ];
35            });
36
37        DealNoteModel::query()
38            ->where('deal_id', $deal->id)
39            ->orderBy('created_at')
40            ->get()
41            ->each(function (DealNoteModel $n) use (&$items): void {
42                $items[] = [
43                    'kind' => 'note',
44                    'type' => 'note',
45                    'title' => 'Observação',
46                    'body' => $n->body,
47                    'at' => $n->created_at?->toIso8601String(),
48                ];
49            });
50
51        DealTaskModel::query()
52            ->where('deal_id', $deal->id)
53            ->orderBy('created_at')
54            ->get()
55            ->each(function (DealTaskModel $t) use (&$items): void {
56                $items[] = [
57                    'kind' => 'task',
58                    'type' => $t->type->value ?? $t->type,
59                    'title' => $t->title,
60                    'body' => $t->description,
61                    'at' => $t->created_at?->toIso8601String(),
62                    'status' => $t->status->value ?? $t->status,
63                ];
64            });
65
66        if ($deal->conversation_id !== null) {
67            MessageModel::query()
68                ->where('conversation_id', $deal->conversation_id)
69                ->orderBy('created_at')
70                ->limit(100)
71                ->get()
72                ->each(function (MessageModel $m) use (&$items): void {
73                    $items[] = [
74                        'kind' => 'message',
75                        'type' => 'whatsapp',
76                        'title' => 'WhatsApp',
77                        'body' => $m->body,
78                        'at' => $m->created_at?->toIso8601String(),
79                        'direction' => $m->direction->value ?? $m->direction,
80                    ];
81                });
82        }
83
84        if ($deal->visit_id !== null) {
85            $visit = VisitModel::query()->find($deal->visit_id);
86            if ($visit !== null) {
87                $items[] = [
88                    'kind' => 'visit',
89                    'type' => 'visit',
90                    'title' => 'Visita vinculada',
91                    'body' => $visit->status->value ?? (string) $visit->status,
92                    'at' => ($visit->scheduled_start ?? $visit->created_at)?->toIso8601String(),
93                ];
94            }
95        } elseif ($deal->contact_id !== null) {
96            VisitModel::query()
97                ->where('tenant_id', $deal->tenant_id)
98                ->where('contact_id', $deal->contact_id)
99                ->orderByDesc('scheduled_start')
100                ->limit(10)
101                ->get()
102                ->each(function (VisitModel $visit) use (&$items): void {
103                    $items[] = [
104                        'kind' => 'visit',
105                        'type' => 'visit',
106                        'title' => 'Visita',
107                        'body' => $visit->status instanceof \ImovelZapAi\Visits\Domain\Enums\VisitStatus
108                            ? $visit->status->label()
109                            : (string) $visit->status,
110                        'at' => ($visit->scheduled_start ?? $visit->created_at)?->toIso8601String(),
111                    ];
112                });
113        }
114
115        usort($items, static function (array $a, array $b): int {
116            return strcmp((string) ($a['at'] ?? ''), (string) ($b['at'] ?? ''));
117        });
118
119        return $items;
120    }
121}