feat: Aggiungi funzionalità di eliminazione per clienti e preventivi con gestione delle dipendenze
This commit is contained in:
@@ -97,10 +97,15 @@ class ClienteResource extends Resource
|
||||
->actions([
|
||||
Tables\Actions\ViewAction::make(),
|
||||
Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\DeleteAction::make()
|
||||
->modalDescription('Verrà eliminato definitivamente il cliente insieme a tutti i suoi preventivi e ai file associati (PDF, immagini)')
|
||||
->successRedirectUrl(static::getUrl('index')),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
Tables\Actions\DeleteBulkAction::make()
|
||||
->modalDescription('I clienti selezionati verranno eliminati definitivamente insieme a tutti i loro preventivi e ai file associati (PDF, immagini)')
|
||||
->successRedirectUrl(static::getUrl('index')),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ class EditCliente extends EditRecord
|
||||
{
|
||||
return [
|
||||
Actions\ViewAction::make(),
|
||||
Actions\DeleteAction::make(),
|
||||
Actions\DeleteAction::make()
|
||||
->modalDescription('Verrà eliminato definitivamente il cliente insieme a tutti i suoi preventivi e ai file associati (PDF, immagini).'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ class ViewCliente extends ViewRecord
|
||||
{
|
||||
return [
|
||||
Actions\EditAction::make(),
|
||||
Actions\DeleteAction::make()
|
||||
->modalDescription('Verrà eliminato definitivamente il cliente insieme a tutti i suoi preventivi e ai file associati (PDF, immagini).'),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Filament\Resources;
|
||||
|
||||
use App\Filament\Resources\PreventivoResource\Pages;
|
||||
use App\Filament\Resources\PreventivoResource\RelationManagers\ItemsRelationManager;
|
||||
use App\Models\Cliente;
|
||||
use App\Models\Preventivo;
|
||||
use App\Support\PreventivoPdf;
|
||||
use Filament\Forms;
|
||||
@@ -44,7 +45,13 @@ class PreventivoResource extends Resource
|
||||
Forms\Components\Select::make('cliente_id')
|
||||
->label('Cliente')
|
||||
->relationship('cliente', 'nome')
|
||||
->searchable()
|
||||
->getOptionLabelFromRecordUsing(function (Cliente $record): string {
|
||||
$nome = trim("{$record->nome} {$record->cognome}");
|
||||
$parti = array_filter([$record->ragione_sociale, $nome]);
|
||||
|
||||
return $parti ? implode(' — ', $parti) : (string) $record->username;
|
||||
})
|
||||
->searchable(['ragione_sociale', 'nome', 'cognome'])
|
||||
->preload(),
|
||||
]);
|
||||
}
|
||||
@@ -58,9 +65,14 @@ class PreventivoResource extends Resource
|
||||
->label('N.')
|
||||
->sortable()
|
||||
->placeholder('—'),
|
||||
Tables\Columns\TextColumn::make('cliente.nominativo')
|
||||
Tables\Columns\TextColumn::make('cliente.ragione_sociale')
|
||||
->label('Ragione sociale')
|
||||
->searchable()
|
||||
->toggleable()
|
||||
->placeholder('—'),
|
||||
Tables\Columns\TextColumn::make('cliente.nome_completo')
|
||||
->label('Cliente')
|
||||
->searchable(['nome', 'cognome', 'ragione_sociale'])
|
||||
->searchable(['nome', 'cognome'])
|
||||
->placeholder('—'),
|
||||
Tables\Columns\TextColumn::make('cliente.email')
|
||||
->label('Email')
|
||||
@@ -116,7 +128,8 @@ class PreventivoResource extends Resource
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
Tables\Actions\DeleteBulkAction::make()
|
||||
->successRedirectUrl(static::getUrl('index')),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ use App\Support\ConfigurazioneFormatter;
|
||||
use App\Support\PreventivoPdf;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@@ -122,8 +123,21 @@ class CarrelloController extends Controller
|
||||
'note' => ['nullable', 'string', 'max:2000'],
|
||||
]);
|
||||
|
||||
DB::transaction(function () use ($preventivo, $dati) {
|
||||
$cliente = Cliente::create($dati);
|
||||
// Se la richiesta arriva da un cliente loggato nel configuratore (token Sanctum
|
||||
// valido), il preventivo va agganciato al suo record esistente — aggiornando
|
||||
// l'anagrafica con i dati confermati nel form — e NON a un nuovo cliente.
|
||||
// Il guard Sanctum legge il token Bearer direttamente dalla richiesta:
|
||||
// per i guest (o token assenti/scaduti/non validi) restituisce null.
|
||||
$clienteLoggato = Auth::guard('sanctum')->user();
|
||||
|
||||
DB::transaction(function () use ($preventivo, $dati, $clienteLoggato) {
|
||||
$cliente = $clienteLoggato;
|
||||
|
||||
if ($cliente) {
|
||||
$cliente->update($dati);
|
||||
} else {
|
||||
$cliente = Cliente::create($dati);
|
||||
}
|
||||
|
||||
$preventivo->cliente_id = $cliente->id;
|
||||
$preventivo->stato = 'inviato';
|
||||
|
||||
@@ -31,6 +31,16 @@ class Cliente extends Model
|
||||
return $this->hasMany(Preventivo::class);
|
||||
}
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::deleting(function (Cliente $cliente): void {
|
||||
// Elimina di conseguenza i preventivi del cliente (con i relativi file)
|
||||
// e revoca i token API usati per l'accesso al configuratore.
|
||||
$cliente->preventivi()->get()->each->delete();
|
||||
$cliente->tokens()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
public function getNominativoAttribute(): string
|
||||
{
|
||||
if ($this->ragione_sociale) {
|
||||
@@ -41,4 +51,11 @@ class Cliente extends Model
|
||||
|
||||
return $nome !== '' ? $nome : $this->username;
|
||||
}
|
||||
|
||||
public function getNomeCompletoAttribute(): string
|
||||
{
|
||||
$nome = trim("{$this->nome} {$this->cognome}");
|
||||
|
||||
return $nome !== '' ? $nome : $this->username;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class Preventivo extends Model
|
||||
{
|
||||
@@ -26,6 +27,24 @@ class Preventivo extends Model
|
||||
'chiuso' => 'Chiuso',
|
||||
];
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::deleting(function (Preventivo $preventivo): void {
|
||||
// Elimina immagini degli item (disk 'public') e PDF (disk 'local') prima della cancellazione.
|
||||
foreach ($preventivo->items()->get() as $item) {
|
||||
if ($item->immagine_path && Storage::disk('public')->exists($item->immagine_path)) {
|
||||
Storage::disk('public')->delete($item->immagine_path);
|
||||
}
|
||||
|
||||
$item->delete();
|
||||
}
|
||||
|
||||
if ($preventivo->pdf_path && Storage::disk('local')->exists($preventivo->pdf_path)) {
|
||||
Storage::disk('local')->delete($preventivo->pdf_path);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function cliente(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Cliente::class);
|
||||
|
||||
Reference in New Issue
Block a user