++ fix: Rientro assegnazione e territorio

This commit is contained in:
2026-04-08 11:55:14 +00:00
parent 777f239c7a
commit 6f8010514d
36 changed files with 1186 additions and 91 deletions

View File

@@ -0,0 +1,94 @@
<?php
namespace App\Services;
use App\Jobs\ImportTerritoryPdfFolder;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Str;
use RuntimeException;
use ZipArchive;
class TerritorioPdfImportDispatcher
{
public function __construct(
protected TerritorioPdfImportState $stateService,
) {
}
public function dispatchStoredFiles(string $importId, array $storedFiles, ?int $actorId, string $initialLog): array
{
$state = $this->stateService->initialize($importId, count($storedFiles));
$this->stateService->appendLog($importId, $initialLog);
ImportTerritoryPdfFolder::dispatch($importId, $storedFiles, $actorId);
return $this->stateService->get($importId) ?? $state;
}
public function dispatchUploadedZip(UploadedFile $zipFile, ?int $actorId): string
{
$importId = (string) Str::uuid();
$zipStoredPath = $zipFile->storeAs(
'bulk-territori-imports/' . $importId,
'archivio-' . $importId . '.zip',
'local'
);
$zipAbsolutePath = storage_path('app/' . $zipStoredPath);
$zip = new ZipArchive();
if ($zip->open($zipAbsolutePath) !== true) {
throw new RuntimeException('Impossibile aprire il file ZIP.');
}
$storedFiles = [];
$entryIndex = 0;
try {
for ($index = 0; $index < $zip->numFiles; $index++) {
$entryName = $zip->getNameIndex($index);
if (! $entryName || str_ends_with($entryName, '/')) {
continue;
}
if (strtolower(pathinfo($entryName, PATHINFO_EXTENSION)) !== 'pdf') {
continue;
}
$content = $zip->getFromIndex($index);
if ($content === false) {
continue;
}
$originalName = basename($entryName);
$safeName = Str::slug(pathinfo($originalName, PATHINFO_FILENAME));
$storedPath = 'bulk-territori-imports/' . $importId . '/zip-' . str_pad((string) $entryIndex, 4, '0', STR_PAD_LEFT) . '-' . $safeName . '.pdf';
file_put_contents(storage_path('app/' . $storedPath), $content);
$storedFiles[] = [
'original_name' => $originalName,
'stored_path' => $storedPath,
];
$entryIndex++;
}
} finally {
$zip->close();
}
if ($storedFiles === []) {
throw new RuntimeException('Lo ZIP non contiene file PDF validi.');
}
$this->dispatchStoredFiles(
$importId,
$storedFiles,
$actorId,
'Archivio ZIP ricevuto: ' . count($storedFiles) . ' PDF estratti e messi in coda per l\'elaborazione.'
);
return $importId;
}
}

View File

@@ -0,0 +1,122 @@
<?php
namespace App\Services;
use Illuminate\Support\Facades\Cache;
class TerritorioPdfImportState
{
protected int $ttlSeconds = 86400;
public function initialize(string $importId, int $totalFiles): array
{
$state = [
'id' => $importId,
'status' => 'queued',
'stats' => [
'total' => $totalFiles,
'processed' => 0,
'updated' => 0,
'skipped' => 0,
'errors' => 0,
],
'logs' => [
'Import creato. In attesa del worker di coda.',
],
'issues' => [],
'started_at' => null,
'finished_at' => null,
];
$this->put($importId, $state);
return $state;
}
public function get(string $importId): ?array
{
return Cache::get($this->key($importId));
}
public function put(string $importId, array $state): void
{
Cache::put($this->key($importId), $state, $this->ttlSeconds);
}
public function update(string $importId, callable $callback): ?array
{
$state = $this->get($importId);
if (! $state) {
return null;
}
$updatedState = $callback($state) ?? $state;
$this->put($importId, $updatedState);
return $updatedState;
}
public function appendLog(string $importId, string $message): void
{
$this->update($importId, function (array $state) use ($message) {
$timestamp = now()->format('H:i:s');
$state['logs'][] = '[' . $timestamp . '] ' . $message;
return $state;
});
}
public function increment(string $importId, string $metric, int $amount = 1): void
{
$this->update($importId, function (array $state) use ($metric, $amount) {
$state['stats'][$metric] = ($state['stats'][$metric] ?? 0) + $amount;
return $state;
});
}
public function addIssue(string $importId, array $issue): void
{
$this->update($importId, function (array $state) use ($issue) {
$state['issues'][] = $issue;
return $state;
});
}
public function markRunning(string $importId): void
{
$this->update($importId, function (array $state) {
$state['status'] = 'running';
$state['started_at'] = now()->toDateTimeString();
return $state;
});
}
public function markCompleted(string $importId): void
{
$this->update($importId, function (array $state) {
$state['status'] = 'completed';
$state['finished_at'] = now()->toDateTimeString();
return $state;
});
}
public function markFailed(string $importId): void
{
$this->update($importId, function (array $state) {
$state['status'] = 'failed';
$state['finished_at'] = now()->toDateTimeString();
return $state;
});
}
protected function key(string $importId): string
{
return 'territori-pdf-import:' . $importId;
}
}