181 lines
9.7 KiB
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
|