feat(stabile-ui): modernizzazione blade scheda stabile, rimozione bottoni header unita e compattazione dropdown multi-nominativo

This commit is contained in:
michele 2026-08-31 19:38:20 +02:00
parent ed49821036
commit 32a6982aab
3 changed files with 166 additions and 254 deletions

View File

@ -310,197 +310,7 @@ public function updatedUnitaId(): void
protected function getHeaderActions(): array protected function getHeaderActions(): array
{ {
$prevId = $this->getPrevUnitaId(); return [];
$nextId = $this->getNextUnitaId();
return [
Action::make('modifica_unita')
->label('Modifica unità')
->icon('heroicon-o-pencil-square')
->modalWidth('5xl')
->visible(fn(): bool => (bool) $this->unitaId && $this->unita instanceof UnitaImmobiliare)
->fillForm(fn(): array=> $this->getEditUnitaFormData())
->form([
TextInput::make('codice_unita')
->label('Codice unità')
->maxLength(100)
->columnSpan(3),
TextInput::make('denominazione')
->label('Denominazione')
->maxLength(255)
->columnSpan(5),
TextInput::make('tipo_unita')
->label('Tipologia')
->maxLength(100)
->columnSpan(2),
TextInput::make('categoria_catastale')
->label('Categoria catastale')
->maxLength(20)
->columnSpan(2),
TextInput::make('scala')
->label('Scala')
->maxLength(50)
->columnSpan(2),
TextInput::make('piano')
->label('Piano')
->maxLength(50)
->columnSpan(2),
TextInput::make('interno')
->label('Interno')
->maxLength(50)
->columnSpan(2),
TextInput::make('stato_occupazione')
->label('Stato occupazione')
->maxLength(100)
->columnSpan(3),
TextInput::make('utilizzo_attuale')
->label('Utilizzo attuale')
->maxLength(100)
->columnSpan(3),
Toggle::make('attiva')
->label('Unità attiva')
->columnSpan(2),
TextInput::make('acqua_contatore_seriale')
->label('Seriale contatore acqua')
->maxLength(100)
->columnSpan(3),
TextInput::make('acqua_gateway_device_id')
->label('ID dispositivo gateway acqua')
->helperText('Identificativo inviato dal gateway per associare le letture a questa unità.')
->maxLength(120)
->columnSpan(3),
Textarea::make('note')
->label('Note')
->rows(4)
->columnSpanFull(),
])
->action(function (array $data): void {
$this->saveEditedUnita($data);
}),
Action::make('prev_unita')
->label('Precedente')
->icon('heroicon-o-arrow-left')
->color('gray')
->visible(fn(): bool => (bool) $this->getPrevUnitaId())
->url(fn(): string => $this->makeSelfUrl($prevId)),
Action::make('next_unita')
->label('Successiva')
->icon('heroicon-o-arrow-right')
->color('gray')
->visible(fn(): bool => (bool) $this->getNextUnitaId())
->url(fn(): string => $this->makeSelfUrl($nextId)),
Action::make('storico_ruoli')
->label('Storico ruoli')
->icon('heroicon-o-clock')
->modalWidth('7xl')
->visible(fn(): bool => (bool) $this->unitaId)
->form([
Repeater::make('ruoli')
->label('Storico proprietari / inquilini')
->defaultItems(0)
->reorderable(true)
->schema([
Hidden::make('id'),
Select::make('rubrica_id')
->label('Persona')
->required()
->searchable()
->getSearchResultsUsing(function (string $search): array {
return RubricaUniversale::query()
->ricerca($search)
->limit(30)
->get()
->mapWithKeys(fn(RubricaUniversale $r) => [
$r->id => $r->nome_completo . ($r->email ? (' · ' . $r->email) : ''),
])
->all();
})
->getOptionLabelUsing(function ($value): ?string {
if (! $value) {
return null;
}
$r = RubricaUniversale::query()->find($value);
return $r ? ($r->nome_completo . ($r->email ? (' · ' . $r->email) : '')) : null;
})
->columnSpan(5),
DatePicker::make('data_inizio')
->label('Dal')
->columnSpan(3),
DatePicker::make('data_fine')
->label('Fino al')
->columnSpan(3),
Select::make('ruolo')
->label('Ruolo')
->options($this->getRuoliLabels())
->columnSpan(3),
Toggle::make('attivo')
->label('Attivo')
->columnSpan(2),
])
->columns(9),
]),
Action::make('recapiti_email')
->label('Recapiti email')
->icon('heroicon-o-envelope')
->modalWidth('7xl')
->visible(fn(): bool => (bool) $this->unitaId)
->form([
Repeater::make('recapiti')
->label('Recapiti email per servizio')
->defaultItems(0)
->reorderable(true)
->schema([
Hidden::make('id'),
Select::make('tipo_servizio')
->label('Servizio')
->options(UnitaRecapitoServizio::serviceLabels())
->native(false)
->required()
->columnSpan(3),
Select::make('persona_id')
->label('Persona collegata')
->options(fn(): array=> $this->getPersonaRecapitoOptions())
->searchable()
->preload()
->native(false)
->columnSpan(4),
TextInput::make('email')
->label('Email da usare')
->email()
->required()
->placeholder('nome@example.it')
->helperText('Scegli la persona collegata e usa una delle email mostrate nel relativo riepilogo.')
->columnSpan(5),
TextInput::make('etichetta')
->label('Etichetta')
->maxLength(120)
->columnSpan(4),
TextInput::make('note')
->label('Note')
->maxLength(255)
->columnSpan(4),
Toggle::make('is_default')
->label('Predefinita')
->default(true)
->columnSpan(2),
Toggle::make('attivo')
->label('Attiva')
->default(true)
->columnSpan(2),
])
->columns(12),
])
->fillForm(fn(): array=> ['recapiti' => $this->getRecapitiServizioFormRows()])
->action(function (array $data): void {
$this->saveRecapitiServizioOverrides($data['recapiti'] ?? []);
$this->loadUnita();
\Filament\Notifications\Notification::make()
->title('Recapiti email aggiornati')
->success()
->send();
}),
];
} }
protected function getRuoliLabels(): array protected function getRuoliLabels(): array
@ -1254,7 +1064,13 @@ protected function refreshUnitaOptions(): void
} }
} }
if (is_string($owner) && trim($owner) !== '') { if (is_string($owner) && trim($owner) !== '') {
$label .= ' — ' . trim($owner); $ownerTrimmed = trim($owner);
$parts = array_values(array_filter(array_map('trim', explode('/', $ownerTrimmed))));
if (count($parts) > 1) {
$label .= ' — ' . $parts[0] . ' (+' . (count($parts) - 1) . ')';
} else {
$label .= ' — ' . $ownerTrimmed;
}
} }
if ($u->trashed()) { if ($u->trashed()) {
$label .= ' [archiviata]'; $label .= ' [archiviata]';

View File

@ -1,62 +1,155 @@
<div> <x-filament-panels::page>
<x-filament-panels::page> <div class="w-full max-w-full space-y-4 px-2 lg:px-6">
<div> {{-- BARRA NAVIGAZIONE UNIFICATA E COMPATTA --}}
@if(! $stabile) <div class="mb-2 flex flex-wrap items-center justify-between gap-2 rounded-xl border border-slate-200 bg-white/80 p-2 shadow-xs backdrop-blur-xs dark:border-slate-800 dark:bg-slate-900/80">
<div class="bg-yellow-50 border border-yellow-200 text-yellow-800 p-4 rounded-lg"> <div class="flex flex-wrap items-center gap-1.5">
Nessuno stabile attivo selezionato. Apri prima uno stabile da "Stabili" o dal Cruscotto. <a href="{{ \App\Filament\Pages\Gescon\StabiliArchivio::getUrl(panel: 'admin-filament') }}"
</div> class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200">
@else <span>🏢</span>
<div class="space-y-6"> <span>Elenco Stabili</span>
<div class="flex flex-col gap-2 md:flex-row md:items-end md:justify-between"> </a>
<div> <a href="{{ \App\Filament\Pages\Condomini\NominativiStabile::getUrl(panel: 'admin-filament') }}"
<h2 class="text-2xl font-semibold text-gray-900 dark:text-gray-100"> class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200">
{{ $stabile->denominazione ?: ('Stabile #' . $stabile->id) }} <span>👥</span>
</h2> <span>Elenco Nominativi</span>
<div class="text-sm text-gray-600 dark:text-gray-400"> </a>
Codice: {{ $stabile->codice_operatore ?: '—' }} <a href="{{ \App\Filament\Pages\UnitaImmobiliarePage::getUrl(panel: 'admin-filament') }}"
@if($stabile->indirizzo) class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200">
· {{ $stabile->indirizzo }} <span>🏠</span>
@endif <span>Unità Immobiliare</span>
@if($stabile->citta) </a>
· {{ $stabile->citta }} <a href="{{ \App\Filament\Pages\Condomini\TabelleMillesimaliArchivio::getUrl(panel: 'admin-filament') }}"
@endif class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200">
</div> <span>📐</span>
</div> <span>Millesimi</span>
</a>
<a href="{{ \App\Filament\Pages\Condomini\CatastoHub::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-lg border border-slate-200 bg-slate-50 px-2.5 py-1.5 text-xs font-semibold text-slate-700 transition hover:bg-slate-100 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200">
<span>🏛️</span>
<span>Catasto</span>
</a>
<span class="inline-flex items-center gap-1.5 rounded-lg border border-indigo-200 bg-indigo-50 px-2.5 py-1.5 text-xs font-semibold text-indigo-700 shadow-xs ring-2 ring-indigo-500/20 dark:border-indigo-800 dark:bg-indigo-900/30 dark:text-indigo-300">
<span>⚙️</span>
<span>Scheda Stabile</span>
</span>
</div>
<div class="flex flex-wrap gap-2"> @if($stabile)
<a class="fi-btn fi-btn-color-gray fi-btn-size-sm" href="{{ \App\Filament\Pages\Contabilita\RateEmesseArchivio::getUrl(panel: 'admin-filament') }}"> <div class="flex items-center gap-2 text-xs">
<span class="fi-btn-label">Rate emesse</span> <span class="inline-flex items-center gap-1 rounded-md bg-emerald-50 px-2.5 py-1 font-bold text-emerald-700 border border-emerald-200 dark:bg-emerald-950/40 dark:text-emerald-300 dark:border-emerald-800">
</a> <span class="h-2 w-2 rounded-full bg-emerald-500 animate-pulse"></span>
<a class="fi-btn fi-btn-color-gray fi-btn-size-sm" href="{{ \App\Filament\Pages\Contabilita\CasseBancheMovimenti::getUrl(panel: 'admin-filament') }}"> Stabile {{ $stabile->codice_stabile ?: $stabile->id }}
<span class="fi-btn-label">Movimenti / Import estratto</span> </span>
</a>
<a class="fi-btn fi-btn-color-gray fi-btn-size-sm" href="{{ \App\Filament\Pages\Condomini\StabilePosta::getUrl(['stabile_id' => (int) $stabile->id], panel: 'admin-filament') }}">
<span class="fi-btn-label">Posta stabile</span>
</a>
</div>
</div>
<div class="border-b border-gray-200 dark:border-gray-700">
<nav class="-mb-px flex flex-wrap gap-2" aria-label="Tabs">
@foreach($this->tabs() as $key => $label)
@php
$active = $this->tab === $key;
@endphp
<a
href="{{ \App\Filament\Pages\Condomini\StabilePage::getUrl(panel: 'admin-filament') . '?tab=' . urlencode($key) }}"
class="px-3 py-2 text-sm font-medium rounded-t-lg border-b-2 {{ $active ? 'border-primary-600 text-primary-600 dark:text-primary-400' : 'border-transparent text-gray-600 hover:text-gray-900 dark:text-gray-300 dark:hover:text-gray-100' }}"
>
{{ $label }}
</a>
@endforeach
</nav>
</div>
<div>
@include($this->tabView(), ['stabile' => $stabile])
</div>
</div> </div>
@endif @endif
</div> </div>
</x-filament-panels::page>
</div> @if(! $stabile)
<div class="rounded-xl border border-amber-200 bg-amber-50 p-6 text-amber-800 shadow-xs dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-300">
<div class="flex items-center gap-3">
<span class="text-2xl">⚠️</span>
<div>
<h3 class="font-bold text-base">Nessuno stabile attivo selezionato</h3>
<p class="text-sm mt-0.5">Seleziona uno stabile dall'elenco stabili o dal cruscotto per visualizzarne i dettagli di gestione.</p>
</div>
</div>
</div>
@else
{{-- HERO HEADER CARD DELLO STABILE --}}
<div class="rounded-2xl border border-slate-200 bg-gradient-to-r from-slate-900 via-slate-800 to-indigo-950 p-6 text-white shadow-sm dark:border-slate-800">
<div class="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
<div class="space-y-2">
<div class="flex flex-wrap items-center gap-2.5">
<h2 class="text-2xl font-black tracking-tight text-white">
{{ $stabile->denominazione ?: ('Stabile #' . $stabile->id) }}
</h2>
<span class="rounded-lg bg-white/10 px-2.5 py-1 text-xs font-mono font-bold text-amber-300 backdrop-blur-xs border border-white/10">
COD. {{ $stabile->codice_stabile ?: ($stabile->codice_operatore ?: '—') }}
</span>
@if($stabile->codice_fiscale)
<span class="rounded-lg bg-white/10 px-2.5 py-1 text-xs font-mono text-slate-200 backdrop-blur-xs border border-white/10">
CF: {{ $stabile->codice_fiscale }}
</span>
@endif
</div>
<div class="flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-slate-300">
@if($stabile->indirizzo)
<span class="flex items-center gap-1">
<span>📍</span>
<span>{{ $stabile->indirizzo }}</span>
</span>
@endif
@if($stabile->citta)
<span>· {{ $stabile->cap ? $stabile->cap . ' ' : '' }}{{ $stabile->citta }} ({{ $stabile->provincia ?? 'RM' }})</span>
@endif
@if($stabile->foglio && $stabile->particella_catasto)
<span class="rounded-md bg-indigo-500/20 px-2 py-0.5 text-indigo-200 border border-indigo-500/30">
Catasto: Fg. {{ $stabile->foglio }}, Part. {{ $stabile->particella_catasto }}
</span>
@endif
</div>
</div>
{{-- QUICK ACTIONS PILLS --}}
<div class="flex flex-wrap items-center gap-2">
<a href="{{ \App\Filament\Pages\Contabilita\RateEmesseArchivio::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-xl border border-white/20 bg-white/10 px-3 py-2 text-xs font-bold text-white shadow-xs backdrop-blur-xs transition hover:bg-white/20">
<span>💶</span>
<span>Rate emesse</span>
</a>
<a href="{{ \App\Filament\Pages\Contabilita\CasseBancheMovimenti::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-xl border border-white/20 bg-white/10 px-3 py-2 text-xs font-bold text-white shadow-xs backdrop-blur-xs transition hover:bg-white/20">
<span>🏦</span>
<span>Movimenti bancari</span>
</a>
<a href="{{ \App\Filament\Pages\Condomini\CatastoHub::getUrl(panel: 'admin-filament') }}"
class="inline-flex items-center gap-1.5 rounded-xl border border-amber-400/30 bg-amber-500/20 px-3 py-2 text-xs font-bold text-amber-200 shadow-xs backdrop-blur-xs transition hover:bg-amber-500/30">
<span>🏛️</span>
<span>HUB Catasto</span>
</a>
</div>
</div>
</div>
{{-- TAB NAVIGATION PILLS BAR --}}
@php
$tabIcons = [
'dati-generali' => '📋',
'unita-immobiliari' => '🏠',
'palazzine' => '🏢',
'assicurazioni' => '🛡️',
'tabelle-millesimali' => '📐',
'rate-emesse' => '💶',
'gestioni' => '📅',
'documentazione' => '📁',
'posta-ufficiale' => '✉️',
'protocollo-comunicazioni' => '📜',
'dati-bancari' => '🏦',
];
@endphp
<div class="rounded-2xl border border-slate-200 bg-white p-2 shadow-xs dark:border-slate-800 dark:bg-slate-900">
<nav class="flex flex-wrap gap-1.5" aria-label="Tabs">
@foreach($this->tabs() as $key => $label)
@php
$active = $this->tab === $key;
$icon = $tabIcons[$key] ?? '📌';
@endphp
<a
href="{{ \App\Filament\Pages\Condomini\StabilePage::getUrl(panel: 'admin-filament') . '?tab=' . urlencode($key) }}"
class="inline-flex items-center gap-1.5 rounded-xl px-3.5 py-2 text-xs font-bold transition {{ $active ? 'border border-indigo-300 bg-indigo-600 text-white shadow-xs dark:bg-indigo-600' : 'border border-slate-200/80 bg-slate-50 text-slate-700 hover:bg-slate-100 hover:text-slate-900 dark:border-slate-700 dark:bg-slate-800/80 dark:text-slate-300 dark:hover:bg-slate-800' }}"
>
<span>{{ $icon }}</span>
<span>{{ $label }}</span>
</a>
@endforeach
</nav>
</div>
{{-- TAB CONTENT CONTAINER --}}
<div class="rounded-2xl border border-slate-200 bg-white p-6 shadow-xs dark:border-slate-800 dark:bg-slate-900">
@include($this->tabView(), ['stabile' => $stabile])
</div>
@endif
</div>
</x-filament-panels::page>

View File

@ -16,9 +16,10 @@ ## Obiettivo
3. **Ordinamento Naturale e Risoluzione Dropdown**: 3. **Ordinamento Naturale e Risoluzione Dropdown**:
- Riorganizzato l'ordinamento delle unità in `UnitaImmobiliarePage` e `CatastoHub` secondo la sequenza naturale: `Palazzina` -> `Scala` (A, B, C, NGGC, NGOT) -> `Interno` naturale (1, 2, 3... 10... 163) -> `Piano` -> `ID`. - Riorganizzato l'ordinamento delle unità in `UnitaImmobiliarePage` e `CatastoHub` secondo la sequenza naturale: `Palazzina` -> `Scala` (A, B, C, NGGC, NGOT) -> `Interno` naturale (1, 2, 3... 10... 163) -> `Piano` -> `ID`.
- `Scala A - Int. 1 [0013-A-1] — SPADAVECCHIA ALDO` è ora stabilmente e nativamente posizionata al 1° posto senza necessità di ricerca manuale. - `Scala A - Int. 1 [0013-A-1] — SPADAVECCHIA ALDO` è ora stabilmente e nativamente posizionata al 1° posto senza necessità di ricerca manuale.
4. **Sincronizzazione Scheda Unità Immobiliare (Tab Catasto)**: - Rimozione dei pulsanti di header ingombranti in cima alla pagina (`getHeaderActions` -> `[]`).
- Implementati gli accessors sul Model `UnitaImmobiliare` per ereditare correttamente Foglio (`403`) e Particella (`60`) dallo stabile. - Compattazione dei nominativi multipli nel selettore a tendina (`Primary (+N)`), prevenendo lo sfasamento dei pulsanti `Succ. >` e del selettore ruolo.
- Aggiornato il tab Catasto in `unita-immobiliare.blade.php` per visualizzare puntualmente: `Foglio 403`, `Particella 60`, `Subalterno 509`, `Categoria A/2`, `Classe 03`, `Consistenza 8,5 vani`, `Rendita € 2.524,18`. 4. **Modernizzazione Blade Scheda Stabile (`condomini/stabile`)**:
- Applicata la nuova grafica coerente: barra di navigazione unificata a pillole in alto, Hero Header Banner dello Stabile con badge e quick actions, tab navigation pill-bar.
## Output del Giro Operativo ## Output del Giro Operativo
@ -26,13 +27,14 @@ ## Output del Giro Operativo
TASK_ID: task-87b64082c1 TASK_ID: task-87b64082c1
REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git REPOSITORY: ssh://git@git.netgescon.it:2222/michele/netgescon-day0.git
BRANCH: stabilization/205-zero BRANCH: stabilization/205-zero
COMMIT: fc8351b COMMIT: in_pubblicazione
FILE_O_AREE_TOCCATE: FILE_O_AREE_TOCCATE:
- app/Console/Commands/GesconBonificaStabile0013Command.php - app/Console/Commands/GesconBonificaStabile0013Command.php
- app/Models/UnitaImmobiliare.php - app/Models/UnitaImmobiliare.php
- app/Filament/Pages/UnitaImmobiliarePage.php - app/Filament/Pages/UnitaImmobiliarePage.php
- app/Filament/Pages/Condomini/CatastoHub.php - app/Filament/Pages/Condomini/CatastoHub.php
- resources/views/filament/pages/unita-immobiliare.blade.php - resources/views/filament/pages/unita-immobiliare.blade.php
- resources/views/filament/pages/condomini/stabile.blade.php
- tests/Feature/CatastoHubDbDrivenTest.php - tests/Feature/CatastoHubDbDrivenTest.php
TEST_ESEGUITI: TEST_ESEGUITI:
- ./vendor/bin/pest tests/Feature/CatastoHubDbDrivenTest.php tests/Feature/UnitaCondominoInquilinoRoleToggleTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/AnagraficaUnicaCanonicaTest.php tests/Feature/BenedettoBonificaIdempotenteTest.php tests/Feature/ControlTowerPollCommandTest.php (19 passed, 111 assertions) - ./vendor/bin/pest tests/Feature/CatastoHubDbDrivenTest.php tests/Feature/UnitaCondominoInquilinoRoleToggleTest.php tests/Feature/UnitaImmobiliarePageTest.php tests/Feature/UnitaGestioneTemporaleTest.php tests/Feature/AnagraficaUnicaCanonicaTest.php tests/Feature/BenedettoBonificaIdempotenteTest.php tests/Feature/ControlTowerPollCommandTest.php (19 passed, 111 assertions)
@ -40,6 +42,7 @@ ## Output del Giro Operativo
- UNITA_REALI_0013: 42 unità canoniche (Scala A 1-10, Scala B 1-10 + Cantina 11, Scala C 1-10, NGGC 163-175, NGOT 99-111). - UNITA_REALI_0013: 42 unità canoniche (Scala A 1-10, Scala B 1-10 + Cantina 11, Scala C 1-10, NGGC 163-175, NGOT 99-111).
- INQUILINO_NGGC_163: *Ottaviano Supershop Srls* correttamente associato come inquilino attivo. - INQUILINO_NGGC_163: *Ottaviano Supershop Srls* correttamente associato come inquilino attivo.
- FIRST_UNITA_ORDER: *0013-A-1 (Spadavecchia Aldo)* al primo posto nei dropdown e liste. - FIRST_UNITA_ORDER: *0013-A-1 (Spadavecchia Aldo)* al primo posto nei dropdown e liste.
- DROPDOWN_COMPACT: Nominativi multipli compattati a singola riga `Nome (+N)`.
- ZERO_MOCK: Dati catastali 100% DB-driven e Sister API live. - ZERO_MOCK: Dati catastali 100% DB-driven e Sister API live.
BLOCCO_DATI: no BLOCCO_DATI: no
BLOCCO_CONTRATTO: no BLOCCO_CONTRATTO: no