2026-05-26 08:14:29 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
use App\Models\Individuo;
|
|
|
|
|
use App\Models\Contatto;
|
|
|
|
|
use App\Models\Documento;
|
2026-06-09 11:02:01 +02:00
|
|
|
use App\Models\Gruppo;
|
2026-05-26 08:14:29 +02:00
|
|
|
use App\Models\Comune;
|
|
|
|
|
use App\Models\Diocesi;
|
2026-06-09 11:02:01 +02:00
|
|
|
use App\Models\Tag;
|
2026-05-26 08:14:29 +02:00
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
|
use Illuminate\Validation\Rule;
|
|
|
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
|
|
|
|
|
|
class IndividuoController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function index(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
2026-06-07 17:27:00 +02:00
|
|
|
$perPage = in_array((int) $request->perPage, [10, 20, 25, 50, 100]) ? (int) $request->perPage : 20;
|
2026-06-09 11:02:01 +02:00
|
|
|
|
|
|
|
|
$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();
|
2026-05-26 08:14:29 +02:00
|
|
|
|
|
|
|
|
$vista = null;
|
|
|
|
|
|
|
|
|
|
if ($request->has('vista_id')) {
|
|
|
|
|
$vista = \App\Models\VistaReport::where('id', $request->vista_id)
|
|
|
|
|
->where('user_id', auth()->id())
|
|
|
|
|
->first();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$vista && auth()->check()) {
|
|
|
|
|
$vista = \App\Models\VistaReport::where('user_id', auth()->id())
|
|
|
|
|
->where('tipo', 'individui')
|
|
|
|
|
->where('is_default', true)
|
|
|
|
|
->first();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$allColumns = [
|
|
|
|
|
['key' => 'codice', 'label' => 'Codice'],
|
|
|
|
|
['key' => 'cognome', 'label' => 'Cognome'],
|
|
|
|
|
['key' => 'nome', 'label' => 'Nome'],
|
|
|
|
|
['key' => 'email', 'label' => 'Email'],
|
|
|
|
|
['key' => 'telefono', 'label' => 'Telefono'],
|
2026-06-09 11:02:01 +02:00
|
|
|
['key' => 'tag', 'label' => 'Tag'],
|
2026-05-26 08:14:29 +02:00
|
|
|
];
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
$defaultVisible = ['codice', 'cognome', 'nome', 'email', 'telefono', 'tag'];
|
2026-05-26 08:14:29 +02:00
|
|
|
$visibleColumns = $vista && !empty($vista->colonne_visibili)
|
|
|
|
|
? $vista->colonne_visibili
|
|
|
|
|
: $defaultVisible;
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
$gruppi = Gruppo::orderBy('nome')->get(['id', 'nome']);
|
|
|
|
|
return view('individui.index', compact('individui', 'vista', 'allColumns', 'visibleColumns', 'allTags', 'gruppi'));
|
2026-05-26 08:14:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function exportCSV(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
|
|
|
|
|
$ids = $request->input('ids', []);
|
|
|
|
|
|
|
|
|
|
$query = Individuo::with('contatti')->orderBy('cognome')->orderBy('nome');
|
|
|
|
|
|
|
|
|
|
if (is_array($ids) && !empty($ids)) {
|
|
|
|
|
$query->whereIn('id', array_map('intval', $ids));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$individui = $query->get();
|
|
|
|
|
|
|
|
|
|
$response = new StreamedResponse(function () use ($individui) {
|
|
|
|
|
$handle = fopen('php://output', 'w');
|
|
|
|
|
|
|
|
|
|
fputcsv($handle, ['Codice', 'Cognome', 'Nome', 'Data Nascita', 'Genere', 'Email', 'Telefono', 'Cellulare', 'Indirizzo', 'CAP', 'Città', 'Provincia', 'Note']);
|
|
|
|
|
|
|
|
|
|
foreach ($individui as $ind) {
|
|
|
|
|
$email = $ind->contatti->where('tipo', 'email')->where('is_primary', true)->first()
|
|
|
|
|
?? $ind->contatti->where('tipo', 'email')->first();
|
|
|
|
|
$telefono = $ind->contatti->where('tipo', 'telefono')->where('is_primary', true)->first()
|
|
|
|
|
?? $ind->contatti->where('tipo', 'telefono')->first();
|
|
|
|
|
$cellulare = $ind->contatti->where('tipo', 'cellulare')->where('is_primary', true)->first()
|
|
|
|
|
?? $ind->contatti->where('tipo', 'cellulare')->first();
|
|
|
|
|
|
|
|
|
|
fputcsv($handle, [
|
|
|
|
|
$ind->codice_id,
|
|
|
|
|
$ind->cognome,
|
|
|
|
|
$ind->nome,
|
|
|
|
|
$ind->data_nascita?->format('d/m/Y') ?? '',
|
|
|
|
|
$ind->genere === 'M' ? 'Maschio' : ($ind->genere === 'F' ? 'Femmina' : ''),
|
|
|
|
|
$email?->valore ?? '',
|
|
|
|
|
$telefono?->valore ?? '',
|
|
|
|
|
$cellulare?->valore ?? '',
|
|
|
|
|
$ind->indirizzo,
|
|
|
|
|
$ind->cap,
|
|
|
|
|
$ind->città,
|
|
|
|
|
$ind->sigla_provincia,
|
|
|
|
|
$ind->note,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($handle);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$response->headers->set('Content-Type', 'text/csv; charset=utf-8');
|
|
|
|
|
$response->headers->set('Content-Disposition', 'attachment; filename="individui_' . now()->format('Y-m-d') . '.csv"');
|
|
|
|
|
$response->headers->set('Cache-Control', 'no-store');
|
|
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function create()
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
|
|
|
|
$comuni = Comune::orderBy('nome')->get();
|
|
|
|
|
$diocesi = Diocesi::orderBy('nome')->get();
|
2026-06-09 11:02:01 +02:00
|
|
|
$tags = Tag::orderBy('name')->get();
|
|
|
|
|
return view('individui.create', compact('comuni', 'diocesi', 'tags'));
|
2026-05-26 08:14:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function store(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
|
|
|
|
$data = $request->validate([
|
|
|
|
|
'cognome' => 'required|string|max:255',
|
|
|
|
|
'nome' => 'required|string|max:255',
|
|
|
|
|
'data_nascita' => 'nullable|date',
|
|
|
|
|
'indirizzo' => 'nullable|string|max:500',
|
|
|
|
|
'cap' => 'nullable|string|max:10',
|
|
|
|
|
'città' => 'nullable|string|max:255',
|
|
|
|
|
'sigla_provincia' => 'nullable|string|max:2',
|
|
|
|
|
'genere' => 'nullable|in:M,F',
|
|
|
|
|
'tipo_documento' => 'nullable|in:carta_identita,patente',
|
|
|
|
|
'numero_documento' => 'nullable|string|max:50',
|
|
|
|
|
'scadenza_documento' => 'nullable|date',
|
|
|
|
|
'note' => 'nullable|string',
|
2026-06-09 11:02:01 +02:00
|
|
|
'tags' => 'nullable|array',
|
|
|
|
|
'tags.*' => 'exists:tags,id',
|
2026-05-26 08:14:29 +02:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$individuo = Individuo::create($data);
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
if ($request->has('tags')) {
|
|
|
|
|
$individuo->tags()->sync($request->tags);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 08:14:29 +02:00
|
|
|
if ($request->has('contatti')) {
|
|
|
|
|
foreach ($request->contatti as $contatto) {
|
|
|
|
|
if (!empty($contatto['tipo']) && !empty($contatto['valore'])) {
|
|
|
|
|
$individuo->contatti()->create([
|
|
|
|
|
'tipo' => $contatto['tipo'],
|
|
|
|
|
'valore' => $contatto['valore'],
|
|
|
|
|
'etichetta' => $contatto['etichetta'] ?? null,
|
|
|
|
|
'is_primary' => $contatto['is_primary'] ?? false,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()->route('individui.index')->with('success', 'Individuo creato con successo.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function show($individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$individuo = Individuo::with(['contatti', 'gruppi' => function ($q) {
|
|
|
|
|
$q->withPivot('ruolo_ids', 'ruolo_nel_gruppo', 'data_adesione');
|
2026-06-09 11:02:01 +02:00
|
|
|
}, 'avatar', 'tags'])->findOrFail($individuo);
|
2026-05-26 08:14:29 +02:00
|
|
|
return view('individui.show', compact('individuo'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function report($individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$individuo = Individuo::with(['contatti', 'gruppi', 'documenti', 'eventiResponsabili', 'avatar'])->findOrFail($individuo);
|
|
|
|
|
return view('individui.report', compact('individuo'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function reportStampa(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$ids = explode(',', $request->ids ?? '');
|
|
|
|
|
$individui = Individuo::with(['contatti', 'gruppi', 'documenti', 'eventiResponsabili', 'avatar'])
|
|
|
|
|
->whereIn('id', $ids)
|
|
|
|
|
->orderBy('cognome')
|
|
|
|
|
->orderBy('nome')
|
|
|
|
|
->get();
|
|
|
|
|
return view('individui.report-multiplo', compact('individui'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function edit($individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
2026-06-09 11:02:01 +02:00
|
|
|
$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'));
|
2026-05-26 08:14:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function update(Request $request, $individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
|
|
|
|
|
\Log::info('=== INDIVIDUO UPDATE START ===', ['id' => $individuo->id]);
|
|
|
|
|
\Log::info('Request contatti:', ['contatti' => $request->input('contatti'), 'all_keys' => array_keys($request->all())]);
|
|
|
|
|
|
|
|
|
|
$data = $request->validate([
|
|
|
|
|
'cognome' => 'required|string|max:255',
|
|
|
|
|
'nome' => 'required|string|max:255',
|
|
|
|
|
'data_nascita' => 'nullable|date',
|
|
|
|
|
'indirizzo' => 'nullable|string|max:500',
|
|
|
|
|
'cap' => 'nullable|string|max:10',
|
|
|
|
|
'città' => 'nullable|string|max:255',
|
|
|
|
|
'sigla_provincia' => 'nullable|string|max:2',
|
|
|
|
|
'genere' => 'nullable|in:M,F',
|
|
|
|
|
'tipo_documento' => 'nullable|in:carta_identita,patente',
|
|
|
|
|
'numero_documento' => 'nullable|string|max:50',
|
|
|
|
|
'scadenza_documento' => 'nullable|date',
|
|
|
|
|
'note' => 'nullable|string',
|
2026-06-09 11:02:01 +02:00
|
|
|
'tags' => 'nullable|array',
|
|
|
|
|
'tags.*' => 'exists:tags,id',
|
2026-05-26 08:14:29 +02:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$individuo->update($data);
|
2026-06-09 11:02:01 +02:00
|
|
|
|
|
|
|
|
if ($request->has('tags')) {
|
|
|
|
|
$individuo->tags()->sync($request->tags);
|
|
|
|
|
} else {
|
|
|
|
|
$individuo->tags()->detach();
|
|
|
|
|
}
|
2026-05-26 08:14:29 +02:00
|
|
|
|
|
|
|
|
\Log::info('Individuo dati salvati', ['id' => $individuo->id]);
|
|
|
|
|
|
2026-06-02 20:29:47 +02:00
|
|
|
if ($request->has('contatti')) {
|
|
|
|
|
$contattiData = $request->input('contatti');
|
|
|
|
|
\Log::info('Contatti ricevuti:', ['contatti' => $contattiData, 'tipo' => gettype($contattiData)]);
|
|
|
|
|
|
|
|
|
|
$individuo->contatti()->delete();
|
|
|
|
|
\Log::info('Contatti precedenti eliminati, count ora:', ['count' => $individuo->contatti()->count()]);
|
|
|
|
|
} else {
|
|
|
|
|
$contattiData = null;
|
|
|
|
|
}
|
2026-05-26 08:14:29 +02:00
|
|
|
|
|
|
|
|
if (!empty($contattiData) && is_array($contattiData)) {
|
|
|
|
|
$created = 0;
|
|
|
|
|
foreach ($contattiData as $contatto) {
|
|
|
|
|
if (!empty($contatto['tipo']) && !empty($contatto['valore'])) {
|
|
|
|
|
$individuo->contatti()->create([
|
|
|
|
|
'tipo' => $contatto['tipo'],
|
|
|
|
|
'valore' => $contatto['valore'],
|
|
|
|
|
'etichetta' => $contatto['etichetta'] ?? null,
|
|
|
|
|
'is_primary' => !empty($contatto['is_primary']),
|
|
|
|
|
]);
|
|
|
|
|
$created++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
\Log::info('Contatti creati:', ['count' => $created]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()->route('individui.show', $individuo)->with('success', 'Individuo aggiornato con successo!');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function destroy($individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeDelete('individui');
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
$individuo->delete();
|
|
|
|
|
return redirect()->route('individui.index')->with('success', 'Individuo eliminato.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function elimina(Request $request, $individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeDelete('individui');
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
|
|
|
|
|
$eliminaContatti = filter_var($request->input('elimina_contatti', false), FILTER_VALIDATE_BOOLEAN);
|
|
|
|
|
$eliminaDocumenti = filter_var($request->input('elimina_documenti', false), FILTER_VALIDATE_BOOLEAN);
|
|
|
|
|
|
|
|
|
|
if ($eliminaContatti) {
|
|
|
|
|
$individuo->contatti()->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($eliminaDocumenti) {
|
|
|
|
|
foreach ($individuo->documenti as $documento) {
|
|
|
|
|
if ($documento->file_path && file_exists(storage_path('app/public/' . $documento->file_path))) {
|
|
|
|
|
unlink(storage_path('app/public/' . $documento->file_path));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$individuo->documenti()->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$individuo->delete();
|
|
|
|
|
|
|
|
|
|
return redirect()->route('individui.index')->with('success', 'Individuo eliminato con successo.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function massElimina(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeDelete('individui');
|
|
|
|
|
|
|
|
|
|
$ids = $request->input('ids', []);
|
|
|
|
|
if (!is_array($ids) || empty($ids)) {
|
|
|
|
|
return redirect()->route('individui.index')->with('error', 'Nessun individuo selezionato.');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$eliminaContatti = filter_var($request->input('elimina_contatti', false), FILTER_VALIDATE_BOOLEAN);
|
|
|
|
|
$eliminaDocumenti = filter_var($request->input('elimina_documenti', false), FILTER_VALIDATE_BOOLEAN);
|
|
|
|
|
|
|
|
|
|
$individui = Individuo::whereIn('id', $ids)->get();
|
|
|
|
|
|
|
|
|
|
foreach ($individui as $individuo) {
|
|
|
|
|
if ($eliminaContatti) {
|
|
|
|
|
$individuo->contatti()->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($eliminaDocumenti) {
|
|
|
|
|
foreach ($individuo->documenti as $documento) {
|
|
|
|
|
if ($documento->file_path && file_exists(storage_path('app/public/' . $documento->file_path))) {
|
|
|
|
|
unlink(storage_path('app/public/' . $documento->file_path));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$individuo->documenti()->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$individuo->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()->route('individui.index')->with('success', count($individui) . ' individui eliminati con successo.');
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-09 11:02:01 +02:00
|
|
|
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.");
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 08:14:29 +02:00
|
|
|
public function elementiCollegati($individuo)
|
|
|
|
|
{
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
|
|
|
|
|
return response()->json([
|
|
|
|
|
'contatti' => $individuo->contatti()->count(),
|
|
|
|
|
'gruppi' => $individuo->gruppi()->count(),
|
|
|
|
|
'documenti' => $individuo->documenti()->count(),
|
|
|
|
|
'eventi' => $individuo->eventiResponsabili()->count(),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function emailList(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$ids = $request->input('ids', '');
|
|
|
|
|
$idArray = array_filter(array_map('intval', explode(',', $ids)));
|
|
|
|
|
|
|
|
|
|
if (empty($idArray)) {
|
|
|
|
|
return response()->json([]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$individui = Individuo::with('contatti')->whereIn('id', $idArray)->get();
|
|
|
|
|
|
|
|
|
|
$result = [];
|
|
|
|
|
foreach ($individui as $ind) {
|
|
|
|
|
$emails = $ind->contatti->where('tipo', 'email')->pluck('valore')->toArray();
|
|
|
|
|
$result[] = [
|
|
|
|
|
'id' => $ind->id,
|
|
|
|
|
'codice_id' => $ind->codice_id,
|
|
|
|
|
'cognome' => $ind->cognome,
|
|
|
|
|
'nome' => $ind->nome,
|
|
|
|
|
'email' => count($emails) === 1 ? $emails[0] : null,
|
|
|
|
|
'emails' => $emails,
|
|
|
|
|
'email_count' => count($emails)
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response()->json($result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function allIndividui()
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$individui = Individuo::select('id', 'codice_id', 'cognome', 'nome')
|
|
|
|
|
->orderBy('cognome')
|
|
|
|
|
->orderBy('nome')
|
|
|
|
|
->get();
|
|
|
|
|
return response()->json($individui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function import()
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
|
|
|
|
return view('individui.import');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function importStore(Request $request)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
|
|
|
|
$request->validate([
|
|
|
|
|
'file' => 'required|file|mimes:csv,txt',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$file = $request->file('file');
|
|
|
|
|
$handle = fopen($file->path(), 'r');
|
|
|
|
|
$header = fgetcsv($handle, 1000, ',');
|
|
|
|
|
|
|
|
|
|
$imported = 0;
|
|
|
|
|
$skipped = 0;
|
|
|
|
|
$errors = [];
|
|
|
|
|
$rowNumber = 1;
|
|
|
|
|
|
|
|
|
|
while (($row = fgetcsv($handle, 1000, ',')) !== false) {
|
|
|
|
|
$rowNumber++;
|
|
|
|
|
|
|
|
|
|
if (count($row) < count($header)) {
|
|
|
|
|
$skipped++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$data = array_combine($header, $row);
|
|
|
|
|
|
|
|
|
|
if ($data === false) {
|
|
|
|
|
$skipped++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$cognome = trim($data['cognome'] ?? '');
|
|
|
|
|
$nome = trim($data['nome'] ?? '');
|
|
|
|
|
|
|
|
|
|
if (empty($cognome) || empty($nome)) {
|
|
|
|
|
$skipped++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$individuo = Individuo::create([
|
|
|
|
|
'cognome' => $cognome,
|
|
|
|
|
'nome' => $nome,
|
|
|
|
|
'data_nascita' => !empty(trim($data['data_nascita'] ?? '')) ? trim($data['data_nascita']) : null,
|
|
|
|
|
'indirizzo' => !empty(trim($data['indirizzo'] ?? '')) ? trim($data['indirizzo']) : null,
|
|
|
|
|
'cap' => !empty(trim($data['cap'] ?? '')) ? trim($data['cap']) : null,
|
|
|
|
|
'città' => !empty(trim($data['città'] ?? '')) ? trim($data['città']) : null,
|
|
|
|
|
'sigla_provincia' => !empty(trim($data['sigla_provincia'] ?? '')) ? trim($data['sigla_provincia']) : null,
|
|
|
|
|
'genere' => !empty(trim($data['genere'] ?? '')) ? strtoupper(trim($data['genere'])) : null,
|
|
|
|
|
'tipo_documento' => !empty(trim($data['tipo_documento'] ?? '')) ? trim($data['tipo_documento']) : null,
|
|
|
|
|
'numero_documento' => !empty(trim($data['numero_documento'] ?? '')) ? trim($data['numero_documento']) : null,
|
|
|
|
|
'scadenza_documento' => !empty(trim($data['scadenza_documento'] ?? '')) ? trim($data['scadenza_documento']) : null,
|
|
|
|
|
'note' => !empty(trim($data['note'] ?? '')) ? trim($data['note']) : null,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
for ($i = 1; $i <= 2; $i++) {
|
|
|
|
|
$tipoKey = 'contatto_' . $i . '_tipo';
|
|
|
|
|
$valoreKey = 'contatto_' . $i . '_valore';
|
|
|
|
|
$etichettaKey = 'contatto_' . $i . '_etichetta';
|
|
|
|
|
|
|
|
|
|
$tipo = trim($data[$tipoKey] ?? '');
|
|
|
|
|
$valore = trim($data[$valoreKey] ?? '');
|
|
|
|
|
|
|
|
|
|
if (!empty($tipo) && !empty($valore)) {
|
|
|
|
|
$individuo->contatti()->create([
|
|
|
|
|
'tipo' => $tipo,
|
|
|
|
|
'valore' => $valore,
|
|
|
|
|
'etichetta' => !empty(trim($data[$etichettaKey] ?? '')) ? trim($data[$etichettaKey]) : null,
|
|
|
|
|
'is_primary' => $i === 1,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$imported++;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
$errors[] = 'Errore riga ' . $rowNumber . ': ' . $e->getMessage();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose($handle);
|
|
|
|
|
|
|
|
|
|
$message = 'Importati ' . $imported . ' individui.';
|
|
|
|
|
if ($skipped > 0) {
|
|
|
|
|
$message .= ' Saltate ' . $skipped . ' righe (vuote o incomplete).';
|
|
|
|
|
}
|
|
|
|
|
if (count($errors) > 0) {
|
|
|
|
|
return back()->with('error', $message . ' Errori: ' . implode('; ', $errors));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()->route('individui.index')->with('success', $message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function downloadTemplate()
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$headers = ['cognome', 'nome', 'data_nascita', 'indirizzo', 'cap', 'città', 'sigla_provincia', 'genere', 'tipo_documento', 'numero_documento', 'scadenza_documento', 'note', 'contatto_1_tipo', 'contatto_1_valore', 'contatto_1_etichetta', 'contatto_2_tipo', 'contatto_2_valore', 'contatto_2_etichetta'];
|
|
|
|
|
|
|
|
|
|
$example = [
|
|
|
|
|
'Rossi',
|
|
|
|
|
'Mario',
|
|
|
|
|
'1990-05-15',
|
|
|
|
|
'Via Roma 10',
|
|
|
|
|
'00100',
|
|
|
|
|
'Roma',
|
|
|
|
|
'RM',
|
|
|
|
|
'M',
|
|
|
|
|
'carta_identita',
|
|
|
|
|
'AB123456',
|
|
|
|
|
'2030-05-15',
|
|
|
|
|
'Socio fondatore',
|
|
|
|
|
'email',
|
|
|
|
|
'mario.rossi@email.com',
|
|
|
|
|
'personale',
|
|
|
|
|
'cellulare',
|
|
|
|
|
'3331234567',
|
|
|
|
|
'lavoro',
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$csv = implode(',', $headers) . "\n" . implode(',', $example);
|
|
|
|
|
|
|
|
|
|
return response($csv, 200, [
|
|
|
|
|
'Content-Type' => 'text/csv',
|
|
|
|
|
'Content-Disposition' => 'attachment; filename="template_individui.csv"',
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function uploadAvatar(Request $request, $individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWrite('individui');
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
|
|
|
|
|
$request->validate([
|
|
|
|
|
'avatar' => 'required|image|mimes:jpeg,jpg,png,gif|max:2048',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$file = $request->file('avatar');
|
|
|
|
|
|
|
|
|
|
$oldAvatar = $individuo->avatar;
|
|
|
|
|
if ($oldAvatar) {
|
|
|
|
|
if (Storage::disk('local')->exists($oldAvatar->file_path)) {
|
|
|
|
|
Storage::disk('local')->delete($oldAvatar->file_path);
|
|
|
|
|
}
|
|
|
|
|
$oldAvatar->delete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$path = $file->store('avatars', 'local');
|
|
|
|
|
|
|
|
|
|
$avatar = Documento::create([
|
|
|
|
|
'tenant_id' => $individuo->tenant_id,
|
|
|
|
|
'nome_file' => $file->getClientOriginalName(),
|
|
|
|
|
'file_path' => $path,
|
|
|
|
|
'tipo' => 'upload',
|
|
|
|
|
'tipologia' => 'avatar',
|
|
|
|
|
'visibilita' => 'individuo',
|
|
|
|
|
'visibilita_target_id' => $individuo->id,
|
|
|
|
|
'visibilita_target_type' => Individuo::class,
|
|
|
|
|
'mime_type' => $file->getMimeType(),
|
|
|
|
|
'dimensione' => $file->getSize(),
|
|
|
|
|
'user_id' => auth()->id(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return response()->json([
|
|
|
|
|
'success' => true,
|
|
|
|
|
'avatar_url' => url('/individui/' . $individuo->id . '/avatar'),
|
|
|
|
|
'avatar_id' => $avatar->id,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getAvatar($individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeRead('individui');
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
$avatar = $individuo->avatar;
|
|
|
|
|
|
|
|
|
|
if (!$avatar || !Storage::disk('local')->exists($avatar->file_path)) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response(
|
|
|
|
|
Storage::disk('local')->get($avatar->file_path),
|
|
|
|
|
200,
|
|
|
|
|
['Content-Type' => $avatar->mime_type]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function deleteAvatar($individuo)
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeDelete('individui');
|
|
|
|
|
$individuo = Individuo::findOrFail($individuo);
|
|
|
|
|
$avatar = $individuo->avatar;
|
|
|
|
|
|
|
|
|
|
if (!$avatar) {
|
|
|
|
|
return response()->json(['success' => false, 'message' => 'Nessun avatar da eliminare']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Storage::disk('local')->exists($avatar->file_path)) {
|
|
|
|
|
Storage::disk('local')->delete($avatar->file_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$avatar->delete();
|
|
|
|
|
|
|
|
|
|
return response()->json(['success' => true]);
|
|
|
|
|
}
|
|
|
|
|
}
|