netgescon-day0/resources/views/admin/gescon-import/index.blade.php

321 lines
16 KiB
PHP
Executable File

@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