651 lines
34 KiB
PHP
651 lines
34 KiB
PHP
<!-- STATISTICHE SINTETICHE (stile NetGescon) -->
|
|
<div class="grid gap-3 md:grid-cols-2 lg:grid-cols-4 mb-3">
|
|
<div class="col-span-1">
|
|
<div class="netgescon-card h-100">
|
|
<div class="netgescon-card-body">
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<div class="text-gray-500 uppercase text-sm">Stabili importati</div>
|
|
<div class="h3 mb-0">{{ number_format($stats['stabili']['totali']) }}</div>
|
|
<div class="text-sm text-gray-500 mt-1">Attivi: <strong>{{ $stats['stabili']['attivi'] }}</strong></div>
|
|
</div>
|
|
<span class="netgescon-badge netgescon-badge-primary"><i class="mdi mdi-home-group"></i></span>
|
|
</div>
|
|
</div>
|
|
<div class="netgescon-card-footer flex justify-end">
|
|
<a href="#stabili" onclick="showGesconTab('stabili'); return false;">Visualizza dettagli</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-span-1">
|
|
<div class="netgescon-card h-100">
|
|
<div class="netgescon-card-body">
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<div class="text-gray-500 uppercase text-sm">Unità immobiliari</div>
|
|
<div class="h3 mb-0">{{ number_format($stats['unita']['totali']) }}</div>
|
|
<div class="text-sm text-gray-500 mt-1">Con millesimi: <strong>{{ $stats['unita']['con_millesimi'] }}</strong></div>
|
|
</div>
|
|
<span class="netgescon-badge netgescon-badge-success"><i class="mdi mdi-home-variant"></i></span>
|
|
</div>
|
|
</div>
|
|
<div class="netgescon-card-footer flex justify-end">
|
|
<a href="#unita" onclick="showGesconTab('unita'); return false;">Visualizza dettagli</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-span-1">
|
|
<div class="netgescon-card h-100">
|
|
<div class="netgescon-card-body">
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<div class="text-gray-500 uppercase text-sm">Soggetti</div>
|
|
<div class="h3 mb-0">{{ number_format($stats['soggetti']['totali']) }}</div>
|
|
<div class="text-sm text-gray-500 mt-1">Proprietari: <strong>{{ $stats['soggetti']['proprietari'] }}</strong></div>
|
|
</div>
|
|
<span class="netgescon-badge netgescon-badge-info"><i class="mdi mdi-account-group"></i></span>
|
|
</div>
|
|
</div>
|
|
<div class="netgescon-card-footer flex justify-end">
|
|
<a href="#soggetti" onclick="showGesconTab('soggetti'); return false;">Visualizza dettagli</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-span-1">
|
|
<div class="netgescon-card h-100">
|
|
<div class="netgescon-card-body">
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<div class="text-gray-500 uppercase text-sm">Fornitori</div>
|
|
<div class="h3 mb-0">{{ number_format($stats['fornitori']['totali']) }}</div>
|
|
<div class="text-sm text-gray-500 mt-1">Attivi: <strong>{{ $stats['fornitori']['attivi'] }}</strong></div>
|
|
</div>
|
|
<span class="netgescon-badge netgescon-badge-warning"><i class="mdi mdi-store"></i></span>
|
|
</div>
|
|
</div>
|
|
<div class="netgescon-card-footer flex justify-end">
|
|
<a href="#fornitori" onclick="showGesconTab('fornitori'); return false;">Visualizza dettagli</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- INFORMAZIONI AMMINISTRATORE -->
|
|
<div class="mb-3">
|
|
<div class="">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-account-tie me-2"></i> Informazioni Amministratore</h3>
|
|
</div>
|
|
<div class="netgescon-card-body">
|
|
<div class="grid md:grid-cols-2 gap-4">
|
|
<div class="grid grid-cols-12 gap-2 items-center">
|
|
<div class="col-span-4 text-gray-600">Nome:</div>
|
|
<div class="col-span-8">{{ $amministratore->nome }} {{ $amministratore->cognome }}</div>
|
|
<div class="col-span-4 text-gray-600">Codice Univoco:</div>
|
|
<div class="col-span-8"><span class="netgescon-badge netgescon-badge-primary">{{ $amministratore->codice_univoco }}</span></div>
|
|
<div class="col-span-4 text-gray-600">Email Studio:</div>
|
|
<div class="col-span-8">{{ $amministratore->email_studio ?? 'Non specificata' }}</div>
|
|
</div>
|
|
<div class="grid grid-cols-12 gap-2 items-center">
|
|
<div class="col-span-4 text-gray-600">Denominazione Studio:</div>
|
|
<div class="col-span-8">{{ $amministratore->denominazione_studio ?? 'Non specificata' }}</div>
|
|
<div class="col-span-4 text-gray-600">Ultimo Accesso:</div>
|
|
<div class="col-span-8">{{ $amministratore->ultimo_accesso ? $amministratore->ultimo_accesso->format('d/m/Y H:i') : 'Mai' }}</div>
|
|
<div class="col-span-4 text-gray-600">Stato:</div>
|
|
<div class="col-span-8">
|
|
@if($amministratore->attivo)
|
|
<span class="netgescon-badge netgescon-badge-success">Attivo</span>
|
|
@else
|
|
<span class="netgescon-badge netgescon-badge-danger">Non attivo</span>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DATI RECENTI -->
|
|
<div class="grid md:grid-cols-2 gap-4">
|
|
<!-- Ultimi Stabili -->
|
|
<div class="">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header flex justify-between items-center">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-home-group me-2"></i> Ultimi Stabili Importati</h3>
|
|
<button type="button" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary" onclick="showGesconTab('stabili')">
|
|
<i class="mdi mdi-eye"></i> Vedi tutti
|
|
</button>
|
|
</div>
|
|
<div class="netgescon-card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Denominazione</th>
|
|
<th>Indirizzo</th>
|
|
<th>Unità</th>
|
|
<th>Data Import</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($datiRecenti['ultimi_stabili'] as $stabile)
|
|
<tr>
|
|
<td>
|
|
<strong>{{ $stabile->denominazione }}</strong>
|
|
@if($stabile->codice_interno)
|
|
<br><small class="text-gray-500">{{ $stabile->codice_interno }}</small>
|
|
@endif
|
|
</td>
|
|
<td>
|
|
{{ $stabile->indirizzo }}
|
|
@if($stabile->numero_civico)
|
|
{{ $stabile->numero_civico }}
|
|
@endif
|
|
<br>
|
|
<small class="text-gray-500">
|
|
{{ $stabile->cap }} {{ $stabile->citta ?? '' }} @if(!empty($stabile->provincia)) ({{ $stabile->provincia }}) @endif
|
|
</small>
|
|
</td>
|
|
<td>
|
|
<span class="netgescon-badge">{{ $stabile->numero_unita ?? 0 }}</span>
|
|
</td>
|
|
<td>
|
|
<small>{{ $stabile->created_at->format('d/m/Y H:i') }}</small>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="text-center text-gray-500 py-3">
|
|
Nessun stabile importato
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Ultime Unità -->
|
|
<div class="">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header flex justify-between items-center">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-home-variant me-2"></i> Ultime Unità Importate</h3>
|
|
<button type="button" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary" data-bs-toggle="tab" data-bs-target="#unita">
|
|
<i class="mdi mdi-eye"></i> Vedi tutte
|
|
</button>
|
|
</div>
|
|
<div class="netgescon-card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Codice</th>
|
|
<th>Stabile</th>
|
|
<th>Posizione</th>
|
|
<th>Superficie</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($datiRecenti['ultime_unita'] as $unita)
|
|
<tr>
|
|
<td>
|
|
<strong>{{ $unita->codice_unita }}</strong>
|
|
</td>
|
|
<td>
|
|
<small>{{ $unita->stabile->denominazione ?? 'N/A' }}</small>
|
|
</td>
|
|
<td>
|
|
@if($unita->scala)
|
|
Scala {{ $unita->scala }}
|
|
@endif
|
|
@if($unita->piano)
|
|
Piano {{ $unita->piano }}
|
|
@endif
|
|
@if($unita->interno)
|
|
Int. {{ $unita->interno }}
|
|
@endif
|
|
</td>
|
|
<td>
|
|
@if($unita->superficie)
|
|
{{ number_format($unita->superficie, 0) }} m²
|
|
@else
|
|
<span class="text-gray-500">N/D</span>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="text-center text-gray-500 py-3">
|
|
Nessuna unità importata
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- AZIONI RAPIDE + SYNC -->
|
|
<div class="mt-4 grid gap-4 lg:grid-cols-2">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-flash me-2"></i> Azioni Rapide Import</h3>
|
|
</div>
|
|
<div class="netgescon-card-body">
|
|
<div class="grid sm:grid-cols-2 gap-3">
|
|
<button type="button" class="netgescon-btn netgescon-btn-primary netgescon-btn-block" onclick="showGesconTab('stabili')">
|
|
<i class="mdi mdi-database-import me-1"></i>
|
|
Pipeline Import
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-primary netgescon-btn-block" onclick="showGesconTab('mapping')">
|
|
<i class="mdi mdi-table-link me-1"></i>
|
|
Mapping Campi
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-success netgescon-btn-block" onclick="showGesconTab('unita'); if(window.showImportUnitaModal){ window.showImportUnitaModal(); }">
|
|
<i class="mdi mdi-home-variant me-1"></i>
|
|
Import Unità
|
|
</button>
|
|
<a href="{{ route('admin.fornitori.index') }}" class="netgescon-btn netgescon-btn-warning netgescon-btn-block">
|
|
<i class="mdi mdi-store me-1"></i>
|
|
Gestione Fornitori
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header flex items-center justify-between">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-sync me-2"></i> Sincronizzazione Rapida</h3>
|
|
<span class="netgescon-badge netgescon-badge-info text-xs">Beta</span>
|
|
</div>
|
|
<div class="netgescon-card-body space-y-3">
|
|
<p class="text-sm text-gray-600">Apri il pannello di sincronizzazione per scegliere uno stabile legacy, abilitare l'auto-sync e lanciare la pipeline completa oppure i singoli step (Stabili, Unità, Soggetti, Diritti, Millesimi, Banche).</p>
|
|
<button type="button" class="netgescon-btn netgescon-btn-primary w-full" onclick="window.openSyncModal && window.openSyncModal()">
|
|
<i class="mdi mdi-refresh-circle me-1"></i>
|
|
Sincronizza intero stabile
|
|
</button>
|
|
<div class="text-xs text-gray-500">Hai a disposizione {{ number_format(count($legacyPreview ?? [])) }} codici legacy rilevati automaticamente.</div>
|
|
<div class="grid grid-cols-2 md:grid-cols-3 gap-2">
|
|
@foreach(['stabili' => 'Stabili', 'unita' => 'Unità', 'soggetti' => 'Soggetti', 'diritti' => 'Diritti', 'millesimi' => 'Millesimi', 'banche' => 'Banche'] as $actionKey => $label)
|
|
<button type="button" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary" data-prefill-action="{{ $actionKey }}" onclick="window.openSyncModal && window.openSyncModal('{{ $actionKey }}')">
|
|
<i class="mdi mdi-play-circle-outline me-1"></i>{{ $label }}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
<div class="text-xs text-gray-500">
|
|
Suggerimento: attiva la casella «Mantieni stabile sincronizzato» nel pannello per lasciare che NetGescon ripeta automaticamente l'allineamento quando rileva modifiche nell'archivio legacy.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- CHECKLIST MIGRAZIONI + MDB -->
|
|
<div class="mt-4">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header flex items-center justify-between">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-clipboard-check-outline me-2"></i> Checklist Migrazione & MDB</h3>
|
|
@if(!empty($legacyBasePath))
|
|
<span class="text-xs text-gray-500">Archivio base: <code>{{ $legacyBasePath }}</code></span>
|
|
@endif
|
|
</div>
|
|
<div class="netgescon-card-body text-sm text-gray-600 space-y-3">
|
|
<p>Prima di ogni sincronizzazione assicurati di aver eseguito i seguenti step. Questo riduce errori dovuti a schema non aggiornato o MDB non caricato.</p>
|
|
<ol class="list-decimal list-inside space-y-2">
|
|
<li>
|
|
<strong>Allinea il database applicativo</strong><br>
|
|
<code>php artisan migrate --force</code><br>
|
|
Garantisce che tutte le tabelle/relazioni richieste dalla pipeline siano presenti.
|
|
</li>
|
|
<li>
|
|
<strong>Carica lo staging da singolo_anno.mdb</strong><br>
|
|
<code>php artisan gescon:load-mdb --mdb=/percorso/singolo_anno.mdb --table=condomin --stabile=XXXX --truncate</code><br>
|
|
Usa il codice legacy corretto e il file dell'anno che vuoi importare. Ripeti per altre tabelle (rate, incassi, ecc.) se necessario.
|
|
</li>
|
|
<li>
|
|
<strong>Esegui la sincronizzazione desiderata</strong><br>
|
|
Usa i pulsanti sopra per scegliere fra sync completo o step specifici e monitora l'output per eventuali avvisi.
|
|
</li>
|
|
</ol>
|
|
<div class="bg-slate-50 border border-dashed border-slate-200 rounded p-3 text-xs text-slate-500">
|
|
Suggerimento: salva i percorsi MDB definitivi in <em>Configurazione Import</em> per evitare di reinserirli. Se lavori da shell, puoi usare il file <code>sync-complete-netgescon.sh</code> come riferimento.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- GESTIONE DOCUMENTALE: Documenti collegati recenti -->
|
|
<div class="mt-4">
|
|
<div class="">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header flex justify-between items-center">
|
|
<h3 class="card-title mb-0"><i class="mdi mdi-file-document-outline me-2"></i> Documenti Collegati recenti</h3>
|
|
@if(isset($amministratore))
|
|
<a class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-primary" href="{{ route('admin.stabili.index') }}">Vai a Stabili</a>
|
|
@endif
|
|
</div>
|
|
<div class="netgescon-card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Protocollo</th>
|
|
<th>Titolo</th>
|
|
<th>Tipo</th>
|
|
<th>Stabile</th>
|
|
<th>Scadenza</th>
|
|
<th class="text-end" style="width: 140px;">Azioni</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse(($datiRecenti['ultimi_documenti'] ?? []) as $doc)
|
|
<tr>
|
|
<td><code>{{ $doc->protocollo_formattato ?? ($doc->numero_protocollo ?? '—') }}</code></td>
|
|
<td>{{ $doc->titolo ?? '—' }}</td>
|
|
<td><span class="netgescon-badge text-uppercase">{{ $doc->tipo_documento ?? '—' }}</span></td>
|
|
<td>{{ $doc->stabile->denominazione ?? '—' }}</td>
|
|
<td>
|
|
@if($doc->data_scadenza)
|
|
<span class="netgescon-badge @switch($doc->stato_scadenza)
|
|
@case('scadenza_imminente') netgescon-badge-warning @break
|
|
@case('disdetta_imminente') netgescon-badge-danger @break
|
|
@case('scaduto') netgescon-badge-secondary @break
|
|
@default netgescon-badge-success @endswitch">
|
|
{{ $doc->data_scadenza->format('d/m/Y') }}
|
|
</span>
|
|
@else
|
|
<span class="text-gray-500">—</span>
|
|
@endif
|
|
</td>
|
|
<td class="text-end">
|
|
<a class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary" href="{{ route('admin.documenti-collegati.download', $doc->id) }}">
|
|
<i class="mdi mdi-download"></i>
|
|
Download
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="6" class="text-center text-gray-500 py-3">
|
|
Nessun documento collegato recente
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@php
|
|
$syncLegacyOptions = collect($legacyPreview ?? [])->map(function ($row) {
|
|
$legacy = is_array($row) ? ($row['legacy_code'] ?? null) : ($row->legacy_code ?? null);
|
|
$den = is_array($row) ? ($row['denominazione'] ?? null) : ($row->denominazione ?? null);
|
|
return [
|
|
'code' => trim((string)($legacy ?? '')),
|
|
'label' => trim((string)($den ?? '')),
|
|
];
|
|
})->filter(fn ($row) => $row['code'] !== '')->unique('code')->values()->take(600);
|
|
@endphp
|
|
|
|
<!-- Modal sincronizzazione rapida -->
|
|
<div id="sync-stabile-modal" class="fixed inset-0 bg-black/40 items-center justify-center p-4 hidden" style="z-index: 70;">
|
|
<div class="bg-white w-full max-w-4xl rounded-lg shadow-2xl">
|
|
<div class="px-5 py-3 border-b flex items-center justify-between">
|
|
<div>
|
|
<h4 class="text-lg font-semibold">Sincronizzazione GESCON</h4>
|
|
<p class="text-xs text-gray-500">Seleziona uno stabile legacy e scegli se eseguire il sync completo o i singoli step.</p>
|
|
</div>
|
|
<button type="button" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary" onclick="window.closeSyncModal && window.closeSyncModal()">
|
|
<i class="mdi mdi-close"></i>
|
|
</button>
|
|
</div>
|
|
<div class="p-5 space-y-4">
|
|
<div class="grid md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-600 mb-1">Codice legacy stabile</label>
|
|
<input type="text" id="sync-legacy-input" class="netgescon-input w-full" list="sync-legacy-datalist" placeholder="es. 0021" autocomplete="off">
|
|
<datalist id="sync-legacy-datalist">
|
|
@foreach($syncLegacyOptions as $opt)
|
|
<option value="{{ $opt['code'] }}">{{ $opt['code'] }}{{ $opt['label'] ? ' · '.$opt['label'] : '' }}</option>
|
|
@endforeach
|
|
</datalist>
|
|
<small class="text-xs text-slate-500">Sono mostrati i primi {{ number_format($syncLegacyOptions->count()) }} codici rilevati.</small>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-600 mb-1">Denominazione legacy</label>
|
|
<div id="sync-legacy-label" class="bg-slate-100 border border-dashed border-slate-200 rounded px-3 py-2 text-sm text-slate-600">—</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid md:grid-cols-2 gap-3">
|
|
<label class="inline-flex items-center gap-2 text-sm">
|
|
<input type="checkbox" id="sync-auto-checkbox" class="form-checkbox">
|
|
Mantieni stabile sincronizzato automaticamente
|
|
</label>
|
|
<label class="inline-flex items-center gap-2 text-sm">
|
|
<input type="checkbox" id="sync-dry-run" class="form-checkbox">
|
|
Esegui come Dry-run (non scrive in dominio)
|
|
</label>
|
|
</div>
|
|
<div class="grid md:grid-cols-2 gap-3">
|
|
<label class="inline-flex items-center gap-2 text-sm">
|
|
<input type="checkbox" id="sync-with-gestioni" class="form-checkbox" checked>
|
|
Includi gestioni e rate (solo sync completo)
|
|
</label>
|
|
<label class="inline-flex items-center gap-2 text-sm">
|
|
<input type="checkbox" id="sync-with-banche" class="form-checkbox" checked>
|
|
Includi banche/casse (solo sync completo)
|
|
</label>
|
|
</div>
|
|
<div class="grid md:grid-cols-3 gap-3">
|
|
<button type="button" class="netgescon-btn netgescon-btn-primary" data-sync-action="full">
|
|
<i class="mdi mdi-refresh-circle me-1"></i> Sync intero stabile
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="stabili">
|
|
<i class="mdi mdi-home-city-outline me-1"></i> Solo stabili
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="millesimi">
|
|
<i class="mdi mdi-chart-bell-curve me-1"></i> Millesimi
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="unita">
|
|
<i class="mdi mdi-home-variant-outline me-1"></i> Unità
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="soggetti">
|
|
<i class="mdi mdi-account-multiple-outline me-1"></i> Soggetti
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="diritti">
|
|
<i class="mdi mdi-vector-link me-1"></i> Diritti
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="banche">
|
|
<i class="mdi mdi-bank me-1"></i> Banche
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-secondary" data-sync-action="reports">
|
|
<i class="mdi mdi-file-chart me-1"></i> Solo log (dry)
|
|
</button>
|
|
<button type="button" class="netgescon-btn netgescon-btn-outline-dark" onclick="window.closeSyncModal && window.closeSyncModal()">
|
|
<i class="mdi mdi-close-circle-outline me-1"></i> Chiudi
|
|
</button>
|
|
</div>
|
|
<div id="sync-status" class="text-sm text-slate-600"></div>
|
|
<div id="sync-log-wrapper" class="hidden">
|
|
<pre id="sync-log" class="bg-gray-900 text-green-200 text-xs p-3 rounded max-h-72 overflow-auto"></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
window.GESCON_SYNC = Object.assign({
|
|
legacy: @json($syncLegacyOptions->toArray()),
|
|
syncStatus: @json($syncByLegacy ?? []),
|
|
routes: {
|
|
sync: @json(route('admin.gescon-import.sync')),
|
|
execute: @json(route('admin.gescon-import.execute')),
|
|
importUnita: @json(route('admin.gescon-import.import-unita')),
|
|
mappingSave: @json(route('admin.gescon-import.mapping.save')),
|
|
},
|
|
csrf: @json(csrf_token()),
|
|
}, window.GESCON_SYNC || {});
|
|
|
|
(function(){
|
|
const modal = document.getElementById('sync-stabile-modal');
|
|
const legacyInput = document.getElementById('sync-legacy-input');
|
|
const legacyLabel = document.getElementById('sync-legacy-label');
|
|
const autoCheckbox = document.getElementById('sync-auto-checkbox');
|
|
const dryCheckbox = document.getElementById('sync-dry-run');
|
|
const gestCheckbox = document.getElementById('sync-with-gestioni');
|
|
const bancheCheckbox = document.getElementById('sync-with-banche');
|
|
const statusBox = document.getElementById('sync-status');
|
|
const logWrapper = document.getElementById('sync-log-wrapper');
|
|
const logPre = document.getElementById('sync-log');
|
|
let pendingAction = null;
|
|
|
|
function legacyMeta(code){
|
|
if (!code) return null;
|
|
const list = window.GESCON_SYNC.legacy || [];
|
|
return list.find(row => row.code === code) || null;
|
|
}
|
|
|
|
function updateLegacyLabel(){
|
|
const code = legacyInput.value.trim();
|
|
const meta = legacyMeta(code);
|
|
legacyLabel.textContent = meta && meta.label ? meta.label : (code ? '—' : 'Seleziona un codice');
|
|
autoCheckbox.checked = Boolean(window.GESCON_SYNC.syncStatus && window.GESCON_SYNC.syncStatus[code]);
|
|
}
|
|
|
|
window.openSyncModal = function(prefill){
|
|
pendingAction = prefill || null;
|
|
modal.classList.remove('hidden');
|
|
modal.classList.add('flex');
|
|
statusBox.textContent = pendingAction ? `Azione selezionata: ${pendingAction}` : '';
|
|
logWrapper.classList.add('hidden');
|
|
logPre.textContent = '';
|
|
updateLegacyLabel();
|
|
};
|
|
|
|
window.closeSyncModal = function(){
|
|
modal.classList.remove('flex');
|
|
modal.classList.add('hidden');
|
|
};
|
|
|
|
legacyInput && legacyInput.addEventListener('change', updateLegacyLabel);
|
|
legacyInput && legacyInput.addEventListener('blur', updateLegacyLabel);
|
|
|
|
autoCheckbox && autoCheckbox.addEventListener('change', async function(){
|
|
const code = legacyInput.value.trim();
|
|
if (!code) {
|
|
alert('Seleziona un codice legacy prima di abilitare la sincronizzazione automatica.');
|
|
autoCheckbox.checked = !autoCheckbox.checked;
|
|
return;
|
|
}
|
|
try {
|
|
const fd = new FormData();
|
|
fd.append('_mapping_only', '1');
|
|
fd.append('_legacy_code', code);
|
|
fd.append('sync_enabled', autoCheckbox.checked ? '1' : '0');
|
|
await fetch(window.GESCON_SYNC.routes.mappingSave, {
|
|
method: 'POST',
|
|
headers: { 'X-CSRF-TOKEN': window.GESCON_SYNC.csrf },
|
|
body: fd,
|
|
});
|
|
window.GESCON_SYNC.syncStatus = window.GESCON_SYNC.syncStatus || {};
|
|
window.GESCON_SYNC.syncStatus[code] = autoCheckbox.checked;
|
|
statusBox.textContent = 'Preferenza auto-sync aggiornata';
|
|
} catch (err) {
|
|
console.error(err);
|
|
alert('Errore durante il salvataggio della preferenza auto-sync.');
|
|
}
|
|
});
|
|
|
|
function appendLog(line){
|
|
logWrapper.classList.remove('hidden');
|
|
logPre.textContent += line + '\n';
|
|
logPre.scrollTop = logPre.scrollHeight;
|
|
}
|
|
|
|
async function handleSyncAction(action){
|
|
const code = legacyInput.value.trim();
|
|
if (!code) {
|
|
alert('Inserisci un codice legacy valido.');
|
|
return;
|
|
}
|
|
statusBox.textContent = `Esecuzione ${action} in corso...`;
|
|
logWrapper.classList.remove('hidden');
|
|
logPre.textContent = '';
|
|
try {
|
|
let response;
|
|
if (action === 'full') {
|
|
const fd = new FormData();
|
|
fd.append('legacy_code', code);
|
|
fd.append('dry', dryCheckbox.checked ? '1' : '0');
|
|
fd.append('with_gestioni', gestCheckbox.checked ? '1' : '0');
|
|
fd.append('with_banche', bancheCheckbox.checked ? '1' : '0');
|
|
response = await fetch(window.GESCON_SYNC.routes.sync, {
|
|
method: 'POST',
|
|
headers: { 'X-CSRF-TOKEN': window.GESCON_SYNC.csrf, 'Accept': 'application/json' },
|
|
body: fd,
|
|
});
|
|
const data = await response.json();
|
|
if (!data.ok) throw new Error(data.error || 'Sync fallito');
|
|
appendLog(JSON.stringify(data, null, 2));
|
|
} else if (['stabili', 'millesimi', 'banche'].includes(action)) {
|
|
const fd = new FormData();
|
|
fd.append('_ajax', '1');
|
|
fd.append('tipo_import', 'stabili');
|
|
fd.append('legacy_code', code);
|
|
fd.append('solo', action);
|
|
fd.append('test_mode', dryCheckbox.checked ? '1' : '0');
|
|
response = await fetch(window.GESCON_SYNC.routes.execute, {
|
|
method: 'POST',
|
|
headers: { 'X-CSRF-TOKEN': window.GESCON_SYNC.csrf, 'Accept': 'application/json', 'X-Requested-With': 'XMLHttpRequest' },
|
|
body: fd,
|
|
});
|
|
const text = await response.text();
|
|
appendLog(text.slice(0, 4000));
|
|
if (!response.ok) throw new Error('Import non completato');
|
|
} else if (['unita', 'soggetti', 'diritti'].includes(action)) {
|
|
const payload = {
|
|
legacy_code: code,
|
|
steps: [action],
|
|
dry_run: dryCheckbox.checked,
|
|
};
|
|
response = await fetch(window.GESCON_SYNC.routes.importUnita, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRF-TOKEN': window.GESCON_SYNC.csrf,
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify(payload),
|
|
});
|
|
const data = await response.json();
|
|
appendLog(JSON.stringify(data, null, 2));
|
|
if (!data.ok) throw new Error('Pipeline unità con errori');
|
|
} else if (action === 'reports') {
|
|
appendLog('Nessuna azione eseguita. Usa questa voce per annotare note durante i dry-run.');
|
|
} else {
|
|
appendLog('Azione non riconosciuta.');
|
|
}
|
|
statusBox.textContent = `Azione ${action} completata.`;
|
|
} catch (err) {
|
|
console.error(err);
|
|
statusBox.textContent = 'Errore: ' + err.message;
|
|
appendLog('Errore: ' + err.message);
|
|
}
|
|
}
|
|
|
|
document.querySelectorAll('#sync-stabile-modal [data-sync-action]').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
const action = btn.getAttribute('data-sync-action');
|
|
handleSyncAction(action);
|
|
});
|
|
});
|
|
})();
|
|
</script>
|