finale 2.0.0
This commit is contained in:
@@ -11,6 +11,7 @@ use App\Models\Individuo;
|
||||
use App\Models\Gruppo;
|
||||
use App\Models\Evento;
|
||||
use App\Models\StorageRepository;
|
||||
use App\Models\Tag;
|
||||
use App\Models\TipologiaDocumento;
|
||||
use App\Services\StorageRepositoryService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -42,9 +43,14 @@ class DocumentoController extends Controller
|
||||
$folderId = $request->get('folder_id');
|
||||
$repoId = $request->get('repository_id');
|
||||
|
||||
$query = Documento::with(['user', 'target', 'cartella', 'repository'])
|
||||
$query = Documento::with(['user', 'target', 'cartella', 'repository', 'tags'])
|
||||
->orderByDesc('created_at');
|
||||
|
||||
if ($request->filled('tag')) {
|
||||
$tagSlugs = (array) $request->input('tag');
|
||||
$query->withAnyTags($tagSlugs);
|
||||
}
|
||||
|
||||
if ($repoId) {
|
||||
$query->where('repository_id', $repoId);
|
||||
} elseif ($folderId) {
|
||||
@@ -54,6 +60,7 @@ class DocumentoController extends Controller
|
||||
}
|
||||
|
||||
$documenti = $query->paginate(20);
|
||||
$allTags = Tag::orderBy('name')->get();
|
||||
$cartelle = DocumentoCartella::with('children')
|
||||
->whereNull('parent_id')
|
||||
->orderBy('nome')
|
||||
@@ -89,7 +96,7 @@ class DocumentoController extends Controller
|
||||
'documenti', 'cartelle', 'currentFolder', 'breadcrumb', 'sottoCartelle',
|
||||
'currentRepo', 'repositories',
|
||||
'individui', 'gruppi', 'eventi', 'mailingLists', 'tipologie',
|
||||
'cartelleMoveOptions'
|
||||
'cartelleMoveOptions', 'allTags'
|
||||
));
|
||||
}
|
||||
|
||||
@@ -106,13 +113,15 @@ class DocumentoController extends Controller
|
||||
public function edit($documento)
|
||||
{
|
||||
$this->authorizeWrite('documenti');
|
||||
$documento = Documento::with('target')->findOrFail($documento);
|
||||
$documento = Documento::with(['target', 'tags'])->findOrFail($documento);
|
||||
$individui = Individuo::orderBy('cognome')->orderBy('nome')->get();
|
||||
$gruppi = Gruppo::orderBy('nome')->get();
|
||||
$eventi = Evento::orderBy('nome_evento')->get();
|
||||
$mailingLists = \App\Models\MailingList::orderBy('nome')->get();
|
||||
$tipologie = TipologiaDocumento::attive();
|
||||
return view('documenti.edit', compact('documento', 'individui', 'gruppi', 'eventi', 'mailingLists', 'tipologie'));
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
$selectedTags = $documento->tags->pluck('id')->toArray();
|
||||
return view('documenti.edit', compact('documento', 'individui', 'gruppi', 'eventi', 'mailingLists', 'tipologie', 'tags', 'selectedTags'));
|
||||
}
|
||||
|
||||
public function options(Request $request)
|
||||
@@ -165,6 +174,8 @@ class DocumentoController extends Controller
|
||||
'visibilita_target_id' => 'nullable|integer',
|
||||
'visibilita_target_type' => 'nullable|string',
|
||||
'note' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$data['visibilita'] = $request->contesto_tipo ?: 'pubblico';
|
||||
@@ -185,6 +196,12 @@ class DocumentoController extends Controller
|
||||
|
||||
$documento->update($data);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$documento->tags()->sync($request->tags);
|
||||
} else {
|
||||
$documento->tags()->detach();
|
||||
}
|
||||
|
||||
return redirect('/documenti')->with('success', 'Documento aggiornato.');
|
||||
}
|
||||
|
||||
@@ -706,6 +723,41 @@ class DocumentoController extends Controller
|
||||
return back()->with('success', count($ids) . ' documenti associati.');
|
||||
}
|
||||
|
||||
public function massTag(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('documenti');
|
||||
$idsInput = $request->input('ids', '');
|
||||
$ids = is_array($idsInput) ? $idsInput : (is_string($idsInput) ? explode(',', $idsInput) : []);
|
||||
|
||||
if (empty($ids)) {
|
||||
return back()->with('error', 'Nessun documento selezionato.');
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'tags' => 'required|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
'mode' => 'required|in:assign,remove',
|
||||
]);
|
||||
|
||||
$tagIds = $data['tags'];
|
||||
$mode = $data['mode'];
|
||||
$count = 0;
|
||||
|
||||
Documento::whereIn('id', $ids)->chunk(100, function ($documenti) use ($tagIds, $mode, &$count) {
|
||||
foreach ($documenti as $documento) {
|
||||
if ($mode === 'assign') {
|
||||
$documento->tags()->syncWithoutDetaching($tagIds);
|
||||
} else {
|
||||
$documento->tags()->detach($tagIds);
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
});
|
||||
|
||||
$actionLabel = $mode === 'assign' ? 'assegnati' : 'rimossi';
|
||||
return back()->with('success', "Tag $actionLabel per $count documenti.");
|
||||
}
|
||||
|
||||
public function massMove(Request $request): RedirectResponse
|
||||
{
|
||||
$this->authorizeWrite('documenti');
|
||||
|
||||
@@ -341,7 +341,7 @@ class EmailController extends Controller
|
||||
$message->delete();
|
||||
}
|
||||
|
||||
return back()->with('success', 'Email spostata nel cestino.');
|
||||
return redirect()->route('email.index', ['folder' => 'inbox'])->with('success', 'Email spostata nel cestino.');
|
||||
}
|
||||
|
||||
public function downloadAttachment($id)
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
|
||||
use App\Models\Evento;
|
||||
use App\Models\Gruppo;
|
||||
use App\Models\Individuo;
|
||||
use App\Models\Tag;
|
||||
use App\Models\TipologiaEvento;
|
||||
use App\Services\IcsExportService;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -16,7 +17,12 @@ class EventoController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorizeRead('eventi');
|
||||
$query = Evento::with(['gruppi', 'responsabili']);
|
||||
$query = Evento::with(['gruppi', 'responsabili', 'tags']);
|
||||
|
||||
if ($request->filled('tag')) {
|
||||
$tagSlugs = (array) $request->input('tag');
|
||||
$query->withAnyTags($tagSlugs);
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$query->where('nome_evento', 'like', '%' . $request->search . '%');
|
||||
@@ -47,8 +53,9 @@ class EventoController extends Controller
|
||||
$perPage = in_array((int) $request->perPage, [10, 20, 25, 50, 100]) ? (int) $request->perPage : 20;
|
||||
$eventi = $query->paginate($perPage);
|
||||
$gruppi = Gruppo::orderBy('nome')->get();
|
||||
$allTags = Tag::orderBy('name')->get();
|
||||
|
||||
return view('eventi.index', compact('eventi', 'gruppi'));
|
||||
return view('eventi.index', compact('eventi', 'gruppi', 'allTags'));
|
||||
}
|
||||
|
||||
public function create(Request $request)
|
||||
@@ -58,8 +65,9 @@ class EventoController extends Controller
|
||||
$individui = Individuo::orderBy('cognome')->orderBy('nome')->get();
|
||||
$selectedGruppo = $request->query('gruppo_id') ? Gruppo::find($request->query('gruppo_id')) : null;
|
||||
$tipologieEventi = TipologiaEvento::attive();
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
|
||||
return view('eventi.create', compact('gruppi', 'individui', 'selectedGruppo', 'tipologieEventi'));
|
||||
return view('eventi.create', compact('gruppi', 'individui', 'selectedGruppo', 'tipologieEventi', 'tags'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
@@ -88,6 +96,8 @@ class EventoController extends Controller
|
||||
'responsabili.*' => 'exists:individui,id',
|
||||
'luogo_indirizzo' => 'nullable|string|max:500',
|
||||
'luogo_url_maps' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$evento = Evento::create([
|
||||
@@ -110,6 +120,10 @@ class EventoController extends Controller
|
||||
'luogo_url_maps' => $data['luogo_url_maps'] ?? null,
|
||||
]);
|
||||
|
||||
if (!empty($data['tags'])) {
|
||||
$evento->tags()->attach($data['tags']);
|
||||
}
|
||||
|
||||
if (!empty($data['gruppi'])) {
|
||||
$evento->gruppi()->attach($data['gruppi']);
|
||||
}
|
||||
@@ -124,19 +138,21 @@ class EventoController extends Controller
|
||||
public function show($evento)
|
||||
{
|
||||
$this->authorizeRead('eventi');
|
||||
$evento = Evento::with(['gruppi', 'responsabili.contatti', 'documenti'])->findOrFail($evento);
|
||||
$evento = Evento::with(['gruppi', 'responsabili.contatti', 'documenti', 'tags'])->findOrFail($evento);
|
||||
return view('eventi.show', compact('evento'));
|
||||
}
|
||||
|
||||
public function edit($evento)
|
||||
{
|
||||
$this->authorizeWrite('eventi');
|
||||
$evento = Evento::with(['gruppi', 'responsabili', 'documenti'])->findOrFail($evento);
|
||||
$evento = Evento::with(['gruppi', 'responsabili', 'documenti', 'tags'])->findOrFail($evento);
|
||||
$gruppi = Gruppo::orderBy('nome')->get();
|
||||
$individui = Individuo::orderBy('cognome')->orderBy('nome')->get();
|
||||
$tipologieEventi = TipologiaEvento::attive();
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
$selectedTags = $evento->tags->pluck('id')->toArray();
|
||||
|
||||
return view('eventi.edit', compact('evento', 'gruppi', 'individui', 'tipologieEventi'));
|
||||
return view('eventi.edit', compact('evento', 'gruppi', 'individui', 'tipologieEventi', 'tags', 'selectedTags'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $evento)
|
||||
@@ -167,6 +183,8 @@ class EventoController extends Controller
|
||||
'responsabili.*' => 'exists:individui,id',
|
||||
'luogo_indirizzo' => 'nullable|string|max:500',
|
||||
'luogo_url_maps' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$evento->update([
|
||||
@@ -189,6 +207,7 @@ class EventoController extends Controller
|
||||
'luogo_url_maps' => $data['luogo_url_maps'] ?? null,
|
||||
]);
|
||||
|
||||
$evento->tags()->sync($data['tags'] ?? []);
|
||||
$evento->gruppi()->sync($data['gruppi'] ?? []);
|
||||
$evento->responsabili()->sync($data['responsabili'] ?? []);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace App\Http\Controllers;
|
||||
use App\Models\Gruppo;
|
||||
use App\Models\Individuo;
|
||||
use App\Models\Diocesi;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Pagination\Paginator;
|
||||
@@ -27,8 +28,8 @@ class GruppoController extends Controller
|
||||
->where('is_default', true)
|
||||
->first();
|
||||
|
||||
$allColumns = ['nome', 'descrizione', 'diocesi', 'livello', 'padre', 'membri', 'responsabili', 'indirizzo', 'citta', 'telefono', 'email'];
|
||||
$defaultVisible = ['nome', 'livello', 'padre', 'membri', 'responsabili'];
|
||||
$allColumns = ['nome', 'descrizione', 'diocesi', 'livello', 'padre', 'membri', 'responsabili', 'indirizzo', 'citta', 'telefono', 'email', 'tag'];
|
||||
$defaultVisible = ['nome', 'livello', 'padre', 'membri', 'responsabili', 'tag'];
|
||||
|
||||
if ($vista && !empty($vista->colonne_visibili)) {
|
||||
$visibleColumns = $vista->colonne_visibili;
|
||||
@@ -36,9 +37,14 @@ class GruppoController extends Controller
|
||||
$visibleColumns = $defaultVisible;
|
||||
}
|
||||
|
||||
$allGruppi = Gruppo::with(['diocesi', 'parent', 'children', 'individui', 'avatar'])
|
||||
->orderBy('nome')
|
||||
->get()
|
||||
$gruppiQuery = Gruppo::with(['diocesi', 'parent', 'children', 'individui', 'avatar', 'tags']);
|
||||
|
||||
if (request()->filled('tag')) {
|
||||
$tagSlugs = (array) request()->input('tag');
|
||||
$gruppiQuery->withAnyTags($tagSlugs);
|
||||
}
|
||||
|
||||
$allGruppi = $gruppiQuery->orderBy('nome')->get()
|
||||
->map(function ($gruppo) {
|
||||
$depth = 0;
|
||||
$parent = $gruppo->parent;
|
||||
@@ -65,12 +71,15 @@ class GruppoController extends Controller
|
||||
$gruppi = $allGruppi;
|
||||
}
|
||||
|
||||
$allTags = Tag::orderBy('name')->get();
|
||||
|
||||
return view('gruppi.index', compact(
|
||||
'gruppi',
|
||||
'allColumns',
|
||||
'visibleColumns',
|
||||
'viewMode',
|
||||
'vista'
|
||||
'vista',
|
||||
'allTags'
|
||||
));
|
||||
}
|
||||
|
||||
@@ -104,7 +113,8 @@ class GruppoController extends Controller
|
||||
$allGruppi = Gruppo::orderBy('nome')->get();
|
||||
$selectedParent = $request->query('parent_id') ? Gruppo::find($request->query('parent_id')) : null;
|
||||
$individui = Individuo::orderBy('cognome')->orderBy('nome')->get();
|
||||
return view('gruppi.create', compact('diocesi', 'allGruppi', 'selectedParent', 'individui'));
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
return view('gruppi.create', compact('diocesi', 'allGruppi', 'selectedParent', 'individui', 'tags'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
@@ -122,6 +132,8 @@ class GruppoController extends Controller
|
||||
'città_incontro' => 'nullable|string|max:255',
|
||||
'sigla_provincia_incontro' => 'nullable|string|max:2',
|
||||
'mappa_posizione' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
if (!empty($data['responsabile_ids'])) {
|
||||
@@ -130,6 +142,10 @@ class GruppoController extends Controller
|
||||
|
||||
$gruppo = Gruppo::create($data);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$gruppo->tags()->sync($request->tags);
|
||||
}
|
||||
|
||||
if ($request->has('individui')) {
|
||||
foreach ($request->individui as $individuoData) {
|
||||
if (!empty($individuoData['individuo_id'])) {
|
||||
@@ -149,7 +165,7 @@ class GruppoController extends Controller
|
||||
$this->authorizeRead('gruppi');
|
||||
$gruppo = Gruppo::with(['parent', 'children', 'diocesi', 'individui.contatti', 'individui.documenti', 'individui' => function ($q) {
|
||||
$q->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione');
|
||||
}, 'avatar', 'eventi' => function ($q) {
|
||||
}, 'avatar', 'tags', 'eventi' => function ($q) {
|
||||
$q->where('is_incontro_gruppo', true);
|
||||
}, 'eventi.responsabili.contatti'])->findOrFail($id);
|
||||
return view('gruppi.show', compact('gruppo'));
|
||||
@@ -158,11 +174,13 @@ class GruppoController extends Controller
|
||||
public function edit($id)
|
||||
{
|
||||
$this->authorizeWrite('gruppi');
|
||||
$gruppo = Gruppo::with(['individui.contatti', 'individui.documenti', 'avatar'])->findOrFail($id);
|
||||
$gruppo = Gruppo::with(['individui.contatti', 'individui.documenti', 'avatar', 'tags'])->findOrFail($id);
|
||||
$diocesi = Diocesi::orderBy('nome')->get();
|
||||
$gruppi = Gruppo::where('id', '!=', $gruppo->id)->orderBy('nome')->get();
|
||||
$membri = $gruppo->individui()->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione')->orderBy('cognome')->orderBy('nome')->get();
|
||||
return view('gruppi.edit', compact('gruppo', 'diocesi', 'gruppi', 'membri'));
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
$selectedTags = $gruppo->tags->pluck('id')->toArray();
|
||||
return view('gruppi.edit', compact('gruppo', 'diocesi', 'gruppi', 'membri', 'tags', 'selectedTags'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
@@ -181,6 +199,8 @@ class GruppoController extends Controller
|
||||
'città_incontro' => 'nullable|string|max:255',
|
||||
'sigla_provincia_incontro' => 'nullable|string|max:2',
|
||||
'mappa_posizione' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
if (!empty($data['responsabile_ids'])) {
|
||||
@@ -191,6 +211,12 @@ class GruppoController extends Controller
|
||||
|
||||
$gruppo->update($data);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$gruppo->tags()->sync($request->tags);
|
||||
} else {
|
||||
$gruppo->tags()->detach();
|
||||
}
|
||||
|
||||
if ($request->has('individui')) {
|
||||
$gruppo->individui()->detach();
|
||||
foreach ($request->individui as $individuoData) {
|
||||
@@ -410,4 +436,59 @@ class GruppoController extends Controller
|
||||
'Content-Disposition' => 'attachment; filename="template_gruppi.csv"',
|
||||
]);
|
||||
}
|
||||
|
||||
public function massTag(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('gruppi');
|
||||
$idsInput = $request->input('ids', '');
|
||||
$ids = is_array($idsInput) ? $idsInput : (is_string($idsInput) ? explode(',', $idsInput) : []);
|
||||
|
||||
if (empty($ids)) {
|
||||
return redirect()->route('gruppi.index')->with('error', 'Nessun gruppo selezionato.');
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'tags' => 'required|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
'mode' => 'required|in:assign,remove',
|
||||
]);
|
||||
|
||||
$tagIds = $data['tags'];
|
||||
$mode = $data['mode'];
|
||||
$count = 0;
|
||||
|
||||
Gruppo::whereIn('id', $ids)->chunk(100, function ($gruppi) use ($tagIds, $mode, &$count) {
|
||||
foreach ($gruppi as $gruppo) {
|
||||
if ($mode === 'assign') {
|
||||
$gruppo->tags()->syncWithoutDetaching($tagIds);
|
||||
} else {
|
||||
$gruppo->tags()->detach($tagIds);
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
});
|
||||
|
||||
$actionLabel = $mode === 'assign' ? 'assegnati' : 'rimossi';
|
||||
return redirect()->route('gruppi.index')->with('success', "Tag {$actionLabel} per {$count} gruppi.");
|
||||
}
|
||||
|
||||
public function massElimina(Request $request)
|
||||
{
|
||||
$this->authorizeDelete('gruppi');
|
||||
$ids = $request->input('ids', []);
|
||||
if (!is_array($ids) || empty($ids)) {
|
||||
return redirect()->route('gruppi.index')->with('error', 'Nessun gruppo selezionato.');
|
||||
}
|
||||
|
||||
$gruppi = Gruppo::whereIn('id', $ids)->get();
|
||||
$count = 0;
|
||||
|
||||
foreach ($gruppi as $gruppo) {
|
||||
$gruppo->individui()->detach();
|
||||
$gruppo->delete();
|
||||
$count++;
|
||||
}
|
||||
|
||||
return redirect()->route('gruppi.index')->with('success', "{$count} gruppi eliminati con successo.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\EmailSetting;
|
||||
use App\Models\Ruolo;
|
||||
use App\Models\SenderAccount;
|
||||
use App\Models\StorageRepository;
|
||||
use App\Models\Tag;
|
||||
use App\Models\TipologiaDocumento;
|
||||
use App\Models\TipologiaEvento;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@@ -26,6 +27,7 @@ class ImpostazioniController extends Controller
|
||||
$tipologie = TipologiaDocumento::orderBy('ordine')->get();
|
||||
$tipologieEventi = TipologiaEvento::orderBy('ordine')->get();
|
||||
$ruoli = Ruolo::orderBy('ordine')->get();
|
||||
$tags = Tag::orderBy('order_column')->get();
|
||||
$appSettings = AppSetting::first();
|
||||
$emailSettings = EmailSetting::first() ?? new EmailSetting();
|
||||
$senderAccounts = SenderAccount::orderBy('email_address')->get();
|
||||
@@ -33,7 +35,7 @@ class ImpostazioniController extends Controller
|
||||
$googleDriveNewToken = session('google_drive_new_token');
|
||||
$calendarioConnessioni = CalendarioConnessione::orderBy('ordine')->get();
|
||||
|
||||
return view('impostazioni.index', compact('tipologie', 'tipologieEventi', 'ruoli', 'appSettings', 'emailSettings', 'senderAccounts', 'repositories', 'googleDriveNewToken', 'calendarioConnessioni'));
|
||||
return view('impostazioni.index', compact('tipologie', 'tipologieEventi', 'ruoli', 'tags', 'appSettings', 'emailSettings', 'senderAccounts', 'repositories', 'googleDriveNewToken', 'calendarioConnessioni'));
|
||||
}
|
||||
|
||||
public function saveAppSettings(Request $request)
|
||||
@@ -371,6 +373,70 @@ class ImpostazioniController extends Controller
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
public function tagStore(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('settings');
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:100|unique:tags,name',
|
||||
'color' => 'nullable|string|max:7',
|
||||
]);
|
||||
|
||||
$maxOrdine = Tag::max('order_column') ?? 0;
|
||||
|
||||
Tag::create([
|
||||
'name' => $validated['name'],
|
||||
'slug' => str()->slug($validated['name']),
|
||||
'color' => $validated['color'] ?? null,
|
||||
'order_column' => $maxOrdine + 1,
|
||||
]);
|
||||
|
||||
return redirect('/impostazioni#tag')->with('success', 'Tag aggiunto.');
|
||||
}
|
||||
|
||||
public function tagUpdate(Request $request, $id)
|
||||
{
|
||||
$this->authorizeWrite('settings');
|
||||
|
||||
$tag = Tag::findOrFail($id);
|
||||
|
||||
$validated = $request->validate([
|
||||
'name' => 'required|string|max:100|unique:tags,name,' . $id,
|
||||
'color' => 'nullable|string|max:7',
|
||||
]);
|
||||
|
||||
$tag->update([
|
||||
'name' => $validated['name'],
|
||||
'slug' => str()->slug($validated['name']),
|
||||
'color' => $validated['color'] ?? null,
|
||||
]);
|
||||
|
||||
return redirect('/impostazioni#tag')->with('success', 'Tag aggiornato.');
|
||||
}
|
||||
|
||||
public function tagDestroy($id)
|
||||
{
|
||||
$this->authorizeDelete('settings');
|
||||
|
||||
$tag = Tag::findOrFail($id);
|
||||
$tag->delete();
|
||||
|
||||
return redirect('/impostazioni#tag')->with('success', 'Tag eliminato.');
|
||||
}
|
||||
|
||||
public function tagReorder(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('settings');
|
||||
|
||||
$order = $request->input('order', []);
|
||||
|
||||
foreach ($order as $index => $id) {
|
||||
Tag::where('id', $id)->update(['order_column' => $index]);
|
||||
}
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
public function uploadLogo(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('settings');
|
||||
|
||||
@@ -5,8 +5,10 @@ namespace App\Http\Controllers;
|
||||
use App\Models\Individuo;
|
||||
use App\Models\Contatto;
|
||||
use App\Models\Documento;
|
||||
use App\Models\Gruppo;
|
||||
use App\Models\Comune;
|
||||
use App\Models\Diocesi;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Validation\Rule;
|
||||
@@ -18,7 +20,16 @@ class IndividuoController extends Controller
|
||||
{
|
||||
$this->authorizeRead('individui');
|
||||
$perPage = in_array((int) $request->perPage, [10, 20, 25, 50, 100]) ? (int) $request->perPage : 20;
|
||||
$individui = Individuo::with('contatti')->orderBy('cognome')->orderBy('nome')->paginate($perPage);
|
||||
|
||||
$query = Individuo::with('contatti', 'tags');
|
||||
|
||||
if ($request->filled('tag')) {
|
||||
$tagSlugs = (array) $request->input('tag');
|
||||
$query->withAnyTags($tagSlugs);
|
||||
}
|
||||
|
||||
$individui = $query->orderBy('cognome')->orderBy('nome')->paginate($perPage);
|
||||
$allTags = Tag::orderBy('name')->get();
|
||||
|
||||
$vista = null;
|
||||
|
||||
@@ -41,14 +52,16 @@ class IndividuoController extends Controller
|
||||
['key' => 'nome', 'label' => 'Nome'],
|
||||
['key' => 'email', 'label' => 'Email'],
|
||||
['key' => 'telefono', 'label' => 'Telefono'],
|
||||
['key' => 'tag', 'label' => 'Tag'],
|
||||
];
|
||||
|
||||
$defaultVisible = ['codice', 'cognome', 'nome', 'email', 'telefono'];
|
||||
$defaultVisible = ['codice', 'cognome', 'nome', 'email', 'telefono', 'tag'];
|
||||
$visibleColumns = $vista && !empty($vista->colonne_visibili)
|
||||
? $vista->colonne_visibili
|
||||
: $defaultVisible;
|
||||
|
||||
return view('individui.index', compact('individui', 'vista', 'allColumns', 'visibleColumns'));
|
||||
$gruppi = Gruppo::orderBy('nome')->get(['id', 'nome']);
|
||||
return view('individui.index', compact('individui', 'vista', 'allColumns', 'visibleColumns', 'allTags', 'gruppi'));
|
||||
}
|
||||
|
||||
public function exportCSV(Request $request)
|
||||
@@ -110,7 +123,8 @@ public function create()
|
||||
$this->authorizeWrite('individui');
|
||||
$comuni = Comune::orderBy('nome')->get();
|
||||
$diocesi = Diocesi::orderBy('nome')->get();
|
||||
return view('individui.create', compact('comuni', 'diocesi'));
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
return view('individui.create', compact('comuni', 'diocesi', 'tags'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
@@ -129,10 +143,16 @@ public function create()
|
||||
'numero_documento' => 'nullable|string|max:50',
|
||||
'scadenza_documento' => 'nullable|date',
|
||||
'note' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$individuo = Individuo::create($data);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$individuo->tags()->sync($request->tags);
|
||||
}
|
||||
|
||||
if ($request->has('contatti')) {
|
||||
foreach ($request->contatti as $contatto) {
|
||||
if (!empty($contatto['tipo']) && !empty($contatto['valore'])) {
|
||||
@@ -154,7 +174,7 @@ public function create()
|
||||
$this->authorizeRead('individui');
|
||||
$individuo = Individuo::with(['contatti', 'gruppi' => function ($q) {
|
||||
$q->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione');
|
||||
}, 'avatar'])->findOrFail($individuo);
|
||||
}, 'avatar', 'tags'])->findOrFail($individuo);
|
||||
return view('individui.show', compact('individuo'));
|
||||
}
|
||||
|
||||
@@ -180,8 +200,10 @@ public function create()
|
||||
public function edit($individuo)
|
||||
{
|
||||
$this->authorizeWrite('individui');
|
||||
$individuo = Individuo::with(['contatti', 'gruppi', 'avatar'])->findOrFail($individuo);
|
||||
return view('individui.edit', compact('individuo'));
|
||||
$individuo = Individuo::with(['contatti', 'gruppi', 'avatar', 'tags'])->findOrFail($individuo);
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
$selectedTags = $individuo->tags->pluck('id')->toArray();
|
||||
return view('individui.edit', compact('individuo', 'tags', 'selectedTags'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $individuo)
|
||||
@@ -205,9 +227,17 @@ public function create()
|
||||
'numero_documento' => 'nullable|string|max:50',
|
||||
'scadenza_documento' => 'nullable|date',
|
||||
'note' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$individuo->update($data);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$individuo->tags()->sync($request->tags);
|
||||
} else {
|
||||
$individuo->tags()->detach();
|
||||
}
|
||||
|
||||
\Log::info('Individuo dati salvati', ['id' => $individuo->id]);
|
||||
|
||||
@@ -308,6 +338,75 @@ public function create()
|
||||
return redirect()->route('individui.index')->with('success', count($individui) . ' individui eliminati con successo.');
|
||||
}
|
||||
|
||||
public function massGruppo(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('individui');
|
||||
$idsInput = $request->input('ids', '');
|
||||
$ids = is_array($idsInput) ? $idsInput : (is_string($idsInput) ? explode(',', $idsInput) : []);
|
||||
if (empty($ids)) {
|
||||
return redirect()->route('individui.index')->with('error', 'Nessun individuo selezionato.');
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'gruppi' => 'required|array',
|
||||
'gruppi.*' => 'exists:gruppi,id',
|
||||
'mode' => 'required|in:assign,remove',
|
||||
]);
|
||||
|
||||
$gruppiIds = $data['gruppi'];
|
||||
$mode = $data['mode'];
|
||||
$count = 0;
|
||||
|
||||
foreach ($ids as $id) {
|
||||
$individuo = Individuo::find($id);
|
||||
if (!$individuo) continue;
|
||||
|
||||
if ($mode === 'assign') {
|
||||
$individuo->gruppi()->syncWithoutDetaching($gruppiIds);
|
||||
} else {
|
||||
$individuo->gruppi()->detach($gruppiIds);
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
|
||||
$actionLabel = $mode === 'assign' ? 'assegnati' : 'rimossi';
|
||||
return redirect()->route('individui.index')->with('success', "Gruppi {$actionLabel} per {$count} individui.");
|
||||
}
|
||||
|
||||
public function massTag(Request $request)
|
||||
{
|
||||
$this->authorizeWrite('individui');
|
||||
$idsInput = $request->input('ids', '');
|
||||
$ids = is_array($idsInput) ? $idsInput : (is_string($idsInput) ? explode(',', $idsInput) : []);
|
||||
if (empty($ids)) {
|
||||
return redirect()->route('individui.index')->with('error', 'Nessun individuo selezionato.');
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'tags' => 'required|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
'mode' => 'required|in:assign,remove',
|
||||
]);
|
||||
|
||||
$tagIds = $data['tags'];
|
||||
$mode = $data['mode'];
|
||||
$count = 0;
|
||||
|
||||
Individuo::whereIn('id', $ids)->chunk(100, function ($individui) use ($tagIds, $mode, &$count) {
|
||||
foreach ($individui as $individuo) {
|
||||
if ($mode === 'assign') {
|
||||
$individuo->tags()->syncWithoutDetaching($tagIds);
|
||||
} else {
|
||||
$individuo->tags()->detach($tagIds);
|
||||
}
|
||||
$count++;
|
||||
}
|
||||
});
|
||||
|
||||
$actionLabel = $mode === 'assign' ? 'assegnati' : 'rimossi';
|
||||
return redirect()->route('individui.index')->with('success', "Tag {$actionLabel} per {$count} individui.");
|
||||
}
|
||||
|
||||
public function elementiCollegati($individuo)
|
||||
{
|
||||
$individuo = Individuo::findOrFail($individuo);
|
||||
|
||||
@@ -95,9 +95,17 @@ class MailingController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$emails = $destinatari->flatMap(fn($ind) => $ind->contatti->where('tipo', 'email')->pluck('valore'))
|
||||
$totaleDestinatari = $destinatari->count();
|
||||
$emails = $destinatari->map(fn($ind) => $ind->contatti->where('tipo', 'email')->first()?->valore)
|
||||
->filter()->unique()->values();
|
||||
|
||||
$skipped = $totaleDestinatari - $emails->count();
|
||||
if ($skipped > 0) {
|
||||
Log::info("Mailing invia: {$skipped} contatti saltati perché senza email", [
|
||||
'lista_id' => $data['lista_id'] ?? null,
|
||||
]);
|
||||
}
|
||||
|
||||
if ($emails->isEmpty()) {
|
||||
return back()->with('error', 'Nessun destinatario email valido trovato.')->withInput();
|
||||
}
|
||||
@@ -229,9 +237,17 @@ class MailingController extends Controller
|
||||
->with('individuo.contatti')
|
||||
->get();
|
||||
|
||||
$totaleContatti = $contatti->count();
|
||||
$emails = $contatti->map(fn($c) => $c->individuo?->contatti->where('tipo', 'email')->first()?->valore)
|
||||
->filter()->unique()->values();
|
||||
|
||||
$skipped = $totaleContatti - $emails->count();
|
||||
if ($skipped > 0) {
|
||||
Log::info("Mailing invio elabora: {$skipped} contatti saltati perché senza email", [
|
||||
'liste_ids' => $data['liste'],
|
||||
]);
|
||||
}
|
||||
|
||||
if ($emails->isEmpty()) {
|
||||
return back()->with('error', 'Nessun destinatario email valido trovato nelle liste selezionate.');
|
||||
}
|
||||
|
||||
@@ -3,23 +3,31 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\MailingList;
|
||||
use App\Models\Tag;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MailingListController extends Controller
|
||||
{
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorizeRead('mailing');
|
||||
$mailingLists = MailingList::with(['user', 'contatti'])
|
||||
->orderBy('nome')
|
||||
->get();
|
||||
return view('mailing-liste.index', compact('mailingLists'));
|
||||
$query = MailingList::with(['user', 'contatti', 'tags']);
|
||||
|
||||
if ($request->filled('tag')) {
|
||||
$tagSlugs = (array) $request->input('tag');
|
||||
$query->withAnyTags($tagSlugs);
|
||||
}
|
||||
|
||||
$mailingLists = $query->orderBy('nome')->get();
|
||||
$allTags = Tag::orderBy('name')->get();
|
||||
return view('mailing-liste.index', compact('mailingLists', 'allTags'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$this->authorizeWrite('mailing');
|
||||
return view('mailing-liste.create');
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
return view('mailing-liste.create', compact('tags'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
@@ -30,6 +38,8 @@ class MailingListController extends Controller
|
||||
'descrizione' => 'nullable|string',
|
||||
'attiva' => 'boolean',
|
||||
'contatti_json' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$data['user_id'] = auth()->id();
|
||||
@@ -42,11 +52,15 @@ class MailingListController extends Controller
|
||||
'user_id' => $data['user_id'],
|
||||
]);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$lista->tags()->sync($request->tags);
|
||||
}
|
||||
|
||||
if (!empty($data['contatti_json'])) {
|
||||
$contatti = json_decode($data['contatti_json'], true);
|
||||
if (is_array($contatti)) {
|
||||
foreach ($contatti as $contatto) {
|
||||
if (!empty($contatto['individuo_id']) && !empty($contatto['email'])) {
|
||||
if (!empty($contatto['individuo_id'])) {
|
||||
$lista->contatti()->create([
|
||||
'individuo_id' => $contatto['individuo_id'],
|
||||
'opt_in' => true,
|
||||
@@ -63,15 +77,17 @@ class MailingListController extends Controller
|
||||
public function show($mailing_liste)
|
||||
{
|
||||
$this->authorizeRead('mailing');
|
||||
$mailingList = MailingList::with(['contatti.individuo.contatti'])->findOrFail($mailing_liste);
|
||||
$mailingList = MailingList::with(['contatti.individuo.contatti', 'tags'])->findOrFail($mailing_liste);
|
||||
return view('mailing-liste.show', compact('mailingList'));
|
||||
}
|
||||
|
||||
public function edit($mailingList)
|
||||
{
|
||||
$this->authorizeWrite('mailing');
|
||||
$mailingList = MailingList::with('contatti.individuo.contatti')->findOrFail($mailingList);
|
||||
return view('mailing-liste.edit', compact('mailingList'));
|
||||
$mailingList = MailingList::with(['contatti.individuo.contatti', 'tags'])->findOrFail($mailingList);
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
$selectedTags = $mailingList->tags->pluck('id')->toArray();
|
||||
return view('mailing-liste.edit', compact('mailingList', 'tags', 'selectedTags'));
|
||||
}
|
||||
|
||||
public function update(Request $request, $mailingList)
|
||||
@@ -84,6 +100,8 @@ class MailingListController extends Controller
|
||||
'descrizione' => 'nullable|string',
|
||||
'attiva' => 'boolean',
|
||||
'contatti_json' => 'nullable|string',
|
||||
'tags' => 'nullable|array',
|
||||
'tags.*' => 'exists:tags,id',
|
||||
]);
|
||||
|
||||
$data['attiva'] = $data['attiva'] ?? false;
|
||||
@@ -94,6 +112,12 @@ class MailingListController extends Controller
|
||||
'attiva' => $data['attiva'],
|
||||
]);
|
||||
|
||||
if ($request->has('tags')) {
|
||||
$mailingList->tags()->sync($request->tags);
|
||||
} else {
|
||||
$mailingList->tags()->detach();
|
||||
}
|
||||
|
||||
if (!empty($data['contatti_json'])) {
|
||||
$newContatti = json_decode($data['contatti_json'], true);
|
||||
if (is_array($newContatti)) {
|
||||
@@ -107,7 +131,7 @@ class MailingListController extends Controller
|
||||
|
||||
$toAdd = array_diff($newIds, $existingIds);
|
||||
foreach ($newContatti as $contatto) {
|
||||
if (in_array($contatto['individuo_id'], $toAdd) && !empty($contatto['email'])) {
|
||||
if (in_array($contatto['individuo_id'], $toAdd)) {
|
||||
$mailingList->contatti()->create([
|
||||
'individuo_id' => $contatto['individuo_id'],
|
||||
'opt_in' => true,
|
||||
|
||||
@@ -11,6 +11,7 @@ use App\Models\Evento;
|
||||
use App\Models\Documento;
|
||||
use App\Models\MailingList;
|
||||
use App\Models\Contatto;
|
||||
use App\Models\Tag;
|
||||
use App\Models\TipologiaDocumento;
|
||||
use App\Models\ReportCustom;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -47,12 +48,15 @@ class ReportController extends Controller
|
||||
$columnOptions[$type] = ReportColumnRegistry::getColumns($type);
|
||||
}
|
||||
|
||||
$allTags = Tag::orderBy('name')->get();
|
||||
|
||||
return view('report.index', compact(
|
||||
'stats',
|
||||
'prebuiltReports',
|
||||
'customReports',
|
||||
'tipologieDocumento',
|
||||
'columnOptions'
|
||||
'columnOptions',
|
||||
'allTags'
|
||||
));
|
||||
}
|
||||
|
||||
@@ -136,6 +140,14 @@ class ReportController extends Controller
|
||||
$config['search_columns'] = $request->input('search_columns');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
ReportCustom::create([
|
||||
'user_id' => auth()->id(),
|
||||
'nome' => $data['nome'],
|
||||
@@ -252,6 +264,9 @@ class ReportController extends Controller
|
||||
'documenti_completo' => $this->reportDocumentiCompleto($tipologiaFilter),
|
||||
'contatti_completo' => $this->reportContattiCompleto(),
|
||||
'scadenze_documenti' => $this->reportScadenzeDocumenti($tipologiaFilter),
|
||||
'tag_statistiche' => $this->reportTagStatistiche(),
|
||||
'individui_per_tag' => $this->reportIndividuiPerTag(),
|
||||
'documenti_per_tag' => $this->reportDocumentiPerTag(),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
@@ -403,6 +418,30 @@ class ReportController extends Controller
|
||||
'colore' => 'teal',
|
||||
'has_tipologia_filter' => false,
|
||||
],
|
||||
[
|
||||
'id' => 'tag_statistiche',
|
||||
'nome' => 'Statistiche Tag',
|
||||
'descrizione' => 'Distribuzione degli elementi per tag (individui, gruppi, eventi, documenti, mailing list)',
|
||||
'icona' => 'fa-tags',
|
||||
'colore' => 'indigo',
|
||||
'has_tipologia_filter' => false,
|
||||
],
|
||||
[
|
||||
'id' => 'individui_per_tag',
|
||||
'nome' => 'Individui per Tag',
|
||||
'descrizione' => 'Elenco completo degli individui raggruppati per tag assegnato',
|
||||
'icona' => 'fa-user-tag',
|
||||
'colore' => 'info',
|
||||
'has_tipologia_filter' => false,
|
||||
],
|
||||
[
|
||||
'id' => 'documenti_per_tag',
|
||||
'nome' => 'Documenti per Tag',
|
||||
'descrizione' => 'Elenco completo dei documenti raggruppati per tag assegnato',
|
||||
'icona' => 'fa-tags',
|
||||
'colore' => 'secondary',
|
||||
'has_tipologia_filter' => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -927,6 +966,102 @@ class ReportController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
protected function reportTagStatistiche(): array
|
||||
{
|
||||
$tags = Tag::orderBy('name')->get();
|
||||
|
||||
$rows = $tags->map(function ($tag) {
|
||||
return [
|
||||
'name' => $tag->name,
|
||||
'color' => $tag->color ?? '#6c757d',
|
||||
'individui' => $tag->individui()->count(),
|
||||
'gruppi' => $tag->gruppi()->count(),
|
||||
'eventi' => $tag->eventi()->count(),
|
||||
'documenti' => $tag->documenti()->count(),
|
||||
'mailing' => $tag->mailingLists()->count(),
|
||||
'totale' => $tag->count,
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
$totalIndividui = array_sum(array_column($rows, 'individui'));
|
||||
$totalGruppi = array_sum(array_column($rows, 'gruppi'));
|
||||
$totalEventi = array_sum(array_column($rows, 'eventi'));
|
||||
$totalDocumenti = array_sum(array_column($rows, 'documenti'));
|
||||
$totalMailing = array_sum(array_column($rows, 'mailing'));
|
||||
|
||||
return [
|
||||
'title' => 'Statistiche Tag',
|
||||
'headers' => ['Tag', 'Individui', 'Gruppi', 'Eventi', 'Documenti', 'Mailing List', 'Totale Elementi'],
|
||||
'rows' => array_map(fn($r) => [$r['name'], $r['individui'], $r['gruppi'], $r['eventi'], $r['documenti'], $r['mailing'], $r['totale']], $rows),
|
||||
'summary' => 'Tag: ' . count($tags) . ' | Individui: ' . $totalIndividui . ' | Gruppi: ' . $totalGruppi . ' | Eventi: ' . $totalEventi . ' | Documenti: ' . $totalDocumenti . ' | Mailing List: ' . $totalMailing,
|
||||
'detail_rows' => $rows,
|
||||
];
|
||||
}
|
||||
|
||||
protected function reportIndividuiPerTag(): array
|
||||
{
|
||||
$individui = Individuo::with('tags')
|
||||
->whereHas('tags')
|
||||
->orderBy('cognome')
|
||||
->orderBy('nome')
|
||||
->get();
|
||||
|
||||
$rows = $individui->flatMap(function ($ind) {
|
||||
if ($ind->tags->isEmpty()) {
|
||||
return collect();
|
||||
}
|
||||
return $ind->tags->map(function ($tag) use ($ind) {
|
||||
return [
|
||||
'tag' => $tag->name,
|
||||
'tag_color' => $tag->color ?? '#6c757d',
|
||||
'codice' => $ind->codice_id,
|
||||
'cognome' => $ind->cognome,
|
||||
'nome' => $ind->nome,
|
||||
'email' => $ind->email_primaria ?? '-',
|
||||
];
|
||||
});
|
||||
})->toArray();
|
||||
|
||||
return [
|
||||
'title' => 'Individui per Tag',
|
||||
'headers' => ['Tag', 'Codice', 'Cognome', 'Nome', 'Email'],
|
||||
'rows' => array_map(fn($r) => [$r['tag'], $r['codice'], $r['cognome'], $r['nome'], $r['email']], $rows),
|
||||
'summary' => 'Totale righe (individuo × tag): ' . count($rows),
|
||||
'detail_rows' => $rows,
|
||||
];
|
||||
}
|
||||
|
||||
protected function reportDocumentiPerTag(): array
|
||||
{
|
||||
$documenti = Documento::with('tags')
|
||||
->whereHas('tags')
|
||||
->orderBy('nome_file')
|
||||
->get();
|
||||
|
||||
$rows = $documenti->flatMap(function ($doc) {
|
||||
if ($doc->tags->isEmpty()) {
|
||||
return collect();
|
||||
}
|
||||
return $doc->tags->map(function ($tag) use ($doc) {
|
||||
return [
|
||||
'tag' => $tag->name,
|
||||
'tag_color' => $tag->color ?? '#6c757d',
|
||||
'nome_file' => $doc->nome_file,
|
||||
'tipologia' => ucfirst((string) $doc->tipologia),
|
||||
'data' => $doc->created_at->format('d/m/Y'),
|
||||
];
|
||||
});
|
||||
})->toArray();
|
||||
|
||||
return [
|
||||
'title' => 'Documenti per Tag',
|
||||
'headers' => ['Tag', 'Nome File', 'Tipologia', 'Data Caricamento'],
|
||||
'rows' => array_map(fn($r) => [$r['tag'], $r['nome_file'], $r['tipologia'], $r['data']], $rows),
|
||||
'summary' => 'Totale righe (documento × tag): ' . count($rows),
|
||||
'detail_rows' => $rows,
|
||||
];
|
||||
}
|
||||
|
||||
protected function runCustomReport(ReportCustom $report): array
|
||||
{
|
||||
$tipo = $report->tipo_report;
|
||||
@@ -954,11 +1089,32 @@ class ReportController extends Controller
|
||||
$columns = $config['columns'] ?? [];
|
||||
$hasRelations = false;
|
||||
|
||||
// Always load tags if tags column or tag filter is present
|
||||
$needsTags = in_array('tags.nome', $columns) || !empty($config['tag_filter']);
|
||||
if ($needsTags) {
|
||||
$query->with('tags');
|
||||
}
|
||||
|
||||
foreach ($columns as $col) {
|
||||
if (str_contains($col, '.')) {
|
||||
$hasRelations = true;
|
||||
$relation = explode('.', $col)[0];
|
||||
$query->with($relation);
|
||||
if ($relation !== 'tags') {
|
||||
$query->with($relation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply tag filter
|
||||
if (!empty($config['tag_filter'])) {
|
||||
$tagSlugs = Tag::whereIn('id', (array) $config['tag_filter'])->pluck('slug')->toArray();
|
||||
if (!empty($tagSlugs)) {
|
||||
$mode = $config['tag_filter_mode'] ?? 'any';
|
||||
if ($mode === 'all') {
|
||||
$query->withAllTags($tagSlugs);
|
||||
} else {
|
||||
$query->withAnyTags($tagSlugs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user