Files
carmine.savino 0f0764367f feat: remove obsolete glass configurations, add title import functionality
- Deleted the `vetro.json` file containing glass configurations.
- Introduced `ImportaTitoliAction` to facilitate importing model titles from Excel.
- Created `TitoliModelliImporter` for handling title import logic and updating existing models.
- Updated `SistemaResource` to include the new title import action.
- Modified `ConfigurazioneModello` to adjust the model name retrieval logic.
- Changed `ListinoImporter` to make the alias constant public.
- Added tests for title import functionality, ensuring correct updates and creation of new models.
2026-10-23 11:15:28 +02:00

101 lines
3.8 KiB
PHP

<?php
namespace App\Support\Listini;
use App\Models\Modello;
use App\Models\Sistema;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
class ListinoImporter
{
// Codici del file con refusi noti rispetto al codice interno del modello.
public const ALIAS = [
'finestra_wasistas' => 'finestra_vasistas',
];
/**
* Associazione proposta codice-del-file → modello del sistema (null se nessun
* modello corrisponde): per codice interno, poi per nome o descrizione.
*
* @param list<string> $codici
* @return array<string, int|null>
*/
public static function suggerisciAssociazioni(Sistema $sistema, array $codici): array
{
$modelli = $sistema->modelli()->get();
$associazioni = [];
foreach ($codici as $codice) {
$associazioni[$codice] = self::trovaModello($modelli, $codice)?->id;
}
return $associazioni;
}
private static function trovaModello(Collection $modelli, string $codice): ?Modello
{
$slug = Str::slug($codice, '_');
$slug = self::ALIAS[$slug] ?? $slug;
return $modelli->first(fn (Modello $m) => $m->codice === $slug)
?? $modelli->first(fn (Modello $m) => Str::slug($m->nome, '_') === $slug)
?? $modelli->first(fn (Modello $m) => $m->descrizione && Str::slug($m->descrizione, '_') === $slug);
}
/**
* Sostituisce il listino di ogni modello associato con i prezzi del rispettivo blocco.
* Con $preservaPersonalizzati i prezzi inseriti a mano restano e prevalgono sull'Excel
* per la stessa misura; altrimenti l'Excel sostituisce tutto.
*
* @param list<array{codice: string, prezzi: list<array>}> $blocchi
* @param array<string, int|null> $associazioni codice del file → id modello
* @return int numero di modelli aggiornati
*/
public static function importa(Sistema $sistema, array $blocchi, array $associazioni, bool $preservaPersonalizzati = false): int
{
$prezziPerCodice = collect($blocchi)->keyBy('codice')->map(fn (array $b) => $b['prezzi']);
$modelli = $sistema->modelli()->get()->keyBy('id');
return DB::transaction(function () use ($associazioni, $prezziPerCodice, $modelli, $preservaPersonalizzati) {
$aggiornati = 0;
$ora = now();
foreach ($associazioni as $codice => $modelloId) {
$modello = $modelloId ? $modelli->get($modelloId) : null;
if (! $modello || ! $prezziPerCodice->has($codice)) {
continue;
}
$misura = fn ($p) => (int) $p['larghezza'].'x'.(int) $p['altezza'];
$daEliminare = $modello->listino();
$personalizzate = [];
if ($preservaPersonalizzati) {
$daEliminare->where('personalizzato', false);
$personalizzate = $modello->listino()->where('personalizzato', true)->get()
->mapWithKeys(fn ($p) => [$misura($p) => true])
->all();
}
$daEliminare->delete();
// Una stessa misura ripetuta nel blocco: vale l'ultima.
$righe = collect($prezziPerCodice[$codice])
->keyBy($misura)
->reject(fn (array $p, string $chiave) => isset($personalizzate[$chiave]))
->map(fn (array $p) => $p + ['modello_id' => $modello->id, 'created_at' => $ora, 'updated_at' => $ora])
->values();
foreach ($righe->chunk(500) as $chunk) {
$modello->listino()->insert($chunk->all());
}
$modello->update(['listino_aggiornato_at' => $ora]);
$aggiornati++;
}
return $aggiornati;
});
}
}