feat: add previous configuration handling for user selections in quotes

- Implemented session storage management for the last configuration choices made by the user.
- Added functionality to prompt users when changing models to retain their previous selections.
- Introduced methods to apply previous choices to the newly loaded model, including finishes, handles, glass types, and options.
- Enhanced user experience by ensuring selections are automatically applied where applicable.
This commit is contained in:
2026-10-19 19:49:44 +02:00
parent 863e6ca920
commit 06617a985a
197 changed files with 4892 additions and 400 deletions
+139
View File
@@ -0,0 +1,139 @@
<?php
namespace App\Models;
use App\Models\Concerns\HaImmaginiCatalogo;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Collection;
/**
* Opzione del configuratore con eventuale supplemento di prezzo. Le righe senza modello
* valgono per tutto il sistema; se un modello ha righe proprie per un gruppo, per quel
* modello sostituiscono l'intero gruppo del sistema.
*/
class Opzione extends Model
{
use HaImmaginiCatalogo;
protected $table = 'opzioni';
/** Valori del gruppo tipo_finitura, derivati dalle finiture scelte (vedi CalcolatorePrezzo). */
public const TIPI_FINITURA = [
'bianco' => 'Bianco (finitura predefinita su interno ed esterno)',
'uniforme' => 'Uniforme (stessa finitura su interno ed esterno)',
'bicolore' => 'Bicolore (finiture diverse)',
];
public const SUPPLEMENTI = [
'percentuale' => 'Percentuale sul prezzo base',
'fisso' => 'Importo fisso (€)',
'metro_lineare' => 'Al metro lineare (€/ml)',
];
protected static array $immagini = ['icona'];
protected $fillable = [
'sistema_id', 'modello_id', 'gruppo', 'valore', 'etichetta', 'icona', 'alternativa',
'supplemento_tipo', 'supplemento', 'ml_per_larghezza', 'ml_per_altezza', 'ml_aggiunta_mm',
'parametri', 'ordine', 'attivo',
];
protected $casts = [
'supplemento' => 'float',
'ml_per_larghezza' => 'float',
'ml_per_altezza' => 'float',
'ml_aggiunta_mm' => 'float',
'parametri' => 'array',
'ordine' => 'integer',
'attivo' => 'boolean',
];
public function sistema(): BelongsTo
{
return $this->belongsTo(Sistema::class);
}
public function modello(): BelongsTo
{
return $this->belongsTo(Modello::class);
}
public function definizione(): BelongsTo
{
return $this->belongsTo(GruppoOpzioni::class, 'gruppo', 'codice');
}
public function scopeDelSistema(Builder $query): Builder
{
return $query->whereNull('modello_id');
}
/**
* Opzioni attive valide per il modello, per gruppo: quelle del modello dove ne ha,
* altrimenti quelle del sistema.
*
* @return Collection<string,Collection<int,Opzione>>
*/
public static function perModello(Modello $modello): Collection
{
$righe = static::query()
->where('sistema_id', $modello->sistema_id)
->where(fn (Builder $q) => $q->whereNull('modello_id')->orWhere('modello_id', $modello->getKey()))
->orderBy('ordine')
->orderBy('id')
->get();
// Basta una riga del modello (anche disattiva) per sostituire il gruppo.
$personalizzati = $righe->whereNotNull('modello_id')->pluck('gruppo')->unique();
return $righe
->filter(fn (Opzione $o) => $o->attivo && ($o->modello_id !== null) === $personalizzati->contains($o->gruppo))
->groupBy('gruppo');
}
public function descriviSupplemento(): string
{
if (! $this->supplemento_tipo || ! $this->supplemento) {
return '—';
}
$valore = number_format($this->supplemento, 2, ',', '.');
return match ($this->supplemento_tipo) {
'percentuale' => "{$valore}%",
'metro_lineare' => "€ {$valore}/ml × ".$this->formulaMetri(),
default => "€ {$valore}",
};
}
/** Metri lineari per un serramento L x H (mm), senza arrotondamenti. */
public function metriLineari(float $larghezza, float $altezza): float
{
return max(0, $larghezza * $this->ml_per_larghezza + $altezza * $this->ml_per_altezza + $this->ml_aggiunta_mm) / 1000;
}
/** Importo del supplemento sul prezzo base, per un serramento L x H (mm). */
public function importo(float $base, float $larghezza, float $altezza): float
{
return match ($this->supplemento_tipo) {
'percentuale' => $base * $this->supplemento / 100,
'metro_lineare' => $this->supplemento * $this->metriLineari($larghezza, $altezza),
'fisso' => $this->supplemento,
default => 0.0,
};
}
/** Es. "(H x 2 + 200 mm)". */
public function formulaMetri(): string
{
$termini = array_filter([
$this->ml_per_larghezza ? 'L'.($this->ml_per_larghezza != 1 ? ' × '.(float) $this->ml_per_larghezza : '') : null,
$this->ml_per_altezza ? 'H'.($this->ml_per_altezza != 1 ? ' × '.(float) $this->ml_per_altezza : '') : null,
$this->ml_aggiunta_mm ? (float) $this->ml_aggiunta_mm.' mm' : null,
]);
return '('.(implode(' + ', $termini) ?: '0').')';
}
}