Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
92.45% covered (success)
92.45%
49 / 53
50.00% covered (danger)
50.00%
1 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
CreateDocumentVersionAction
92.45% covered (success)
92.45%
49 / 53
50.00% covered (danger)
50.00%
1 / 2
8.03
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
92.31% covered (success)
92.31%
48 / 52
0.00% covered (danger)
0.00%
0 / 1
7.02
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Documents\Application\Actions;
6
7use App\Models\User;
8use Illuminate\Support\Facades\DB;
9use Illuminate\Support\Str;
10use ImovelZapAi\Documents\Application\Services\DocumentHistoryWriter;
11use ImovelZapAi\Documents\Application\Services\DocumentPdfGenerator;
12use ImovelZapAi\Documents\Application\Services\DocumentVariableResolver;
13use ImovelZapAi\Documents\Domain\Enums\DocumentHistoryEvent;
14use ImovelZapAi\Documents\Domain\Enums\DocumentStatus;
15use ImovelZapAi\Documents\Domain\Exceptions\DocumentException;
16use ImovelZapAi\Documents\Infrastructure\Persistence\Eloquent\BusinessDocumentModel;
17use ImovelZapAi\Documents\Infrastructure\Persistence\Eloquent\DocumentTemplateModel;
18use ImovelZapAi\Documents\Infrastructure\Persistence\Eloquent\DocumentVersionModel;
19
20final class CreateDocumentVersionAction
21{
22    public function __construct(
23        private readonly DocumentVariableResolver $resolver,
24        private readonly DocumentPdfGenerator $pdf,
25        private readonly DocumentHistoryWriter $history,
26    ) {}
27
28    /**
29     * @param  array{
30     *     amount?: float|string|null,
31     *     intro_message?: string|null,
32     *     title?: string|null,
33     *     change_summary?: string|null,
34     *     context_snapshot?: array<string, mixed>|null,
35     * }  $data
36     */
37    public function execute(BusinessDocumentModel $document, User $actor, array $data = []): DocumentVersionModel
38    {
39        if (in_array($document->status, [
40            DocumentStatus::Accepted,
41            DocumentStatus::Rejected,
42            DocumentStatus::Expired,
43        ], true)) {
44            throw DocumentException::invalidState('documento encerrado.');
45        }
46
47        return DB::transaction(function () use ($document, $actor, $data): DocumentVersionModel {
48            if (array_key_exists('amount', $data)) {
49                $document->amount = $data['amount'];
50            }
51            if (array_key_exists('intro_message', $data)) {
52                $document->intro_message = $data['intro_message'];
53            }
54            if (! empty($data['title'])) {
55                $document->title = $data['title'];
56            }
57            if (array_key_exists('context_snapshot', $data)) {
58                $document->context_snapshot = $data['context_snapshot'];
59            }
60            if ($document->status === DocumentStatus::ChangesRequested) {
61                $document->status = DocumentStatus::Draft;
62            }
63            $document->save();
64
65            $document->load(['contact', 'property.neighborhood', 'property.city', 'responsible', 'template']);
66            $next = ((int) $document->versions()->max('version')) + 1;
67            $template = $document->template
68                ?? DocumentTemplateModel::query()
69                    ->where('tenant_id', $document->tenant_id)
70                    ->where('document_type', $document->document_type)
71                    ->where('is_default', true)
72                    ->firstOrFail();
73
74            $snapshot = $this->resolver->snapshot($document, $next);
75            $html = $this->resolver->resolve($template->body_html, $snapshot['variables']);
76
77            $version = DocumentVersionModel::query()->create([
78                'tenant_id' => $document->tenant_id,
79                'business_document_id' => $document->id,
80                'version' => $next,
81                'snapshot' => $snapshot,
82                'html_body' => $html,
83                'change_summary' => $data['change_summary'] ?? 'Nova revisão',
84                'validation_code' => Str::upper(Str::random(10)),
85                'created_by' => $actor->id,
86            ]);
87
88            $pdf = $this->pdf->generate($document, $version, '');
89            $version->forceFill(['pdf_disk' => $pdf['disk'], 'pdf_path' => $pdf['path']])->save();
90            $document->forceFill(['current_version_id' => $version->id])->save();
91
92            $this->history->write(
93                $document->tenant_id,
94                $document->id,
95                DocumentHistoryEvent::VersionCreated,
96                actorType: 'broker',
97                actorUserId: (int) $actor->id,
98                payload: ['version' => $next],
99                message: 'Versão v'.$next.' criada.',
100            );
101
102            return $version->fresh();
103        });
104    }
105}