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

181 lines
9.7 KiB
PHP

@extends('admin.layouts.netgescon')
@section('content')
<div class="netgescon-card">
<div class="netgescon-card-header flex items-center justify-between">
<h3 class="m-0">GESCON Staging Loader (MDB DB di staging)</h3>
<a href="{{ route('admin.gescon-import.staging-status') }}" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-primary">Stato Staging</a>
</div>
<div class="netgescon-card-body">
<div class="mb-3 text-sm text-gray-600">
Connessione di staging attiva: <strong>{{ $settings['gescon.import_conn'] ?? 'gescon_import' }}</strong> mdb-tools: <strong>{{ $hasMdbTools ? 'OK' : 'NON DISPONIBILE' }}</strong>
</div>
<form id="mdb-form" class="flex items-center gap-2 flex-wrap" onsubmit="return false;">
<label class="text-sm">Percorso MDB</label>
<input id="mdb-path" type="text" class="netgescon-input" style="min-width:420px" placeholder="/path/to/Stabili.mdb" value="{{ $settings['gescon.mdb_stabili'] ?? '' }}">
<button id="btn-verify" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary">Verifica</button>
<button id="btn-scan" class="netgescon-btn netgescon-btn-sm netgescon-btn-primary">Elenca tabelle</button>
</form>
<div id="verify-out" class="mt-2 text-xs text-gray-700"></div>
<div id="tables-panel" class="mt-4" style="display:none;">
<div class="mb-2 flex items-center gap-2">
<strong>Seleziona tabelle da importare in staging</strong>
<label class="text-xs flex items-center gap-1"><input type="checkbox" id="truncate" checked> Trunca prima di importare</label>
<button id="btn-import" class="netgescon-btn netgescon-btn-sm netgescon-btn-success">Importa selezionate</button>
</div>
<div id="tables-list" class="flex flex-col gap-2"></div>
<div id="import-result" class="mt-3 text-xs"></div>
</div>
<hr class="my-6">
<div class="mb-2">
<h4 class="m-0 text-base font-semibold">Import rapido singolo_anno.mdb (stabile/anno)</h4>
<div class="text-xs text-gray-600">Usa i comandi di staging per: condomin, dett_tab, voc_spe, cre_deb_preced, operazioni, incassi, rate, giri_conti, straordinarie, dett_pers, detrazioni_fiscali.</div>
</div>
<div class="flex flex-wrap items-center gap-2">
<label class="text-sm">Stabile</label>
<input id="quick-stabile" type="text" class="netgescon-input" style="width:110px" placeholder="0019">
<label class="text-sm">Anno/Cartella</label>
<select id="quick-year" class="netgescon-input" style="min-width:120px">
<option value=""></option>
</select>
<label class="text-xs flex items-center gap-1"><input type="checkbox" id="quick-all-years"> Tutti gli anni</label>
<label class="text-xs flex items-center gap-1"><input type="checkbox" id="quick-truncate" checked> Trunca (solo primo anno)</label>
<button id="btn-load-years" class="netgescon-btn netgescon-btn-sm netgescon-btn-outline-secondary">Carica anni</button>
<button id="btn-quick-load" class="netgescon-btn netgescon-btn-sm netgescon-btn-success">Importa</button>
</div>
<div class="mt-3 grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2 text-sm" id="quick-tables">
@php
$quickTables = [
'condomin' => 'Condomini (condomin)',
'dett_tab' => 'Dett. tabelle (dett_tab)',
'voc_spe' => 'Voci spesa (voc_spe)',
'cre_deb_preced' => 'Crediti/Debiti prec. (cre_deb_preced)',
'operazioni' => 'Operazioni',
'incassi' => 'Incassi',
'rate' => 'Rate',
'giri_conti' => 'Giroconti',
'straordinarie' => 'Straordinarie',
'dett_pers' => 'Addebiti personali',
'detrazioni_fiscali' => 'Detrazioni fiscali',
];
@endphp
@foreach($quickTables as $key => $label)
<label class="flex items-center gap-2">
<input type="checkbox" class="quick-table" value="{{ $key }}"> <span>{{ $label }}</span>
</label>
@endforeach
</div>
<div id="quick-result" class="mt-3 text-xs"></div>
</div>
</div>
<script>
const routes = {
verify: @json(route('admin.gescon-import.archive.verify-mdb')),
scan: @json(route('admin.gescon-import.archive.scan-tables')),
ingest: @json(route('admin.gescon-import.archive.ingest-tables')),
quickLoad: @json(route('admin.gescon-import.archive.quick-load')),
years: @json(route('admin.gescon-import.years')),
};
const el = sel => document.querySelector(sel);
const out = (node, html) => node.innerHTML = html;
el('#btn-verify').addEventListener('click', async () => {
const path = el('#mdb-path').value.trim();
out(el('#verify-out'), 'Verifica in corso…');
const res = await fetch(routes.verify, { method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-TOKEN': @json(csrf_token())}, body: new URLSearchParams({ mdb_path: path }) });
const data = await res.json();
out(el('#verify-out'), `<pre>${JSON.stringify(data, null, 2)}</pre>`);
});
el('#btn-scan').addEventListener('click', async () => {
const path = el('#mdb-path').value.trim();
out(el('#verify-out'), '');
out(el('#tables-list'), 'Lettura tabelle…');
el('#tables-panel').style.display = '';
const res = await fetch(routes.scan, { method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-TOKEN': @json(csrf_token())}, body: new URLSearchParams({ mdb_path: path }) });
const data = await res.json();
if (!data.tables) { out(el('#tables-list'), '<em>Nessuna tabella trovata</em>'); return; }
const html = data.tables.map(t => {
const def = 'mdb_' + t.replace(/\s+/g,'_').replace(/[^A-Za-z0-9_]/g,'').toLowerCase();
return `
<div class='flex items-center gap-3 text-sm'>
<label class='flex items-center gap-2'>
<input type='checkbox' name='tables' value='${t}'> <span>${t}</span>
</label>
<span class='text-xs text-gray-600'>→ Tabella destinazione</span>
<input type='text' class='netgescon-input' name='target_${t}' placeholder='${def}' style='min-width:240px'>
</div>`;
}).join('');
out(el('#tables-list'), html);
});
el('#btn-import').addEventListener('click', async () => {
const path = el('#mdb-path').value.trim();
const selected = Array.from(document.querySelectorAll("#tables-list input[name='tables']:checked")).map(i => i.value);
if (selected.length === 0) { out(el('#import-result'), '<span style="color:#b00">Seleziona almeno una tabella.</span>'); return; }
out(el('#import-result'), 'Import in corso…');
const body = new URLSearchParams({ mdb_path: path });
selected.forEach(t => {
body.append('tables[]', t);
const tgt = (document.querySelector(`[name='target_${CSS.escape(t)}']`)?.value || '').trim();
if (tgt) body.append(`targets[${t}]`, tgt);
});
body.append('truncate', el('#truncate').checked ? '1' : '0');
const res = await fetch(routes.ingest, { method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-TOKEN': @json(csrf_token())}, body });
const data = await res.json();
if (data.ok) {
const list = (data.result||[]).map(r => `${r.table} → ${r.target}: ${r.rows} righe`).join('<br>');
out(el('#import-result'), `<span style='color:#070'>OK</span><br>${list}`);
} else {
out(el('#import-result'), `<span style='color:#b00'>Errore:</span> ${data.error||'—'}`);
}
});
el('#btn-load-years').addEventListener('click', async () => {
const stable = el('#quick-stabile').value.trim();
if (!stable) { out(el('#quick-result'), '<span style="color:#b00">Inserisci lo stabile.</span>'); return; }
const url = new URL(routes.years, window.location.origin);
url.searchParams.set('legacy_code', stable);
out(el('#quick-result'), 'Caricamento anni…');
const res = await fetch(url);
const data = await res.json();
if (!data.ok) { out(el('#quick-result'), `<span style="color:#b00">${data.error || 'Errore'}</span>`); return; }
const years = data.years || [];
el('#quick-year').innerHTML = `<option value="">—</option>` + years.map(y => `<option value="${y}">${y}</option>`).join('');
out(el('#quick-result'), `<span style="color:#070">Anni trovati: ${years.length}</span>`);
});
el('#btn-quick-load').addEventListener('click', async () => {
const stabile = el('#quick-stabile').value.trim();
const year = el('#quick-year').value.trim();
const allYears = el('#quick-all-years').checked;
const truncate = el('#quick-truncate').checked;
const tables = Array.from(document.querySelectorAll('.quick-table:checked')).map(i => i.value);
if (!stabile) { out(el('#quick-result'), '<span style="color:#b00">Stabile obbligatorio.</span>'); return; }
if (!allYears && !year) { out(el('#quick-result'), '<span style="color:#b00">Seleziona anno o spunta "tutti gli anni".</span>'); return; }
if (tables.length === 0) { out(el('#quick-result'), '<span style="color:#b00">Seleziona almeno una tabella.</span>'); return; }
out(el('#quick-result'), 'Import in corso…');
const body = new URLSearchParams({ stabile, year, truncate: truncate ? '1' : '0', all_years: allYears ? '1' : '0' });
tables.forEach(t => body.append('tables[]', t));
const res = await fetch(routes.quickLoad, { method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-TOKEN': @json(csrf_token())}, body });
const data = await res.json();
if (!data.ok) { out(el('#quick-result'), `<span style="color:#b00">Errore: ${data.error || '—'}</span>`); return; }
const rows = (data.results || []).map(r => {
const line = r.table ? `${r.year} • ${r.table}` : `${r.year}`;
const msg = r.output ? r.output.replace(/\n/g, '<br>') : (r.error || 'OK');
return `<div><strong>${line}</strong>: ${msg}</div>`;
}).join('');
out(el('#quick-result'), `<span style="color:#070">OK</span><div class="mt-1">${rows}</div>`);
});
</script>
@endsection