321 lines
16 KiB
PHP
321 lines
16 KiB
PHP
@extends('admin.layouts.netgescon')
|
|
|
|
@section('title', 'GESCON Import')
|
|
|
|
@section('breadcrumb')
|
|
<span>GESCON Import</span>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="content-wrapper">
|
|
|
|
<!-- BREADCRUMB + PAGE HEADER -->
|
|
<div class="px-6">
|
|
@include('components.layout.alerts')
|
|
@php
|
|
$canSwitchAmministratore = $canSwitchAmministratore ?? false;
|
|
$selectedAmministratoreId = $selectedAmministratoreId ?? ($amministratore->id ?? null);
|
|
$amministratoriDisponibili = $amministratoriDisponibili ?? collect();
|
|
if (!($amministratoriDisponibili instanceof \Illuminate\Support\Collection)) {
|
|
$amministratoriDisponibili = collect($amministratoriDisponibili);
|
|
}
|
|
$hasStabiliData = ($stats['stabili_totali'] ?? 0) > 0 || ($stats['stabili_gescon'] ?? 0) > 0;
|
|
$showImportUi = $hasStabiliData || $canSwitchAmministratore;
|
|
@endphp
|
|
|
|
@if($canSwitchAmministratore && $amministratoriDisponibili->count())
|
|
<form method="get" action="{{ route('admin.gescon-import.index') }}" class="netgescon-card p-4 mb-4 flex flex-wrap items-end gap-3">
|
|
@foreach(request()->query() as $paramName => $paramValue)
|
|
@if($paramName === 'amministratore_id')
|
|
@continue
|
|
@endif
|
|
@if(is_array($paramValue))
|
|
@foreach($paramValue as $value)
|
|
<input type="hidden" name="{{ $paramName }}[]" value="{{ $value }}">
|
|
@endforeach
|
|
@else
|
|
<input type="hidden" name="{{ $paramName }}" value="{{ $paramValue }}">
|
|
@endif
|
|
@endforeach
|
|
<div class="flex flex-col min-w-[240px]">
|
|
<label class="text-sm font-semibold text-slate-600 mb-1">Amministratore destinatario</label>
|
|
<select name="amministratore_id" class="netgescon-input" style="min-width: 260px;" onchange="this.form.submit()">
|
|
@foreach($amministratoriDisponibili as $amm)
|
|
@php
|
|
$label = trim($amm->denominazione_studio ?? '');
|
|
if ($label === '') {
|
|
$nome = trim($amm->nome ?? '');
|
|
$cognome = trim($amm->cognome ?? '');
|
|
$label = trim($nome . ' ' . $cognome);
|
|
}
|
|
if ($label === '') {
|
|
$label = 'Amministratore #' . $amm->id;
|
|
}
|
|
@endphp
|
|
<option value="{{ $amm->id }}" @selected($selectedAmministratoreId === $amm->id)>{{ $label }} (ID {{ $amm->id }})</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="text-xs text-slate-500 max-w-xs">
|
|
Seleziona l'amministratore su cui registrare gli stabili e i dati importati. La scelta resta salvata per le prossime sessioni.
|
|
</div>
|
|
</form>
|
|
@elseif($canSwitchAmministratore && !$amministratoriDisponibili->count())
|
|
<div class="netgescon-card p-4 mb-4">
|
|
<h2 class="text-lg font-semibold mb-2 text-red-600">Nessun amministratore configurato</h2>
|
|
<p class="text-gray-600 text-sm">Crea o abilita almeno un amministratore dal pannello Super Admin per poter procedere con l'importazione.</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if($showImportUi)
|
|
@include('admin.gescon-import.partials.menu')
|
|
<div class="flex flex-wrap items-center gap-3 mb-4">
|
|
<a href="{{ route('admin.gescon-import.occupazione') }}" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-primary">
|
|
<i class="mdi mdi-account-multiple-outline me-1"></i>
|
|
Vista Condomini / Inquilini (QA)
|
|
</a>
|
|
{{-- Link disabilitato: route non presente in dev --}}
|
|
<a href="{{ route('admin.gescon-import.anagrafiche') }}" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary">
|
|
<i class="mdi mdi-format-list-bulleted"></i>
|
|
Elenco anagrafiche importate
|
|
</a>
|
|
<form method="post" action="{{ route('admin.gescon-import.auto-sync-anagrafiche') }}" class="flex items-center gap-2">
|
|
@csrf
|
|
<input type="text" name="stabile" value="{{ request('legacy_code') ?? request('stabile') ?? '' }}" class="netgescon-input netgescon-input-sm w-28" placeholder="Stabile">
|
|
<input type="number" name="limit" value="5000" min="100" max="20000" class="netgescon-input netgescon-input-sm w-24" title="Limite record">
|
|
<button type="submit" class="netgescon-btn netgescon-btn-sm netgescon-btn-primary">
|
|
<i class="mdi mdi-sync"></i> Sync anagrafiche
|
|
</button>
|
|
</form>
|
|
<form method="post" action="{{ route('admin.gescon-import.sync-millesimi') }}" class="flex items-center gap-2">
|
|
@csrf
|
|
<input type="text" name="stabile" value="{{ request('legacy_code') ?? request('stabile') ?? '' }}" class="netgescon-input netgescon-input-sm w-24" placeholder="Stabile" required>
|
|
<input type="number" name="limit" value="" min="100" max="20000" class="netgescon-input netgescon-input-sm w-20" title="Limite opzionale">
|
|
<label class="flex items-center gap-1 text-xs text-slate-600">
|
|
<input type="checkbox" name="dry_run" value="1"> Dry-run
|
|
</label>
|
|
<button type="submit" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-primary">
|
|
<i class="mdi mdi-table-sync"></i> Sync millesimi
|
|
</button>
|
|
</form>
|
|
<form method="post" action="{{ route('admin.gescon-import.cleanup-unita-zero') }}" class="flex items-center gap-2">
|
|
@csrf
|
|
<button type="submit" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-danger" onclick="return confirm('Cancellare unità con codice nullo/0?')">
|
|
<i class="mdi mdi-delete"></i> Pulisci unità 0/null
|
|
</button>
|
|
</form>
|
|
<span class="text-xs text-slate-500">Anteprima rapida di proprietari e inquilini per stabile, utile dopo ogni import.</span>
|
|
</div>
|
|
@if(!$hasStabiliData)
|
|
<div class="netgescon-card p-4 mt-3">
|
|
<h2 class="text-lg font-semibold mb-2">Primo importo per {{ $amministratore->denominazione_studio ?? ($amministratore->nome ?? 'l\'amministratore selezionato') }}</h2>
|
|
<p class="text-gray-600 text-sm">Nessuno stabile è ancora presente in NetGescon. Seleziona un codice legacy dalla colonna di sinistra e avvia il Dry-run per verificare l'importazione prima di procedere definitivamente.</p>
|
|
</div>
|
|
@endif
|
|
@else
|
|
<div class="netgescon-card p-4">
|
|
<h2 class="text-lg font-semibold mb-2">Benvenuto in GESCON Import</h2>
|
|
<p class="text-gray-600">Per iniziare, imposta la sorgente degli archivi e i file MDB oppure procedi con il mapping se la sorgente è già accessibile.</p>
|
|
<div class="flex items-center gap-3 mt-3 flex-wrap">
|
|
@can('gescon-import.config')
|
|
<a href="{{ route('admin.gescon-import.config') }}" class="netgescon-btn netgescon-netgescon-btn netgescon-btn-primary">
|
|
<i class="mdi mdi-cog"></i> Vai a Configurazione Import
|
|
</a>
|
|
@endcan
|
|
@cannot('gescon-import.config')
|
|
<a href="{{ route('admin.gescon-import.index') }}#mapping" class="netgescon-btn netgescon-netgescon-btn netgescon-btn-outline-primary">
|
|
<i class="mdi mdi-link-variant"></i> Apri Mapping Campi
|
|
</a>
|
|
<span class="text-sm text-slate-500">Se gli archivi non sono leggibili, chiedi al Super Admin di completare la Configurazione.</span>
|
|
@endcannot
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
<!-- MAIN CONTENT AREA -->
|
|
<section class="content">
|
|
<div class="px-6">
|
|
<div class="tab-content" id="gescon-tab-content">
|
|
|
|
@if($showImportUi)
|
|
<!-- DASHBOARD TAB -->
|
|
<div class="tab-pane fade show active" id="dashboard" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.dashboard', [
|
|
'stats' => $stats,
|
|
'datiRecenti' => $datiRecenti,
|
|
'amministratore' => $amministratore,
|
|
'legacyPreview' => $legacyPreview ?? [],
|
|
'syncByLegacy' => $syncByLegacy ?? [],
|
|
'legacyBasePath' => $legacyBasePath ?? null,
|
|
])
|
|
</div>
|
|
@endif
|
|
|
|
<!-- STABILI TAB -->
|
|
@if($showImportUi)
|
|
<div class="tab-pane fade" id="stabili" role="tabpanel">
|
|
@php
|
|
$activeSection = request()->get('sec', 'anagrafica');
|
|
$activeItem = request()->get('item', 'stabili');
|
|
@endphp
|
|
<div class="px-6 mb-2">
|
|
<a href="{{ route('admin.gescon-import.index', array_merge(request()->query(), ['refresh' => 1])) }}#stabili" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary">
|
|
<i class="mdi mdi-refresh"></i> Ricarica elenco legacy
|
|
</a>
|
|
</div>
|
|
@if($activeSection === 'anagrafica' && $activeItem === 'stabili')
|
|
@include('admin.gescon-import.partials.stabili-dual-pane')
|
|
@else
|
|
@include('admin.gescon-import.tabs.stabili')
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
<!-- SOGGETTI TAB -->
|
|
@if(($stats['stabili_totali'] ?? 0) > 0)
|
|
<div class="tab-pane fade" id="soggetti" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.soggetti')
|
|
</div>
|
|
@endif
|
|
|
|
<!-- COMUNI TAB -->
|
|
<div class="tab-pane fade" id="comuni" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.comuni')
|
|
</div>
|
|
|
|
<!-- UNITA TAB (sempre visibile per onboarding/import Unità) -->
|
|
<div class="tab-pane fade" id="unita" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.unita')
|
|
@include('admin.gescon-import.partials.unita-field-mapping')
|
|
</div>
|
|
|
|
<!-- FORNITORI TAB -->
|
|
@if(($stats['stabili_totali'] ?? 0) > 0)
|
|
<div class="tab-pane fade" id="fornitori" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.fornitori')
|
|
</div>
|
|
@endif
|
|
|
|
<!-- TABELLE MILLESIMALI TAB -->
|
|
@if(($stats['stabili_totali'] ?? 0) > 0)
|
|
<div class="tab-pane fade" id="tabelle" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.tabelle')
|
|
</div>
|
|
@endif
|
|
|
|
<!-- VOCI TAB -->
|
|
@if(($stats['stabili_totali'] ?? 0) > 0)
|
|
<div class="tab-pane fade" id="voci" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.voci')
|
|
</div>
|
|
@endif
|
|
|
|
<!-- BANCHE TAB -->
|
|
@if(($stats['stabili_totali'] ?? 0) > 0)
|
|
<div class="tab-pane fade" id="banche" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.banche')
|
|
</div>
|
|
@endif
|
|
|
|
<!-- MAPPING UNITA/ANAGRAFICHE TAB -->
|
|
<div class="tab-pane fade" id="mapping-unita" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.unita-mapping')
|
|
</div>
|
|
|
|
<!-- REPORTS TAB -->
|
|
@if(($stats['stabili_totali'] ?? 0) > 0)
|
|
<div class="tab-pane fade" id="reports" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.reports')
|
|
</div>
|
|
@endif
|
|
|
|
<!-- MAPPING TAB (sempre disponibile: serve anche in onboarding) -->
|
|
<div class="tab-pane fade" id="mapping" role="tabpanel">
|
|
@include('admin.gescon-import.tabs.mapping')
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('module-styles')
|
|
<style>
|
|
/* Typography alignment with Contabilità page */
|
|
.content-wrapper h1, .content-wrapper h2, .content-wrapper h3 { color: var(--netgescon-gray-900); }
|
|
.content-wrapper p { color: var(--netgescon-gray-600); }
|
|
/* Card look */
|
|
.netgescon-card { border: 1px solid var(--netgescon-gray-200); border-radius: .75rem; box-shadow: var(--netgescon-shadow); background: #fff; }
|
|
.netgescon-card + .netgescon-card { margin-top: 1rem; }
|
|
.stats-card {
|
|
transition: transform 0.2s;
|
|
}
|
|
.stats-card:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
.import-status {
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
}
|
|
.data-table-wrapper {
|
|
background: white;
|
|
border-radius: 0.375rem;
|
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
}
|
|
/* Tabs stile NetGescon (coerente con pagina Stabili) */
|
|
.nav-tabs { display: flex; flex-wrap: wrap; gap: .5rem; border-bottom: 1px solid var(--netgescon-gray-200); }
|
|
.nav-tabs .nav-link { padding: .5rem .75rem; border: 0; border-bottom: 2px solid transparent; color: #6b7280; border-radius: .25rem .25rem 0 0; }
|
|
.nav-tabs .nav-link:hover { color: #1f2937; border-bottom-color: #d1d5db; }
|
|
.nav-tabs .nav-link.active { color: #2563eb; border-bottom-color: #3b82f6; background: transparent; }
|
|
/* Avoid Bootstrap-like .table overrides to keep QA clean */
|
|
/* Ensure only the active tab pane is visible without relying on Bootstrap CSS */
|
|
#gescon-tab-content > .tab-pane { display: none; }
|
|
#gescon-tab-content > .tab-pane.show.active { display: block; }
|
|
/* Menus sizing: main vs submenu */
|
|
.netgescon-mainmenu a { font-size: .92rem; font-weight: 600; }
|
|
.netgescon-submenu a { font-size: .85rem; }
|
|
.netgescon-submenu { margin-top: .25rem; }
|
|
</style>
|
|
@endsection
|
|
|
|
@section('module-scripts')
|
|
<script>
|
|
window.GESCON_MAPPING = window.GESCON_MAPPING || {};
|
|
const __baseRoutes = {
|
|
stagingColumns: @json(route('admin.gescon-import.staging-columns')),
|
|
stagingTableColumns: @json(route('admin.gescon-import.staging-table-columns')),
|
|
createTargetColumns: @json(route('admin.gescon-import.create-target-columns')),
|
|
mappingSave: @json(route('admin.gescon-import.mapping.save')),
|
|
years: @json(route('admin.gescon-import.years')),
|
|
unitaYear: @json(route('admin.gescon-import.unita-year')),
|
|
importUnita: @json(route('admin.gescon-import.import-unita'))
|
|
};
|
|
window.GESCON_MAPPING.routes = Object.assign({}, __baseRoutes, window.GESCON_MAPPING.routes || {});
|
|
window.GESCON_MAPPING.csrf = window.GESCON_MAPPING.csrf || @json(csrf_token());
|
|
</script>
|
|
@vite('resources/js/admin/gescon-import-mapping.js')
|
|
<script>
|
|
// Gestore minimale di tab basato su hash (#dashboard, #stabili, #soggetti, #unita, #fornitori, #reports, #mapping)
|
|
function showGesconTab(tabId) {
|
|
var target = document.getElementById(tabId);
|
|
if (!target) return;
|
|
document.querySelectorAll('#gescon-tab-content > .tab-pane').forEach(function(p){ p.classList.remove('show','active'); });
|
|
target.classList.add('show','active');
|
|
try { history.replaceState({}, '', '#' + tabId); } catch(_) {}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function(){
|
|
var initial = (location.hash || '#dashboard').replace('#','');
|
|
if (!document.getElementById(initial)) initial = 'dashboard';
|
|
showGesconTab(initial);
|
|
window.addEventListener('hashchange', function(){
|
|
var id = (location.hash || '#dashboard').replace('#','');
|
|
showGesconTab(id);
|
|
});
|
|
window.showGesconTab = showGesconTab;
|
|
});
|
|
</script>
|
|
@endsection
|