finale 2.0.0
This commit is contained in:
@@ -28,6 +28,25 @@ App gestionale Laravel 13 con AdminLTE 4 per gestione Persone e Gruppi.
|
||||
- Esclude: .git, node_modules, tests, cache, storage content, vendor/docs/tests, Docker
|
||||
- **Istruzioni post-estrazione complete**: mkdir, permessi, configurazione, cache clear
|
||||
|
||||
## Tag System
|
||||
|
||||
### Implementazione Completa (Opzione B)
|
||||
- **Migration**: `2026_06_08_194155_create_tags_tables.php` — tabelle `tags` + `taggables`
|
||||
- **Model `Tag.php`**: morphToMany a 5 entity types, auto-slug su creating, color badge
|
||||
- **Trait `HasTagsLight.php`**: `tags()` morphToMany, scopes `withAllTags`/`withAnyTags`
|
||||
- **5 Models aggiornati**: Individuo, Gruppo, Evento, Documento, MailingList — usano `HasTagsLight`
|
||||
- **ImpostazioniController**: CRUD completo per Tag (store, update, destroy, reorder) con tab nella pagina Impostazioni
|
||||
- **Tag selector**: `_tag-selector.blade.php` — search + pill badges con colori, incluso in create/edit di Individui, Gruppi, Eventi, MailingList
|
||||
- **Tag filtering**: `?tag[]=slug` supportato in `IndividuoController@index`, `GruppoController@index`, `EventoController@index`, `DocumentoController@index`, `MailingListController@index` via `withAnyTags` scope
|
||||
- **Tag column in index views**: Colonna "Tag" con badge colorati cliccabili (collegamento a index filtrato) in individui, gruppi, eventi, documenti, mailing-liste
|
||||
- **Tag filter widget**: `_tag-filter-bar.blade.php` — barra cliccabile con badge colorati sopra ogni index table (individui, gruppi, eventi, documenti, mailing-liste). Attiva/disattiva filtro `?tag[]=` con un click, evidenzia tag attivi, include "Cancella filtri" quando attivo
|
||||
- **RicercaController**: Controller per ricerca unificata per tag — mostra risultati aggregati da tutte 5 entity types con info-box counters
|
||||
- **Route `GET /ricerca`**: Registrata come `ricerca.index` → `RicercaController@index`
|
||||
- **Sidebar link**: "Ricerca per Tag" (icona `fas fa-tags`) sotto la sezione Report, visibile con permesso `individui`
|
||||
- **Mass tag action for Documenti**: `POST /documenti/mass-tag` → `DocumentoController@massTag` — modal with tag selector + assign/remove radio, processes selected documents in chunks of 100 via `syncWithoutDetaching()` (assign) or `detach()` (remove)
|
||||
- **Report tag columns**: `tags.nome` disponibile come colonna per individui/gruppi/eventi/documenti nei report personalizzati
|
||||
- **Report tag filters**: Custom report form include tag multi-select (Select2) + modalità OR/AND; `runCustomReport()` applica filtri via `withAllTags`/`withAnyTags`
|
||||
|
||||
## Bug Fix Recenti
|
||||
|
||||
### 2026-06-07 — Colonne mancanti in eventi e gruppo_individuo
|
||||
@@ -158,5 +177,140 @@ php artisan config:clear
|
||||
1. **`app/Models/AppSetting.php`**: Sostituito `file_exists(public_path('storage/' . $path))` con `Storage::disk('public')->exists($path)` e `asset('storage/' . $path)` con `Storage::disk('public')->url($path)`. Il controllo ora avviene direttamente su `storage/app/public/` (disk root), bypassando il symlink.
|
||||
2. **`app/Http/Controllers/ImpostazioniController.php`**: In `uploadLogo()`, aggiunta creazione automatica del symlink `public/storage → storage/app/public` se mancante, per garantire che il browser possa servire l'immagine.
|
||||
|
||||
## 2026-06-08 — Guardie Schema::hasColumn() aggiunte a 18 migration
|
||||
|
||||
**Problema**: 18 migration files aggiungevano colonne a tabelle esistenti senza `Schema::hasColumn()` guard. Se eseguite su DB dove le colonne già esistevano (es. da install.sql), causavano errore "Duplicate column".
|
||||
|
||||
**Fix**: Aggiunto `if (!Schema::hasColumn(...))` wrapper a ogni colonna aggiunta nelle seguenti migration:
|
||||
1. `2026_06_02_000002_add_uid_esterno_to_eventi_table.php` — `uid_esterno`
|
||||
2. `2026_05_12_000002_change_ruolo_to_multi.php` — `ruolo_ids` (up), `ruolo_id` (down)
|
||||
3. `2026_05_28_000001_add_storage_disk_to_documenti.php` — `storage_disk`
|
||||
4. `2026_05_27_113246_add_repository_id_to_documenti.php` — `repository_id`
|
||||
5. `2026_05_26_000003_add_log_falliti_to_mailing_messaggi.php` — `log_falliti`, `mittente_nome`, `mittente_email`
|
||||
6. `2026_05_27_000002_add_cartella_id_to_documenti.php` — `cartella_id`
|
||||
7. `2026_05_16_000004_add_signature_enabled_to_email_settings.php` — `signature_enabled`
|
||||
8. `2026_05_16_000003_add_signature_to_email_settings.php` — `signature`
|
||||
9. `2024_01_01_000017_add_occorrenza_mese_to_eventi.php` — `occorrenza_mese`
|
||||
10. `2024_01_01_000016_add_eventi_recurrence_fields.php` — `giorno_mese`, `mesi_recorrenza`, `mese_annuale`
|
||||
11. `2026_05_10_000002_add_acl_tables.php` — `permissions` (users)
|
||||
12. `2026_05_12_142009_add_location_to_eventi_table.php` — `luogo_indirizzo`, `luogo_url_maps`
|
||||
13. `2026_05_12_000003_change_responsabile_to_multi.php` — `responsabile_ids` (up), `responsabile_id` (down)
|
||||
14. `2024_01_01_000023_add_is_default_to_viste_report_table.php` — `is_default`
|
||||
15. `2024_01_01_000024_add_user_id_to_mailing_lists_table.php` — `user_id`
|
||||
16. `2026_05_12_000001_create_ruoli_table.php` — `ruolo_id` (gruppo_individuo) + data migration annessa
|
||||
17. `2024_01_01_000021_add_user_id_to_documenti_table.php` — `user_id`
|
||||
18. `2024_01_01_000013_add_numero_documento_to_individui_table.php` — `numero_documento`
|
||||
|
||||
Tutte verificate con `php -l` (nessun errore di sintassi).
|
||||
|
||||
### 2026-06-09 — `@stack('scripts')` mancante nel layout
|
||||
|
||||
**Problema**: Il partial `_tag-selector.blade.php` usa `@push('scripts')` per iniettare le funzioni JS `toggleTag`, `removeTag`, `filterTags`. Il layout `adminlte.blade.php` aveva solo `@yield('scripts')` (per `@section`), ma **non** `@stack('scripts')` (per `@push`). Di conseguenza il JavaScript interattivo del tag selector (clic sui badge, ricerca, rimozione) non veniva mai caricato su nessuna pagina create/edit.
|
||||
|
||||
**Fix**: `resources/views/layouts/adminlte.blade.php:305` — Aggiunto `@stack('scripts')` subito prima di `@yield('scripts')`.
|
||||
|
||||
### 2026-06-09 — Tag support completato per MailingList + Report + Ricerca
|
||||
|
||||
**MailingList — Controller & Views** (`app/Http/Controllers/MailingListController.php`):
|
||||
- `index()`: eager-load `tags`, supporto `?tag[]=` filter via `withAnyTags`, pass `$allTags` per filter bar
|
||||
- `create()`: pass `$tags` per tag selector
|
||||
- `store()`: validazione `tags.* exists:tags,id`, sync dopo create. Auto-fetch email da `Individuo::contatti()` quando email non fornita
|
||||
- `edit()`: eager-load `tags`, pass `$tags` + `$selectedTags`
|
||||
- `update()`: validazione `tags.*`, sync se presente, detach se assente. Auto-fetch email da `Individuo::contatti()` quando email non fornita. Diff logica: `$toRemove = array_diff($existingIds, $newIds)` corretto — rimuove solo contatti deselezionati/esplicitamente rimossi
|
||||
- `show()`: eager-load `tags`
|
||||
|
||||
**MailingList — Views**:
|
||||
- `index.blade.php`: aggiunto `@include('partials._tag-filter-bar')`, colonna "Tag" con badge colorati cliccabili
|
||||
- `create.blade.php`: incluso `_tag-selector` dopo descrizione
|
||||
- `edit.blade.php`: incluso `_tag-selector` dopo descrizione (prima della sezione contatti). Submit handler include `#individui-select.selectedOptions` in `contatti_json` con `email: ''` (già presente da fix precedente)
|
||||
- `show.blade.php`: aggiunta card Tag nel pannello sinistro con badge colorati (o "Nessun tag assegnato")
|
||||
|
||||
**ReportColumnRegistry** (`app/Helpers/ReportColumnRegistry.php`):
|
||||
- Aggiunta colonna `'tags.nome'` con label 'Tag' a 4 entity types: individui, gruppi, eventi, documenti
|
||||
|
||||
**ReportController** (`app/Http/Controllers/ReportController.php`):
|
||||
- `runCustomReport()`: supporta `config['tag_filter']` (array di tag IDs) + `config['tag_filter_mode']` ('any'/'all')
|
||||
- `storeCustom()`: ora salva `tag_filter` e `tag_filter_mode` nella config del report salvato
|
||||
- Carica `$allTags` nell'index e passa alla vista
|
||||
- Converte IDs → slugs via `Tag::whereIn('id', ...)->pluck('slug')`, applica `withAllTags`/`withAnyTags`
|
||||
- Eager-load `tags` automaticamente quando la colonna `tags.nome` è selezionata
|
||||
|
||||
**Report — View** (`resources/views/report/index.blade.php`):
|
||||
- Aggiunto filtro tag multi-select nel form "Crea Report Personalizzato" (Select2 con badge colorati)
|
||||
- Aggiunto select per modalità filtro (OR/AND)
|
||||
- JS: `initTagFilterSelect2()` / `destroyTagFilterSelect2()` con template colorato
|
||||
|
||||
**RicercaController** (`app/Http/Controllers/RicercaController.php`):
|
||||
- Aggiunta MailingList alle query per tag slug
|
||||
- `results['mailingLists']` e `totals['mailingLists']` passati alla view
|
||||
|
||||
**Ricerca — View** (`resources/views/ricerca/index.blade.php`):
|
||||
- Aggiunto info-box Mailing List (colore bg-purple) con link "Vedi tutti" → `mailing-liste.index?tag[]=`
|
||||
- Aggiunta tabella dettaglio Mailing List nel risultato di ricerca (nome, contatti, stato, azione show)
|
||||
- Fix: `route('documenti.edit')` → `url('/documenti/' . $doc->id . '/edit')` (route non esiste)
|
||||
|
||||
### 2026-06-09 — Fix: storeCustom() non salvava tag_filter
|
||||
|
||||
**Problema**: `ReportController@storeCustom()` non salvava `tag_filter` e `tag_filter_mode` nella config del report personalizzato. Quando un report salvato veniva eseguito, `runCustomReport()` non trovava i filtri tag nella config e non li applicava.
|
||||
|
||||
**Fix**: Aggiunte righe 143-148 in `ReportController.php`:
|
||||
```php
|
||||
if ($request->has('tag_filter')) {
|
||||
$config['tag_filter'] = $request->input('tag_filter');
|
||||
}
|
||||
if ($request->filled('tag_filter_mode')) {
|
||||
$config['tag_filter_mode'] = $request->input('tag_filter_mode');
|
||||
}
|
||||
```
|
||||
|
||||
### 2026-06-09 — Fix: MailingList edit — "Carica contatti" non inseriva i selezionati
|
||||
|
||||
**Problema**: Due bug nel JS `caricaSelezionati()` in `mailing-liste/edit.blade.php`:
|
||||
1. **Typo**: `ind.cogname` invece di `ind.cognome` — il campo Cognome nella tabella era sempre vuoto/undefined (API restituisce `cognome`)
|
||||
2. **Email gate**: `if (ind.emails && ind.emails.length > 0)` filtro bloccante — individui senza email salvata in `contatti` venivano SILENZIOSAMENTE scartati, mai aggiunti alla tabella
|
||||
|
||||
**Fix**:
|
||||
1. `ind.cogname` → `ind.cognome` (righe 227 e 256)
|
||||
2. Rimossa condizione `if (ind.emails...)` — ora anche individui senza email vengono aggiunti alla tabella
|
||||
3. `email: ind.emails[0]` → `email: (ind.emails && ind.emails.length > 0) ? ind.emails[0] : ''` — email vuota se nessuna presente
|
||||
4. Controller già fixato per auto-risolvere email da `Individuo::contatti()` al salvataggio
|
||||
|
||||
### 2026-06-09 — Fix: MailingListController email gate bloccava nuovi contatti senza email
|
||||
|
||||
**Problema**: `store()` e `update()` in `MailingListController` usavano `!empty($contatto['email'])` per decidere se creare un contatto. L'email era richiesta ma il MailingContact non memorizza l'email — la risolve dall'Individuo al momento del display/invio. Questo impediva di aggiungere individui senza email (o con email non nei contatti) alla mailing list.
|
||||
|
||||
**Fix**: Rimossa completamente la verifica email sia in `store()` che in `update()`. Ora ogni `individuo_id` valido viene aggiunto come MailingContact. L'email viene risolta al display dal model `$contact->individuo->contatti->where('tipo', 'email')->first()?->valore`.
|
||||
|
||||
Prima (bloccante):
|
||||
```php
|
||||
if (!empty($contatto['individuo_id']) && !empty($contatto['email'])) { create }
|
||||
```
|
||||
Dopo (semplice):
|
||||
```php
|
||||
if (!empty($contatto['individuo_id'])) { create }
|
||||
```
|
||||
|
||||
## Prossimi Passi
|
||||
- *(nessuno — in attesa di nuove richieste)*
|
||||
- [DONE] Aggiungere filtro Tag nella vista Documenti — già presente (tag filter bar + colonna Tag in lista/griglia)
|
||||
- [DONE] Gestire il caso `tag[]` vuoto — già gestito da `$request->filled('tag')` in tutti i 4 controller index
|
||||
- [DONE] MailingList — tag support completato (controller, index/create/edit/show views, filter bar)
|
||||
- [DONE] Report — tag columns in ReportColumnRegistry + tag filter in custom reports + UI multi-select
|
||||
- [DONE] Ricerca per Tag — MailingList integrata nei risultati
|
||||
- [DONE] `storeCustom()` ora salva correttamente `tag_filter` e `tag_filter_mode`
|
||||
- [DONE] `MailingListController@store/update` — auto-fetch email da Individuo quando non fornita
|
||||
- [DONE] Verificata presenza `@stack('scripts')` nel layout — presente a riga 305 (prima di `@yield('scripts')`)
|
||||
- [DONE] Verificata mass tag action Documenti (`DocumentoController@massTag`) — funzionante
|
||||
- [DONE] Verificato: tutti i 5 entity controllers passano `$allTags` alle viste index
|
||||
- [DONE] La logica `$toRemove = array_diff($existingIds, $newIds)` in `update()` è corretta — rimuove solo contatti che l'utente ha esplicitamente deselezionato o rimosso dalla tabella. Non necessita modifiche.
|
||||
- [DONE] SweetAlert2 conferma su salvataggio mailing list (edit.blade.php) quando ci sono contatti senza email
|
||||
- [DONE] Normalizzata `invia()` da `flatMap`+`pluck` a `map`+`first()` (1 email per individuo, come `invioElabora()`)
|
||||
- [DONE] Aggiunto logging contatti saltati in `invia()` e `invioElabora()` (quando senza email)
|
||||
- [DONE] Fix: contattiCaricati initialization ora include codice_id/cognome/nome da righe DOM — contatti esistenti non più blank dopo Carica contatti
|
||||
- [DONE] Fix: EmailController@destroy ora redirect a inbox invece che back() (non rimane su email cancellata)
|
||||
- [DONE] Mass action Individui: Assegna Gruppo (route + controller + modal con select gruppi + Assign/Remove radio)
|
||||
- [DONE] Mass action Individui: Assegna Tag (route + controller + modal con _tag-selector)
|
||||
- [DONE] Mass action Gruppi: Assegna Tag (route + controller + modal con _tag-selector)
|
||||
- [DONE] Mass action Gruppi: Elimina (route + controller + modal con conferma, detach membri + delete)
|
||||
- [DONE] Fix: IndividuoController@massGruppo e @massTag ora convertono stringa ids in array (non funzionavano perché hidden input invia stringa, non array)
|
||||
- [DONE] Ricerca per Tag multipli: controller accetta `?tag[]=slug1&tag[]=slug2`, usa `withAllTags` (AND logic) per 2+ tag. Vista aggiornata: checkbox cliccabili per multi-selezione, info boxes unificate, "Vedi tutti" passa tutti i tag
|
||||
- Verificare end-to-end su remote: tutte le nuove mass action, mailing list con contatti senza email, ricerca multi-tag
|
||||
|
||||
Reference in New Issue
Block a user