390 lines
20 KiB
PHP
390 lines
20 KiB
PHP
{{-- Semplifica: rimuoviamo la sezione duplicata e lavoriamo sulla card sottostante --}}
|
|
@php
|
|
$legacyCode = request('legacy_code');
|
|
$mapping = null;
|
|
if ($legacyCode) {
|
|
$mapping = \App\Models\GesconImportMapping::where('user_id', auth()->id())
|
|
->where('legacy_code', $legacyCode)
|
|
->first();
|
|
}
|
|
$stabileCurrent = $stabileCurrent ?? null;
|
|
$gestioneCurrent = $gestioneCurrent ?? null;
|
|
if (!$stabileCurrent && $mapping) {
|
|
try {
|
|
$candidate = $mapping->stabile;
|
|
} catch (\Throwable $e) {
|
|
$candidate = null;
|
|
}
|
|
if ($candidate) {
|
|
$stabileCurrent = $candidate;
|
|
}
|
|
}
|
|
if (!$stabileCurrent && $legacyCode) {
|
|
try {
|
|
$candidates = [];
|
|
if (\Illuminate\Support\Facades\Schema::hasColumn('stabili', 'codice_stabile')) { $candidates[] = 'codice_stabile'; }
|
|
if (\Illuminate\Support\Facades\Schema::hasColumn('stabili', 'codice_interno')) { $candidates[] = 'codice_interno'; }
|
|
if (\Illuminate\Support\Facades\Schema::hasColumn('stabili', 'old_id')) { $candidates[] = 'old_id'; }
|
|
if (!empty($candidates)) {
|
|
$stabileCurrent = \App\Models\Stabile::where(function ($q) use ($candidates, $legacyCode) {
|
|
foreach ($candidates as $idx => $col) {
|
|
$method = $idx === 0 ? 'where' : 'orWhere';
|
|
$q->{$method}($col, $legacyCode);
|
|
}
|
|
})->first();
|
|
}
|
|
if (!$stabileCurrent) {
|
|
$stabileCurrent = \App\Models\Stabile::where('denominazione', 'like', $legacyCode . '%')->first();
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$stabileCurrent = null;
|
|
}
|
|
}
|
|
if (!$gestioneCurrent && $stabileCurrent) {
|
|
try {
|
|
$gestioneCurrent = \App\Models\GestioneContabile::where('stabile_id', $stabileCurrent->id)
|
|
->orderByDesc('gestione_attiva')
|
|
->orderByDesc('anno_gestione')
|
|
->orderBy('tipo_gestione')
|
|
->orderByDesc('numero_straordinaria')
|
|
->first();
|
|
} catch (\Throwable $e) {
|
|
$gestioneCurrent = null;
|
|
}
|
|
}
|
|
$isSuper = $isSuper ?? (auth()->user()?->hasRole('super-admin') ?? false);
|
|
if (!isset($blockMappingUi)) {
|
|
$blockMappingUi = !$stabileCurrent && !$isSuper;
|
|
}
|
|
$globalMapping = \App\Models\GesconImportMapping::where('user_id', auth()->id())
|
|
->where(function($q){ $q->whereNull('legacy_code')->orWhere('legacy_code','*'); })
|
|
->orderByDesc('updated_at')
|
|
->first();
|
|
// Elenco stabili legacy per selezione rapida (riusa $legacyPreview passato dalla vista index)
|
|
$legacyOptions = $legacyPreview ?? [];
|
|
// 1) Preferisci Stabili.mdb per i campi legacy; fallback al dataset
|
|
$legacyFields = [];
|
|
$legacySource = null;
|
|
try {
|
|
$hasMdb = trim((string)@shell_exec('command -v mdb-export')) !== '';
|
|
$mdbPath = \App\Models\UserSetting::get('gescon.mdb_stabili');
|
|
if (!$mdbPath || !@is_file($mdbPath) || !@is_readable($mdbPath)) {
|
|
$legacyArchivePath = '/mnt/gescon-archives/gescon/dbc/STABILI.mdb';
|
|
if (@is_file($legacyArchivePath) && @is_readable($legacyArchivePath)) {
|
|
$mdbPath = $legacyArchivePath;
|
|
} else {
|
|
$storageFallback = '/var/www/netgescon/storage/gescon/Stabili.mdb';
|
|
if (@is_file($storageFallback) && @is_readable($storageFallback)) { $mdbPath = $storageFallback; }
|
|
}
|
|
}
|
|
if ($hasMdb && $mdbPath && @is_file($mdbPath)) {
|
|
$binTables = trim((string)@shell_exec('command -v mdb-tables')) ?: '/usr/bin/mdb-tables';
|
|
$binExport = trim((string)@shell_exec('command -v mdb-export')) ?: '/usr/bin/mdb-export';
|
|
$tables = @shell_exec(sprintf('%s -1 %s 2>/dev/null', escapeshellarg($binTables), escapeshellarg($mdbPath))) ?: '';
|
|
$tableGuess = 'Stabili';
|
|
if ($tables) {
|
|
foreach (preg_split('/\r?\n/', trim($tables)) as $t) { if ($t === '') continue; if (preg_match('/stabil/i', $t)) { $tableGuess = trim($t); break; } }
|
|
}
|
|
$tmp = tempnam(sys_get_temp_dir(), 'mdbcsv_');
|
|
$cmd = sprintf('%s -D %s -d %s -q %s -R "\\n" %s %s > %s 2>/dev/null',
|
|
escapeshellarg($binExport), escapeshellarg('%Y-%m-%d'), escapeshellarg('|'), escapeshellarg('"'),
|
|
escapeshellarg($mdbPath), escapeshellarg($tableGuess), escapeshellarg($tmp));
|
|
@shell_exec($cmd);
|
|
if (@filesize($tmp) > 0) {
|
|
$fh = fopen($tmp, 'r');
|
|
$headers = fgetcsv($fh, 0, '|');
|
|
fclose($fh);
|
|
@unlink($tmp);
|
|
$headers = $headers ? array_map(fn($h) => strtolower(trim((string)$h)), $headers) : [];
|
|
$preferred = ['denominazione','indirizzo','numero_civico','cap','comune','provincia','codice_fiscale','cod_fisc_amministratore','codice_comune_catasto','foglio_catasto','particella_catasto','ac_foglio','ac_particella','ac_sub','ac_categoria','ac_classe','ac_consistenza','ac_rendita'];
|
|
$keys = array_values(array_unique(array_merge($preferred, $headers)));
|
|
foreach ($keys as $k) { if ($k === '' || $k === null) continue; $legacyFields[] = ['name' => ucwords(str_replace(['_','-'],' ', (string)$k)), 'key' => (string)$k]; }
|
|
$legacySource = 'mdb';
|
|
} else { @unlink($tmp); }
|
|
}
|
|
} catch (\Throwable $e) { /* fallback below */ }
|
|
if (empty($legacyFields)) {
|
|
try {
|
|
$ds = \App\Models\MigrationDataset::where('key','stabili')->orderByDesc('updated_at')->first();
|
|
$sample = $ds ? \App\Models\MigrationRecord::where('dataset_id', $ds->id)
|
|
->when($legacyCode, function($q) use ($legacyCode){ $q->where('legacy_key', $legacyCode); })
|
|
->orderBy('id')->first() : null;
|
|
$keys = array_keys((array)($sample?->data ?? []));
|
|
$preferred = ['denominazione','indirizzo','numero_civico','cap','comune','provincia','codice_fiscale','cod_fisc_amministratore','codice_comune_catasto','foglio_catasto','particella_catasto','ac_foglio','ac_particella','ac_sub','ac_categoria','ac_classe','ac_consistenza','ac_rendita'];
|
|
$keys = array_values(array_unique(array_merge($preferred, $keys)));
|
|
foreach ($keys as $k) { if ($k === '' || $k === null) continue; $legacyFields[] = ['name' => ucwords(str_replace(['_','-'],' ', (string)$k)), 'key' => (string)$k]; }
|
|
$legacySource = 'dataset';
|
|
} catch (\Throwable $e) {
|
|
$legacyFields = [
|
|
['name' => 'Denominazione', 'key' => 'denominazione'],
|
|
['name' => 'Indirizzo', 'key' => 'indirizzo'],
|
|
['name' => 'CAP', 'key' => 'cap'],
|
|
['name' => 'Comune', 'key' => 'comune'],
|
|
['name' => 'Provincia', 'key' => 'provincia'],
|
|
['name' => 'CF Stabile', 'key' => 'codice_fiscale'],
|
|
['name' => 'CF Amministratore', 'key' => 'cod_fisc_amministratore'],
|
|
];
|
|
$legacySource = 'static';
|
|
}
|
|
}
|
|
// 1b) Unisci eventuali colonne da tabelle sorgente avanzate (configurate dal Super Admin)
|
|
try {
|
|
$srcConn = \App\Models\UserSetting::get('gescon.source_conn');
|
|
$srcTablesRaw = \App\Models\UserSetting::get('gescon.source_tables');
|
|
$srcTables = [];
|
|
if (is_string($srcTablesRaw) && $srcTablesRaw !== '') {
|
|
$decoded = null; try { $decoded = json_decode($srcTablesRaw, true, 512, JSON_THROW_ON_ERROR); } catch (\Throwable $e) { $decoded = null; }
|
|
if (is_array($decoded)) { $srcTables = array_values(array_filter(array_map('strval', $decoded))); }
|
|
else { $srcTables = array_values(array_filter(array_map('trim', explode(',', $srcTablesRaw)))); }
|
|
}
|
|
$conn = $srcConn ?: 'gescon_import';
|
|
if (!empty($srcTables) && \Illuminate\Support\Facades\DB::connection($conn)) {
|
|
foreach ($srcTables as $t) {
|
|
try {
|
|
if (!\Illuminate\Support\Facades\Schema::connection($conn)->hasTable($t)) continue;
|
|
$cols = \Illuminate\Support\Facades\Schema::connection($conn)->getColumnListing($t);
|
|
foreach ($cols as $col) {
|
|
$key = $t.'.'.$col; $label = strtoupper($t).' • '.str_replace('_',' ', $col);
|
|
$legacyFields[] = ['name' => $label, 'key' => $key];
|
|
}
|
|
} catch (\Throwable $e) { /* ignore */ }
|
|
}
|
|
}
|
|
// dedup mantenendo ordine
|
|
$seen = [];
|
|
$legacyFields = array_values(array_filter($legacyFields, function($f) use (&$seen){ $k = $f['key']; if(isset($seen[$k])) return false; $seen[$k]=1; return true; }));
|
|
} catch (\Throwable $e) { /* ignore */ }
|
|
|
|
$targetFields = [
|
|
// Identificazione e indirizzo
|
|
'stabile.denominazione' => 'Stabile → Denominazione',
|
|
'stabile.codice_interno' => 'Stabile → Codice Interno',
|
|
'stabile.indirizzo' => 'Stabile → Indirizzo',
|
|
'stabile.numero_civico' => 'Stabile → Numero Civico',
|
|
'stabile.scala' => 'Stabile → Scala',
|
|
'stabile.cap' => 'Stabile → CAP',
|
|
'stabile.comune_id' => 'Stabile → Comune (ID)',
|
|
'stabile.comune_cod' => 'Stabile → Comune (cod legacy)',
|
|
'stabile.provincia' => 'Stabile → Provincia',
|
|
'stabile.regione' => 'Stabile → Regione',
|
|
// Dati amministratore
|
|
'stabile.cod_fisc_amministratore' => 'Stabile → CF Amministratore',
|
|
// Dati catastali
|
|
'stabile.codice_comune_catasto' => 'Stabile → Catasto: Codice Comune',
|
|
'stabile.foglio' => 'Stabile → Catasto: Foglio',
|
|
'stabile.foglio_catasto' => 'Stabile → Catasto: Foglio (campo dedicato)',
|
|
'stabile.particella' => 'Stabile → Catasto: Particella',
|
|
'stabile.particella_catasto' => 'Stabile → Catasto: Particella (campo dedicato)',
|
|
'stabile.mappale' => 'Stabile → Catasto: Mappale',
|
|
'stabile.subalterno' => 'Stabile → Catasto: Subalterno',
|
|
'stabile.categoria_catastale' => 'Stabile → Catasto: Categoria',
|
|
'stabile.classe' => 'Stabile → Catasto: Classe',
|
|
'stabile.consistenza' => 'Stabile → Catasto: Consistenza',
|
|
'stabile.rendita_catastale' => 'Stabile → Catasto: Rendita',
|
|
'stabile.superficie_catastale' => 'Stabile → Catasto: Superficie',
|
|
// Caratteristiche edificio
|
|
'stabile.anno_costruzione' => 'Stabile → Anno costruzione',
|
|
'stabile.numero_piani' => 'Stabile → Numero Piani',
|
|
'stabile.ascensore' => 'Stabile → Ascensore (bool)',
|
|
'stabile.riscaldamento_centralizzato' => 'Stabile → Riscaldamento Centralizzato (bool)',
|
|
'stabile.tipo_edificio' => 'Stabile → Tipo edificio',
|
|
// Dati amministrativi
|
|
'stabile.codice_fiscale_condominio' => 'Stabile → Codice Fiscale Condominio',
|
|
'stabile.partita_iva_condominio' => 'Stabile → Partita IVA Condominio',
|
|
'stabile.codice_destinatario_sdi' => 'Stabile → SDI: Codice Destinatario',
|
|
'stabile.pec_condominio' => 'Stabile → PEC Condominio',
|
|
'stabile.pec_amministratore' => 'Stabile → PEC Amministratore',
|
|
'stabile.modalita_rateizzazione' => 'Stabile → Rate: Modalità',
|
|
'stabile.inizio_esercizio' => 'Stabile → Rate: Inizio Esercizio',
|
|
'stabile.fine_esercizio' => 'Stabile → Rate: Fine Esercizio',
|
|
// Dati bancari associati allo stabile
|
|
'stabile.iban_principale' => 'Stabile → Banca: IBAN Principale',
|
|
'stabile.banca_principale' => 'Stabile → Banca: Istituto Principale',
|
|
'stabile.filiale' => 'Stabile → Banca: Filiale Principale',
|
|
'stabile.iban_secondario' => 'Stabile → Banca: IBAN Secondario',
|
|
'stabile.banca_secondaria' => 'Stabile → Banca: Istituto Secondario',
|
|
'stabile.filiale_secondaria' => 'Stabile → Banca: Filiale Secondaria',
|
|
// Campi banca dettagliati (tab "Banche")
|
|
'banca.denominazione' => 'Banca → Denominazione (mapping avanzato)',
|
|
'banca.nome_banca' => 'Banca → Nome banca (legacy compatibile)',
|
|
'banca.intestazione' => 'Banca → Intestazione conto',
|
|
'banca.numero_conto' => 'Banca → Numero conto',
|
|
'banca.iban' => 'Banca → IBAN',
|
|
'banca.bic_swift' => 'Banca → BIC/SWIFT',
|
|
'banca.abi' => 'Banca → ABI',
|
|
'banca.cab' => 'Banca → CAB',
|
|
'banca.cuc' => 'Banca → Codice CUC',
|
|
'banca.cin' => 'Banca → CIN',
|
|
'banca.filiale' => 'Banca → Filiale / sportello',
|
|
'banca.valuta' => 'Banca → Valuta',
|
|
'banca.saldo_iniziale' => 'Banca → Saldo iniziale',
|
|
'banca.data_saldo_iniziale' => 'Banca → Data saldo iniziale',
|
|
'banca.stato_conto' => 'Banca → Stato conto',
|
|
'banca.note' => 'Banca → Note',
|
|
'banca.is_nostro_conto' => 'Banca → Flag conto principale',
|
|
'banca.codice_cassa' => 'Banca → Codice cassa legacy',
|
|
'banca.tipo_conto' => 'Banca → Tipo conto',
|
|
// I dati bancari vengono ora gestiti nel tab dedicato «Banche»
|
|
];
|
|
// Mapping extra: Unità and Tabelle field mappings
|
|
$unitaFieldMapping = [];
|
|
$tabelleFieldMapping = [];
|
|
$vociFieldMapping = [];
|
|
try {
|
|
if ($mapping) {
|
|
$unitaFieldMapping = (array) data_get($mapping->meta, 'unita_field_mapping', []);
|
|
$tabelleFieldMapping = (array) data_get($mapping->meta, 'tabelle_field_mapping', []);
|
|
$vociFieldMapping = (array) data_get($mapping->meta, 'voci_field_mapping', []);
|
|
}
|
|
} catch (\Throwable $e) { /* ignore */ }
|
|
// Sample Unità legacy rows (from staging) to infer headers
|
|
$legacyUnitaSampleRows = [];
|
|
try {
|
|
$importConn = \App\Models\UserSetting::get('gescon.import_conn', 'gescon_import');
|
|
if ($legacyCode && \Illuminate\Support\Facades\Schema::connection($importConn)->hasTable('condomin')) {
|
|
$legacyUnitaSampleRows = \Illuminate\Support\Facades\DB::connection($importConn)
|
|
->table('condomin')
|
|
->when(\Illuminate\Support\Facades\Schema::connection($importConn)->hasColumn('condomin', 'cod_stabile'), function ($q) use ($legacyCode) {
|
|
$q->where('cod_stabile', $legacyCode);
|
|
})
|
|
->limit(5)
|
|
->get()
|
|
->map(fn($r) => (array)$r)
|
|
->toArray();
|
|
}
|
|
} catch (\Throwable $e) { $legacyUnitaSampleRows = []; }
|
|
@endphp
|
|
<div id="gescon-mapping">
|
|
<div class="netgescon-card">
|
|
<div class="netgescon-card-header flex flex-col gap-3">
|
|
@include('admin.gescon-import.tabs.partials._mapping_header', [
|
|
'legacyCode' => $legacyCode ?? null,
|
|
'legacyOptions' => $legacyOptions ?? [],
|
|
'availableYears' => $availableYears ?? [],
|
|
'stabileCurrent' => $stabileCurrent ?? null,
|
|
'gestioneCurrent' => $gestioneCurrent ?? null,
|
|
'isSuper' => $isSuper ?? false,
|
|
'blockMappingUi' => $blockMappingUi ?? false,
|
|
'targetFields' => $targetFields ?? [],
|
|
'savedPresetKey' => $savedPresetKey ?? null,
|
|
'legacySource' => $legacySource ?? null,
|
|
'mapping' => $mapping ?? null,
|
|
'globalMapping' => $globalMapping ?? null,
|
|
])
|
|
</div>
|
|
|
|
@include('admin.gescon-import.tabs.partials._segment_stabili', [
|
|
'legacyFields' => $legacyFields ?? [],
|
|
'savedSources' => $savedSources ?? [],
|
|
'targetFields' => $targetFields ?? [],
|
|
'mapping' => $mapping ?? [],
|
|
'globalMapping' => $globalMapping ?? [],
|
|
'autoMap' => $autoMap ?? [],
|
|
'isGlobal' => $isGlobal ?? false,
|
|
'stabileCurrent' => $stabileCurrent ?? null,
|
|
'blockMappingUi' => $blockMappingUi ?? false,
|
|
])
|
|
|
|
@include('admin.gescon-import.tabs.partials._segment_gestioni', [
|
|
'legacyCode' => $legacyCode ?? null,
|
|
])
|
|
|
|
@include('admin.gescon-import.tabs.partials._segment_finanziari', [
|
|
'legacyCode' => $legacyCode ?? null,
|
|
'stabileCurrent' => $stabileCurrent ?? null,
|
|
])
|
|
|
|
@include('admin.gescon-import.tabs.partials._segment_unita', [
|
|
'legacyCode' => $legacyCode ?? null,
|
|
'legacyUnitaSampleRows' => $legacyUnitaSampleRows,
|
|
'unitaFieldMapping' => $unitaFieldMapping,
|
|
])
|
|
|
|
@include('admin.gescon-import.tabs.partials._segment_tabelle', [
|
|
'legacyCode' => $legacyCode ?? null,
|
|
'tabelleFieldMapping' => $tabelleFieldMapping,
|
|
])
|
|
|
|
<div id="segment-voci" class="segment-container d-none">
|
|
@include('admin.gescon-import.partials.voci-field-mapping', [
|
|
'vociFieldMapping' => $vociFieldMapping ?? [],
|
|
])
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Diagnostics are handled inside the extracted JS file --}}
|
|
|
|
<style>
|
|
#gescon-mapping .mapping-two-col {
|
|
display: flex !important;
|
|
gap: 24px;
|
|
align-items: stretch;
|
|
width: 100%;
|
|
}
|
|
#gescon-mapping .mapping-two-col .mapping-pane {
|
|
flex: 1 1 0;
|
|
min-width: 0;
|
|
}
|
|
/* Ensure legacy lists stack vertically and scroll predictably */
|
|
#gescon-mapping .legacy-field-row,
|
|
#gescon-mapping .legacy-tab-row,
|
|
#gescon-mapping .legacy-voce-row { display:block; border-bottom:1px solid #f1f1f1; }
|
|
#gescon-mapping #legacy-fields-list,
|
|
#gescon-mapping #legacy-tabelle-list,
|
|
#gescon-mapping #legacy-voci-list { max-height: 24rem; overflow:auto; display:block; }
|
|
/* Normalize font to match app; avoid monospace labels */
|
|
#gescon-mapping .mapping-row .w-40,
|
|
#gescon-mapping .mapping-tab-row .w-40,
|
|
#gescon-mapping .mapping-voce-row .w-40 { font-family: inherit; font-variant-ligatures: none; }
|
|
#gescon-mapping .mapping-tab-row .w-40,
|
|
#gescon-mapping .mapping-row .w-40 { width: 12rem; }
|
|
/* Tighten inputs for better alignment */
|
|
#gescon-mapping .target-field-input,
|
|
#gescon-mapping .target-tab-input { padding:.3rem .45rem; }
|
|
/* Card equal height in column layout */
|
|
#gescon-mapping .mapping-two-col .netgescon-card { display:flex; flex-direction:column; height:100%; }
|
|
#gescon-mapping .mapping-two-col .netgescon-card-body { flex:1 1 auto; }
|
|
@media (max-width: 991px) {
|
|
#gescon-mapping .mapping-two-col {
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
}
|
|
|
|
/* Steps di navigazione import */
|
|
#gescon-mapping .netgescon-steps ul{list-style:none;display:flex;gap:8px;padding:0;margin:0}
|
|
#gescon-mapping .netgescon-steps li{padding:6px 10px;border-radius:16px;background:#f2f2f2;color:#666;font-size:12px}
|
|
#gescon-mapping .netgescon-steps li.active{background:#0d6efd1a;color:#0d6efd;font-weight:600}
|
|
#gescon-mapping .netgescon-steps li.disabled{opacity:.6}
|
|
|
|
/* Box progress import */
|
|
#gescon-mapping .import-progress{border:1px solid #e5e5e5;border-radius:8px;padding:10px 12px;background:#fff;margin-bottom:12px}
|
|
/* Bootstrap-free utility */
|
|
#gescon-mapping .d-none{display:none !important}
|
|
|
|
/* Compatta i controlli in questa pagina per una resa più fine (senza impattare altrove) */
|
|
#gescon-mapping #mapping-form .netgescon-input,
|
|
#gescon-mapping #mapping-form select.mapping-select,
|
|
#gescon-mapping #legacy-filter-input,
|
|
#gescon-mapping #target-filter-input,
|
|
#gescon-mapping .netgescon-card-header select.netgescon-input {
|
|
font-size: .875rem; /* text-sm */
|
|
line-height: 1.25rem;
|
|
padding: .25rem .5rem !important;
|
|
}
|
|
#gescon-mapping #mapping-rows .mapping-row label small { font-size: .82rem; }
|
|
#gescon-mapping .netgescon-card-header .netgescon-btn { padding: .25rem .5rem; font-size: .8rem; }
|
|
#gescon-mapping .netgescon-btn-sm { padding: .2rem .45rem; font-size: .72rem; }
|
|
/* Stato attivo pulsanti filtro mapping */
|
|
#gescon-mapping #mapping-visibility-buttons .netgescon-btn.active { background:#0d6efd; color:#fff; border-color:#0d6efd; }
|
|
/* (Dimming rimosso: i campi restano sempre visibili) */
|
|
/* Clickable steps */
|
|
#gescon-mapping .mapping-steps li.clickable{cursor:pointer;}
|
|
#gescon-mapping .mapping-steps li.clickable:hover{background:#e2ecf9;}
|
|
#gescon-mapping .segment-container.d-none{display:none !important;}
|
|
</style>
|
|
|
|
{{-- (pannello staging rimosso: le anteprime sono ora integrate nei singoli segmenti) --}}
|
|
|
|
</div> <!-- /#gescon-mapping -->
|