- 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.
140 lines
4.7 KiB
PHP
140 lines
4.7 KiB
PHP
<?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').')';
|
||
}
|
||
}
|