Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
UploadImportAction
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
2 / 2
6
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
43 / 43
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2
3declare(strict_types=1);
4
5namespace ImovelZapAi\Importing\Application\Actions;
6
7use App\Models\User;
8use Illuminate\Http\UploadedFile;
9use Illuminate\Support\Facades\DB;
10use ImovelZapAi\Importing\Application\Services\ImportFileStorage;
11use ImovelZapAi\Importing\Application\Services\ImportLogWriter;
12use ImovelZapAi\Importing\Domain\Enums\ImportJobStatus;
13use ImovelZapAi\Importing\Domain\Enums\ImportLogEvent;
14use ImovelZapAi\Importing\Infrastructure\Jobs\AnalyzeImportJob;
15use ImovelZapAi\Importing\Infrastructure\Persistence\Eloquent\ImportFileModel;
16use ImovelZapAi\Importing\Infrastructure\Persistence\Eloquent\ImportJobModel;
17
18final class UploadImportAction
19{
20    public function __construct(
21        private readonly ImportFileStorage $storage,
22        private readonly ImportLogWriter $logWriter,
23    ) {}
24
25    public function execute(
26        string $tenantId,
27        User $actor,
28        UploadedFile $file,
29        ?string $idempotencyKey = null,
30    ): ImportJobModel {
31        if ($idempotencyKey !== null && $idempotencyKey !== '') {
32            $existing = ImportJobModel::query()
33                ->where('tenant_id', $tenantId)
34                ->where('idempotency_key', $idempotencyKey)
35                ->first();
36
37            if ($existing !== null) {
38                return $existing->load('file');
39            }
40        }
41
42        return DB::transaction(function () use ($tenantId, $actor, $file, $idempotencyKey): ImportJobModel {
43            $job = ImportJobModel::query()->create([
44                'tenant_id' => $tenantId,
45                'created_by' => $actor->id,
46                'status' => ImportJobStatus::Uploaded,
47                'format' => 'vrsync',
48                'idempotency_key' => $idempotencyKey !== '' ? $idempotencyKey : null,
49            ]);
50
51            $stored = $this->storage->storeUpload($tenantId, $job->id, $file);
52
53            ImportFileModel::query()->create([
54                'tenant_id' => $tenantId,
55                'import_job_id' => $job->id,
56                'original_name' => $file->getClientOriginalName(),
57                'mime_type' => $stored['mime_type'],
58                'size_bytes' => $stored['size_bytes'],
59                'sha256' => $stored['sha256'],
60                'disk' => $this->storage->disk(),
61                'path' => $stored['path'],
62                'metadata' => [
63                    'extension' => $file->getClientOriginalExtension(),
64                ],
65            ]);
66
67            $this->logWriter->write(
68                $tenantId,
69                $job->id,
70                ImportLogEvent::Uploaded,
71                message: 'Arquivo VRSync recebido.',
72            );
73
74            $job->forceFill([
75                'status' => ImportJobStatus::Analyzing,
76                'analyzing_started_at' => now(),
77            ])->save();
78
79            AnalyzeImportJob::dispatch($job->id, $tenantId)
80                ->onQueue((string) config('importing.queue', 'imports'));
81
82            return $job->fresh(['file']);
83        });
84    }
85}