1222 lines
72 KiB
JavaScript
1222 lines
72 KiB
JavaScript
/* global window, document, CSS, fetch */
|
|
// NetGescon — GESCON Mapping JS (extracted from Blade)
|
|
(function () {
|
|
'use strict';
|
|
const CFG = window.GESCON_MAPPING || {};
|
|
const R = (k) => (CFG.routes || {})[k] || '';
|
|
const LEGACY = CFG.legacyCode || '';
|
|
const CSRF = CFG.csrf || '';
|
|
|
|
// Utilities
|
|
function escapeHtml(s) {
|
|
return String(s)
|
|
.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>')
|
|
.replaceAll('"', '"').replaceAll("'", ''');
|
|
}
|
|
|
|
function formatEuro(value) {
|
|
if (value === null || value === undefined || value === '') {
|
|
return '';
|
|
}
|
|
const num = Number(value);
|
|
if (!Number.isFinite(num)) {
|
|
return String(value);
|
|
}
|
|
try {
|
|
return new Intl.NumberFormat('it-IT', { style: 'currency', currency: 'EUR' }).format(num);
|
|
} catch (e) {
|
|
return num.toFixed(2);
|
|
}
|
|
}
|
|
|
|
function toggleInlineCreate(trigger, show = true) {
|
|
const row = trigger && typeof trigger.closest === 'function'
|
|
? trigger.closest('.mapping-tab-row, .mapping-voce-row')
|
|
: null;
|
|
if (!row) return;
|
|
const ui = row.querySelector('.inline-create-ui');
|
|
if (!ui) return;
|
|
if (show) {
|
|
ui.classList.remove('hidden');
|
|
const focusTarget = ui.querySelector('.new-col-name');
|
|
if (focusTarget) {
|
|
setTimeout(() => focusTarget.focus(), 0);
|
|
}
|
|
} else {
|
|
ui.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
// ===== Mapping filtering & UI =====
|
|
let __mappingVisibilityMode = 'all';
|
|
let __searchTerm = '';
|
|
function filterLegacyList(term) {
|
|
const t = (term || '').toLowerCase();
|
|
document.querySelectorAll('#legacy-list > li').forEach(li => {
|
|
const key = (li.getAttribute('data-key') || '').toLowerCase();
|
|
const txt = (li.innerText || '').toLowerCase();
|
|
li.style.display = (!t || key.includes(t) || txt.includes(t)) ? '' : 'none';
|
|
});
|
|
}
|
|
function applyMappingVisibility() {
|
|
document.querySelectorAll('#mapping-rows .mapping-row').forEach(row => {
|
|
const sel = row.querySelector('select.mapping-select');
|
|
const mapped = !!(sel && sel.value);
|
|
let show = true;
|
|
if (__mappingVisibilityMode === 'mapped') show = mapped;
|
|
else if (__mappingVisibilityMode === 'unmapped') show = !mapped;
|
|
if (show && __searchTerm) {
|
|
const term = __searchTerm.toLowerCase();
|
|
const key = (row.getAttribute('data-key') || '').toLowerCase();
|
|
const nameEl = row.querySelector('label small');
|
|
const nameTxt = ((nameEl && nameEl.textContent) || '').toLowerCase();
|
|
let selectedLabel = '', selectedValue = '';
|
|
if (sel && sel.selectedIndex >= 0) {
|
|
const opt = sel.options[sel.selectedIndex];
|
|
selectedLabel = (opt.text || '').toLowerCase();
|
|
selectedValue = (opt.value || '').toLowerCase();
|
|
}
|
|
if (!(key.includes(term) || nameTxt.includes(term) || selectedLabel.includes(term) || selectedValue.includes(term))) {
|
|
show = false;
|
|
}
|
|
}
|
|
row.style.display = show ? '' : 'none';
|
|
});
|
|
}
|
|
function setMappingFilter(mode) {
|
|
__mappingVisibilityMode = mode || 'all';
|
|
document.querySelectorAll('#mapping-visibility-buttons button').forEach(btn => {
|
|
if (btn.getAttribute('data-mode') === __mappingVisibilityMode) btn.classList.add('active'); else btn.classList.remove('active');
|
|
});
|
|
applyMappingVisibility();
|
|
}
|
|
function syncMappingSearch(term) {
|
|
__searchTerm = term || '';
|
|
try {
|
|
const lf = document.getElementById('legacy-filter-input');
|
|
if (lf && lf.value !== term) lf.value = term;
|
|
const tf = document.getElementById('target-filter-input');
|
|
if (tf && tf.value !== term) tf.value = term;
|
|
} catch (e) { }
|
|
filterLegacyList(term);
|
|
applyMappingVisibility();
|
|
}
|
|
function buildTargetSelect(name) {
|
|
let html = '<select class="netgescon-input mapping-select" name="' + escapeHtml(name) + '" style="padding:.35rem .5rem;">';
|
|
html += '<option value="">— Seleziona campo target —</option>';
|
|
(window.__targetFields || []).forEach(function (tf) {
|
|
html += '<option value="' + escapeHtml(tf.value) + '">' + escapeHtml(tf.label) + '</option>';
|
|
});
|
|
html += '</select>';
|
|
return html;
|
|
}
|
|
function promptAddField() {
|
|
const key = prompt('Chiave campo legacy (es. telefono_amministratore):');
|
|
if (!key) return;
|
|
const name = prompt('Etichetta leggibile (opzionale):', key.replace(/[_-]/g, ' '));
|
|
addLegacyField(key, name || key);
|
|
}
|
|
function addLegacyField(key, label) {
|
|
if (document.querySelector('#mapping-rows .mapping-row[data-key="' + key + '"]')) return;
|
|
const li = document.createElement('li');
|
|
li.className = 'flex justify-between items-center';
|
|
li.style.borderBottom = '1px solid #eee';
|
|
li.style.padding = '.5rem';
|
|
li.setAttribute('data-key', key);
|
|
li.innerHTML = '<div><div class="font-semibold">' + escapeHtml(label) + '</div><small class="text-gray-500">' + escapeHtml(key) + '</small></div><span class="netgescon-badge netgescon-badge-secondary">Sorgente</span>';
|
|
const ul = document.getElementById('legacy-list'); if (ul) ul.appendChild(li);
|
|
const row = document.createElement('div');
|
|
row.className = 'grid md:grid-cols-12 gap-3 items-center mb-2 mapping-row';
|
|
row.setAttribute('data-key', key);
|
|
row.innerHTML = '<div class="md:col-span-5 col-span-12"><label class="mb-0"><small>' + escapeHtml(label) + '</small></label><div class="text-gray-500 text-sm">' + escapeHtml(key) + '</div></div>' +
|
|
'<div class="md:col-span-7 col-span-12">' + buildTargetSelect('mapping[' + key + ']') + '</div>';
|
|
const container = document.getElementById('mapping-rows'); if (container) container.appendChild(row);
|
|
}
|
|
function updateMappingPreviews() {
|
|
document.querySelectorAll('#mapping-form .mapping-row').forEach(row => {
|
|
const key = row.getAttribute('data-key');
|
|
const valEl = document.querySelector('.legacy-value[data-field-value="' + CSS.escape(key) + '"]');
|
|
const preview = row.querySelector('.import-preview');
|
|
if (preview) preview.textContent = valEl ? (valEl.textContent || '—') : '—';
|
|
});
|
|
}
|
|
|
|
// ===== Manual Values =====
|
|
function getManualContainer() {
|
|
return document.getElementById('manual-values-container');
|
|
}
|
|
|
|
function refreshManualEmptyState() {
|
|
const container = getManualContainer();
|
|
if (!container) return;
|
|
const rows = container.querySelectorAll('.manual-value-row');
|
|
const placeholder = container.querySelector('.manual-value-empty');
|
|
if (rows.length === 0) {
|
|
if (placeholder) {
|
|
placeholder.classList.remove('hidden');
|
|
} else {
|
|
const info = document.createElement('div');
|
|
info.className = 'manual-value-empty text-xs text-gray-500 border rounded p-2 bg-slate-50';
|
|
info.textContent = 'Nessun valore manuale configurato.';
|
|
container.appendChild(info);
|
|
}
|
|
} else if (placeholder) {
|
|
placeholder.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
function syncManualValueRow(selectEl) {
|
|
if (!selectEl) return;
|
|
const row = selectEl.closest('.manual-value-row');
|
|
if (!row) return;
|
|
const input = row.querySelector('.manual-value-input');
|
|
if (!input) return;
|
|
const target = (selectEl.value || '').trim();
|
|
if (target) {
|
|
input.name = 'manual_target_values[' + target + ']';
|
|
row.dataset.target = target;
|
|
} else {
|
|
input.name = '';
|
|
row.dataset.target = '';
|
|
}
|
|
}
|
|
|
|
function addManualValueRow(target = '', value = '') {
|
|
const container = getManualContainer();
|
|
if (!container) return;
|
|
const tmpl = document.getElementById('manual-value-row-template');
|
|
if (!tmpl) return;
|
|
const cloneRoot = (() => {
|
|
if (tmpl.content && tmpl.content.firstElementChild) {
|
|
return tmpl.content.firstElementChild.cloneNode(true);
|
|
}
|
|
const wrapper = document.createElement('div');
|
|
wrapper.innerHTML = (tmpl.innerHTML || '').trim();
|
|
return wrapper.firstElementChild ? wrapper.firstElementChild.cloneNode(true) : null;
|
|
})();
|
|
if (!cloneRoot) return;
|
|
container.appendChild(cloneRoot);
|
|
const select = cloneRoot.querySelector('.manual-value-target');
|
|
const input = cloneRoot.querySelector('.manual-value-input');
|
|
if (select) {
|
|
select.value = target || '';
|
|
syncManualValueRow(select);
|
|
}
|
|
if (input) input.value = value || '';
|
|
refreshManualEmptyState();
|
|
if (select) {
|
|
setTimeout(() => select.focus(), 0);
|
|
} else if (input) {
|
|
setTimeout(() => input.focus(), 0);
|
|
}
|
|
}
|
|
|
|
function removeManualValueRow(triggerEl) {
|
|
const row = triggerEl ? triggerEl.closest('.manual-value-row') : null;
|
|
if (row) row.remove();
|
|
refreshManualEmptyState();
|
|
}
|
|
|
|
function initializeManualValueRows() {
|
|
const container = getManualContainer();
|
|
if (!container) return;
|
|
container.querySelectorAll('.manual-value-row .manual-value-target').forEach(selectEl => {
|
|
syncManualValueRow(selectEl);
|
|
});
|
|
const defaults = (CFG.manualTargetValues && typeof CFG.manualTargetValues === 'object') ? CFG.manualTargetValues : null;
|
|
if (container.querySelectorAll('.manual-value-row').length === 0 && defaults) {
|
|
Object.keys(defaults).forEach(key => {
|
|
addManualValueRow(key, defaults[key]);
|
|
});
|
|
}
|
|
refreshManualEmptyState();
|
|
}
|
|
|
|
// ===== Samples & Presets =====
|
|
let __sampleIndex = 0;
|
|
async function loadSample(idx) {
|
|
const box = document.getElementById('legacy-sample');
|
|
if (box) box.innerHTML = '<div class="text-gray-500 text-sm">Caricamento…</div>';
|
|
try {
|
|
const params = new URLSearchParams({ index: String(idx) });
|
|
if (LEGACY) params.set('legacy_code', LEGACY);
|
|
const res = await fetch(R('sample') + '?' + params.toString());
|
|
const j = await res.json();
|
|
if (!j.ok) { if (box) box.innerHTML = '<div class="text-danger small">' + escapeHtml(j.error || 'Errore caricamento') + '</div>'; return; }
|
|
__sampleIndex = j.index || 0;
|
|
const data = j.data || {};
|
|
document.querySelectorAll('.legacy-value[data-field-value]').forEach(el => {
|
|
const key = el.getAttribute('data-field-value');
|
|
el.textContent = (key in data) ? String(data[key] ?? '') : '—';
|
|
});
|
|
try {
|
|
const legacyBankBadge = document.getElementById('bank-count-legacy');
|
|
if (legacyBankBadge) {
|
|
const keys = Object.keys(data || {});
|
|
const ibanKeys = keys.filter(k => /iban/.test(String(k).toLowerCase()));
|
|
const count = ibanKeys.filter(k => String(data[k] ?? '').trim().length > 0).length;
|
|
legacyBankBadge.textContent = 'Banche presenti: ' + count;
|
|
legacyBankBadge.style.display = '';
|
|
}
|
|
} catch (e) { }
|
|
updateMappingPreviews();
|
|
try { populateGestioneRatesFromData(data); } catch (e) { }
|
|
if (box) box.innerHTML = '';
|
|
} catch (e) { if (box) box.innerHTML = '<div class="text-danger small">Errore</div>'; }
|
|
}
|
|
function browseSample(delta) { __sampleIndex = Math.max(0, __sampleIndex + (delta || 0)); return loadSample(__sampleIndex); }
|
|
function syncLegacyPreview() { return loadSample(__sampleIndex || 0); }
|
|
|
|
function applyPreset() {
|
|
const sel = document.getElementById('preset-select');
|
|
const key = (sel?.value || '').trim();
|
|
const preset = (CFG.mappingPresets || {})[key];
|
|
document.getElementById('preset_key').value = key;
|
|
if (!preset) { updatePresetMeta(); return; }
|
|
const mapping = preset.mapping || {};
|
|
document.querySelectorAll('#mapping-form .mapping-row').forEach(row => {
|
|
const legacyKey = row.getAttribute('data-key');
|
|
const sel2 = row.querySelector('select.mapping-select');
|
|
if (!legacyKey || !sel2) return;
|
|
const target = mapping[legacyKey];
|
|
if (target) { sel2.value = target; }
|
|
});
|
|
const meta = Object.assign({}, preset.meta || {});
|
|
document.getElementById('preset_meta').value = JSON.stringify(meta);
|
|
}
|
|
function updatePresetMeta() {
|
|
const sel = document.getElementById('preset-select');
|
|
const key = (sel?.value || '').trim();
|
|
const preset = (CFG.mappingPresets || {})[key];
|
|
const base = preset?.meta || {};
|
|
const meta = Object.assign({}, base);
|
|
document.getElementById('preset_meta').value = JSON.stringify(meta);
|
|
document.getElementById('preset_key').value = key;
|
|
}
|
|
|
|
// ===== Segments =====
|
|
function switchSegment(seg) {
|
|
const segments = ['stabili', 'gestioni', 'finanziari', 'unita', 'tabelle', 'voci'];
|
|
segments.forEach(s => {
|
|
const el = document.getElementById('segment-' + s);
|
|
if (el) { if (s === seg) el.classList.remove('d-none'); else el.classList.add('d-none'); }
|
|
document.querySelectorAll('.mapping-steps [data-segment="' + s + '"]').forEach(li => {
|
|
if (s === seg) li.classList.add('active'); else li.classList.remove('active');
|
|
});
|
|
});
|
|
if (LEGACY) {
|
|
if (seg === 'unita') { refreshUnitaPreview(); }
|
|
if (seg === 'gestioni') {
|
|
if (!Array.isArray(__gestioniYears) || !__gestioniYears.length) {
|
|
// try to fetch years then load data
|
|
(async () => {
|
|
try {
|
|
const res = await fetch(R('years') + '?legacy_code=' + encodeURIComponent(LEGACY));
|
|
if (res.ok) { const js = await res.json(); __gestioniYears = Array.isArray(js.years) ? js.years : []; __gestioniYearIndex = Math.max(0, __gestioniYears.length - 1); updateGestioneYearUI(); }
|
|
} catch (e) { }
|
|
try { await loadGestioneYearData(); } catch (e) { }
|
|
})();
|
|
} else { loadGestioneYearData(); }
|
|
}
|
|
if (seg === 'finanziari') { loadLegacyCasse(); }
|
|
if (seg === 'tabelle' && typeof window.reloadTabelleColumns === 'function') { try { window.reloadTabelleColumns(); } catch (_) { } }
|
|
if (seg === 'voci' && typeof window.reloadVociColumns === 'function') { try { window.reloadVociColumns(); } catch (_) { } }
|
|
}
|
|
}
|
|
|
|
// ===== Gestione anni (generale_stabile) =====
|
|
function ensureRow(id) {
|
|
const tr = document.getElementById(id);
|
|
if (!tr) return null;
|
|
if (tr.children.length < 13) {
|
|
for (let i = tr.children.length; i < 13; i++) {
|
|
const td = document.createElement('td'); td.className = 'text-center text-xs'; td.dataset.mese = i; td.textContent = ''; tr.appendChild(td);
|
|
}
|
|
}
|
|
return tr;
|
|
}
|
|
function populateGestioneRatesFromData(data) {
|
|
if (!data) return;
|
|
const rowOrd = ensureRow('row-ord');
|
|
const rowRis = ensureRow('row-ris');
|
|
for (let i = 1; i <= 12; i++) {
|
|
const ko = 'ord_rata_' + i; const kr = 'ris_rata_' + i;
|
|
if (rowOrd) { const td = rowOrd.children[i]; if (td) td.textContent = (ko in data && String(data[ko] || '0') !== '0') ? '✓' : ''; }
|
|
if (rowRis) { const td = rowRis.children[i]; if (td) td.textContent = (kr in data && String(data[kr] || '0') !== '0') ? '✓' : ''; }
|
|
}
|
|
const annoO = data['anno_o'] || data['anno_or'] || '';
|
|
const annoR = data['anno_r'] || '';
|
|
const goAnno = document.getElementById('go-anno'); if (goAnno) goAnno.textContent = annoO ? '(' + annoO + ')' : '';
|
|
const grAnno = document.getElementById('gr-anno'); if (grAnno) grAnno.textContent = annoR ? '(' + annoR + ')' : '';
|
|
const cellAnnoO = document.getElementById('gg-anno-o'); if (cellAnnoO) cellAnnoO.textContent = annoO || '—';
|
|
const cellAnnoR = document.getElementById('gg-anno-r'); if (cellAnnoR) cellAnnoR.textContent = annoR || '—';
|
|
const statoO = data['stato_o'] || (annoO ? 'aperta' : '—');
|
|
const statoR = data['stato_r'] || (annoR ? 'aperta' : '—');
|
|
const cellStatoO = document.getElementById('gg-stato-o'); if (cellStatoO) cellStatoO.textContent = statoO;
|
|
const cellStatoR = document.getElementById('gg-stato-r'); if (cellStatoR) cellStatoR.textContent = statoR;
|
|
}
|
|
let __gestioniYears = Array.isArray(CFG.availableYears) ? CFG.availableYears : [];
|
|
let __gestioniYearIndex = 0;
|
|
function browseGestioneYear(delta) {
|
|
if (!__gestioniYears || __gestioniYears.length === 0) return;
|
|
__gestioniYearIndex = Math.min(Math.max(0, __gestioniYearIndex + delta), __gestioniYears.length - 1);
|
|
updateGestioneYearUI();
|
|
loadGestioneYearData();
|
|
}
|
|
function updateGestioneYearUI() {
|
|
const lbl = document.getElementById('gestione-year-label');
|
|
if (lbl) { lbl.textContent = (__gestioniYears && __gestioniYears.length) ? __gestioniYears[__gestioniYearIndex] : '—'; }
|
|
}
|
|
async function loadGestioneYearData() {
|
|
const year = __gestioniYears[__gestioniYearIndex];
|
|
if (!year || !LEGACY) return;
|
|
try {
|
|
const url = R('gestioniYear') + '?legacy_code=' + encodeURIComponent(LEGACY) + '&anno=' + encodeURIComponent(year);
|
|
const res = await fetch(url);
|
|
if (!res.ok) throw new Error('Errore caricamento gestioni');
|
|
const js = await res.json();
|
|
// Wire Staging Loader Unità link if possible
|
|
try {
|
|
const btn = document.getElementById('btn-unita-loader');
|
|
const base = R('archiveUi') || '';
|
|
if (btn && base) {
|
|
const p = (js.meta && js.meta.path_singolo_anno) ? String(js.meta.path_singolo_anno) : '';
|
|
const q = new URLSearchParams();
|
|
if (p) q.set('mdb_path', p);
|
|
// Pre-fill doesn't support table param explicitly, but UI lets user pick tables; this opens with mdb preselected
|
|
btn.href = base + (q.toString() ? ('?' + q.toString()) : '');
|
|
}
|
|
} catch (_) { }
|
|
const data = {};
|
|
if (js.ordinaria && js.ordinaria.rate) { Object.keys(js.ordinaria.rate).forEach(k => { data['ord_rata_' + k] = 1; }); data.anno_o = js.ordinaria.anno; data.stato_o = js.ordinaria.stato; }
|
|
if (js.riscaldamento && js.riscaldamento.rate) { Object.keys(js.riscaldamento.rate).forEach(k => { data['ris_rata_' + k] = 1; }); data.anno_r = js.riscaldamento.anno; data.stato_r = js.riscaldamento.stato; }
|
|
populateGestioneRatesFromData(data, year);
|
|
const tbody = document.querySelector('#straordinarie-table tbody');
|
|
if (tbody) {
|
|
const list = js.straordinarie || [];
|
|
if (list.length === 0) { tbody.innerHTML = `<tr><td colspan="6" class="text-xs text-gray-500">(Nessuna straordinaria per ${year})</td></tr>`; }
|
|
else { tbody.innerHTML = list.map(s => `<tr><td class='text-xs'>${s.id || '—'}</td><td class='text-xs'>${escapeHtml(s.descrizione || '—')}</td><td class='text-xs'>${s.data_inizio || '—'}</td><td class='text-xs'>${s.data_fine || '—'}</td><td class='text-xs'>${(s.rate_emesse || 0)}/${(s.rate_totali || 0)}</td><td class='text-xs'>${s.periodicita || ''}</td></tr>`).join(''); }
|
|
}
|
|
const annoS = document.getElementById('gg-anno-s'); if (annoS) annoS.textContent = year;
|
|
} catch (e) { console.warn(e); }
|
|
}
|
|
|
|
// ===== Finanziari (casse/banche) =====
|
|
let __legacyCasse = [];
|
|
async function loadLegacyCasse() {
|
|
const tb = document.querySelector('#legacy-casse-table tbody');
|
|
if (!tb) return;
|
|
tb.innerHTML = '<tr><td colspan="8" class="text-xs text-gray-500">Caricamento...</td></tr>';
|
|
try {
|
|
const url = R('casse') + '?legacy_code=' + encodeURIComponent(LEGACY);
|
|
const res = await fetch(url);
|
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
const js = await res.json();
|
|
__legacyCasse = (js.casse || []).map(c => ({
|
|
codice: c.codice,
|
|
descrizione: c.descrizione,
|
|
abi: c.abi,
|
|
cab: c.cab,
|
|
cin: c.cin || c.CIN || null,
|
|
cuc: c.cuc || c.CUC || c.codice_cuc || null,
|
|
iban: c.iban,
|
|
swift: c.swift || c.SWIFT || c.bic || c.BIC || null,
|
|
conto: c.numero_conto || c.conto || null,
|
|
intestatario: c.intestatario || c.intestazione || null,
|
|
filiale: c.filiale || c.filiale_descr || null,
|
|
indirizzo: c.indirizzo || c.indirizzo_filiale || null,
|
|
cap: c.cap || c.cap_filiale || null,
|
|
citta: c.citta || c.comune || null,
|
|
provincia: c.provincia || c.prov || null,
|
|
telefono: c.telefono || c.telefono_ufficio || null,
|
|
email: c.email || null,
|
|
pec: c.pec || c.email_pec || null,
|
|
valuta: c.valuta || c.currency || null,
|
|
saldo: c.saldo_iniziale_euro ?? c.saldo_iniziale ?? c.saldo ?? null,
|
|
saldo_euro: c.saldo_iniziale_euro ?? null,
|
|
data_saldo: c.data_saldo || c.data_saldo_iniziale || null,
|
|
note: c.note || null
|
|
}));
|
|
if (!__legacyCasse.find(c => c.codice === 'CON')) { __legacyCasse.unshift({ codice: 'CON', descrizione: 'CASSA CONTANTI', abi: null, cab: null, cin: null, cuc: null, iban: null, swift: null, conto: 'CON', intestatario: null, valuta: 'EUR', saldo: null, saldo_euro: null, data_saldo: null, note: null }); }
|
|
renderLegacyCasse();
|
|
ensureBancheMappingRows();
|
|
ensureMandatoryConMapping();
|
|
} catch (e) { tb.innerHTML = '<tr><td colspan="8" class="text-xs text-danger">Errore caricamento</td></tr>'; }
|
|
}
|
|
function renderLegacyCasse(term) {
|
|
const tbody = document.querySelector('#legacy-casse-table tbody'); if (!tbody) return;
|
|
const t = (term || '').toLowerCase();
|
|
const rows = __legacyCasse.filter(c => !t || c.codice.toLowerCase().includes(t) || (c.descrizione || '').toLowerCase().includes(t));
|
|
if (rows.length === 0) { tbody.innerHTML = '<tr><td colspan="8" class="text-xs text-gray-500">Nessun conto</td></tr>'; return; }
|
|
tbody.innerHTML = rows.map(c => {
|
|
const saldoFormatted = formatEuro(c.saldo_euro ?? c.saldo);
|
|
return `<tr data-cod="${c.codice}">
|
|
<td>${escapeHtml(c.codice || '')}</td>
|
|
<td>${escapeHtml(c.descrizione || '')}</td>
|
|
<td>${escapeHtml(c.abi || '')}</td>
|
|
<td>${escapeHtml(c.cab || '')}</td>
|
|
<td>${escapeHtml(c.cuc || '')}</td>
|
|
<td class="text-xs font-mono">${escapeHtml(c.iban || '')}</td>
|
|
<td class="text-xs">${escapeHtml(saldoFormatted || '')}</td>
|
|
<td><button type="button" class="netgescon-btn netgescon-btn-xs netgescon-btn-outline-primary" onclick="addBancaMapping('${c.codice}')">Mappa</button></td>
|
|
</tr>`;
|
|
}).join('');
|
|
try {
|
|
const badge = document.getElementById('bank-count-legacy');
|
|
if (badge) {
|
|
const exclCon = __legacyCasse.filter(c => c.codice !== 'CON').length;
|
|
const hasCon = __legacyCasse.some(c => c.codice === 'CON');
|
|
badge.style.display = 'inline-block';
|
|
badge.textContent = 'Legacy conti: ' + String(exclCon) + (hasCon ? ' (+CON)' : '');
|
|
}
|
|
} catch (e) { }
|
|
}
|
|
function filterLegacyCasse(term) { renderLegacyCasse(term); }
|
|
function ensureBancheMappingRows() {
|
|
const container = document.getElementById('banche-mapping-rows'); if (!container) return;
|
|
const saved = Array.isArray(CFG.savedBancheMapping) ? CFG.savedBancheMapping : [];
|
|
if (!container.querySelector('.banca-mapping-row')) {
|
|
if (saved.length) {
|
|
container.innerHTML = '';
|
|
saved.forEach(bm => {
|
|
if (!bm || !bm.codice_legacy) return;
|
|
addBancaMapping(String(bm.codice_legacy), bm);
|
|
});
|
|
syncBancheJson();
|
|
} else {
|
|
renderBanchePlaceholder(container);
|
|
}
|
|
}
|
|
}
|
|
function renderBanchePlaceholder(container) {
|
|
if (!container) return;
|
|
container.innerHTML = '<div class="placeholder-banche text-xs text-slate-500 border border-dashed border-slate-300 rounded px-4 py-4 text-center bg-slate-50">Seleziona una cassa legacy a sinistra per iniziare la configurazione.</div>';
|
|
}
|
|
function addBancaMapping(codice, data) {
|
|
if (!codice) return null;
|
|
const container = document.getElementById('banche-mapping-rows'); if (!container) return null;
|
|
const existing = container.querySelector(`[data-mapping-cod='${CSS.escape(codice)}']`);
|
|
if (existing) {
|
|
if (data) populateBancaMappingRow(existing, data);
|
|
return existing;
|
|
}
|
|
if (container.querySelector('.placeholder-banche')) {
|
|
container.innerHTML = '';
|
|
}
|
|
const legacy = (__legacyCasse.find(x => x.codice === codice) || {});
|
|
const idx = container.querySelectorAll('.banca-mapping-row').length;
|
|
const legacyDescr = (data?.descrizione_legacy) || (data?.legacy?.descrizione) || legacy.descrizione || '';
|
|
const legacyIban = data?.legacy?.iban || data?.iban || legacy.iban || '';
|
|
const legacyAbi = data?.legacy?.abi || legacy.abi || '';
|
|
const legacyCab = data?.legacy?.cab || legacy.cab || '';
|
|
const legacyCuc = data?.legacy?.cuc || data?.cuc || legacy.cuc || '';
|
|
const legacyCin = data?.legacy?.cin || legacy.cin || '';
|
|
const legacySwift = data?.legacy?.swift || legacy.swift || '';
|
|
const legacyConto = data?.legacy?.conto || legacy.conto || '';
|
|
const legacyIntestatario = data?.legacy?.intestatario || legacy.intestatario || '';
|
|
const legacyFiliale = data?.legacy?.filiale || data?.filiale || legacy.filiale || '';
|
|
const legacyIndirizzo = data?.legacy?.indirizzo || data?.indirizzo || legacy.indirizzo || '';
|
|
const legacyCap = data?.legacy?.cap || data?.cap || legacy.cap || '';
|
|
const legacyCitta = data?.legacy?.citta || data?.citta || legacy.citta || '';
|
|
const legacyProvincia = data?.legacy?.provincia || data?.provincia || legacy.provincia || '';
|
|
const legacyTelefono = data?.legacy?.telefono || data?.telefono || legacy.telefono || '';
|
|
const legacyEmail = data?.legacy?.email || data?.email || legacy.email || '';
|
|
const legacyPec = data?.legacy?.pec || data?.pec || legacy.pec || '';
|
|
const legacySaldo = (legacy.saldo_euro ?? legacy.saldo ?? '');
|
|
const hasLegacySaldo = legacySaldo !== '' && legacySaldo !== null && legacySaldo !== undefined;
|
|
const legacyBadges = [
|
|
legacyIban ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5 font-mono uppercase">IBAN: ${escapeHtml(legacyIban)}</span>` : '',
|
|
(legacyAbi || legacyCab) ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5">ABI/CAB: ${escapeHtml([legacyAbi, legacyCab].filter(Boolean).join(' • '))}</span>` : '',
|
|
legacyCuc ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5">CUC: ${escapeHtml(legacyCuc)}</span>` : '',
|
|
legacySwift ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5">SWIFT: ${escapeHtml(legacySwift)}</span>` : '',
|
|
legacyConto ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5">Conto: ${escapeHtml(legacyConto)}</span>` : '',
|
|
hasLegacySaldo ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5">Saldo: ${escapeHtml(formatEuro(legacySaldo) || '')}</span>` : '',
|
|
legacyFiliale ? `<span class="inline-flex items-center gap-1 rounded border border-slate-200 bg-white px-2 py-0.5">Filiale: ${escapeHtml(legacyFiliale)}</span>` : ''
|
|
].filter(Boolean).join('<span class="text-slate-300">•</span>');
|
|
|
|
const row = document.createElement('div');
|
|
row.className = 'banca-mapping-row border border-slate-200 rounded-lg p-4 bg-white shadow-sm hover:shadow transition-shadow';
|
|
row.setAttribute('data-mapping-cod', codice);
|
|
row.setAttribute('data-descrizione-legacy', legacyDescr || '');
|
|
row.innerHTML = `
|
|
<div class="flex flex-col md:flex-row md:items-start md:justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-slate-800">${escapeHtml(codice)} — ${escapeHtml(legacyDescr || 'Conto senza descrizione')}</div>
|
|
<div class="legacy-tags flex flex-wrap gap-2 mt-2 text-[11px] text-slate-500">${legacyBadges || '<span>Dati legacy non disponibili</span>'}</div>
|
|
</div>
|
|
<div class="flex items-center gap-3 text-xs">
|
|
<label class="flex items-center gap-2 text-slate-600">
|
|
<input type="checkbox" class="h-4 w-4 rounded border-slate-300 text-blue-600 focus:ring-blue-500" name="banche_mapping[${idx}][target][is_nostro_conto]" value="1" onchange="syncBancheJson()">
|
|
Conto principale
|
|
</label>
|
|
<button type="button" class="netgescon-btn netgescon-btn-xs netgescon-btn-outline-danger" onclick="removeBancaMappingRow(this)">Rimuovi</button>
|
|
</div>
|
|
</div>
|
|
<div class="grid gap-3 mt-4 text-xs md:grid-cols-2 xl:grid-cols-3">
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Tipo conto</label>
|
|
<select name="banche_mapping[${idx}][tipo_conto]" class="netgescon-input" onchange="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
<option value="bancario">Bancario</option>
|
|
<option value="contanti">Cassa contanti</option>
|
|
<option value="postale">Postale</option>
|
|
<option value="risparmio">Risparmio</option>
|
|
<option value="altro">Altro</option>
|
|
</select>
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Denominazione banca</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][denominazione_banca]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Intestazione conto</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][intestazione_conto]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Numero conto</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][numero_conto]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">IBAN</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][iban]" value="${escapeHtml(legacyIban)}" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">BIC / SWIFT</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][bic_swift]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">ABI</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][abi]" value="${escapeHtml(legacyAbi)}" class="netgescon-input" maxlength="5" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">CAB</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][cab]" value="${escapeHtml(legacyCab)}" class="netgescon-input" maxlength="5" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">CUC</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][cuc]" value="${escapeHtml(legacyCuc)}" class="netgescon-input" maxlength="10" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">CIN</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][cin]" value="${escapeHtml(legacyCin)}" class="netgescon-input" maxlength="1" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Valuta</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][valuta]" value="EUR" class="netgescon-input" maxlength="3" oninput="syncBancheJson()" style="padding:.35rem .5rem; text-transform:uppercase;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Saldo iniziale</label>
|
|
<input type="number" step="0.01" name="banche_mapping[${idx}][target][saldo_iniziale]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Data saldo</label>
|
|
<input type="date" name="banche_mapping[${idx}][target][data_saldo_iniziale]" class="netgescon-input" onchange="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Stato</label>
|
|
<select name="banche_mapping[${idx}][target][stato_conto]" class="netgescon-input" onchange="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
<option value="attivo">Attivo</option>
|
|
<option value="sospeso">Sospeso</option>
|
|
<option value="chiuso">Chiuso</option>
|
|
</select>
|
|
</div>
|
|
<div class="flex flex-col gap-1 md:col-span-2 xl:col-span-3">
|
|
<label class="text-slate-600 font-medium">Note</label>
|
|
<textarea name="banche_mapping[${idx}][target][note]" rows="2" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;"></textarea>
|
|
</div>
|
|
<div class="md:col-span-2 xl:col-span-3 border-t border-dashed border-slate-200 pt-3 mt-2">
|
|
<div class="text-[11px] uppercase tracking-wide text-slate-500 font-semibold">Anagrafica contatto / Filiale</div>
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Filiale</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][filiale]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Indirizzo</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][indirizzo]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">CAP</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][cap]" maxlength="5" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Città</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][citta]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Provincia</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][provincia]" maxlength="2" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem; text-transform:uppercase;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Telefono ufficio</label>
|
|
<input type="text" name="banche_mapping[${idx}][target][telefono_ufficio]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">Email</label>
|
|
<input type="email" name="banche_mapping[${idx}][target][email]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
<div class="flex flex-col gap-1">
|
|
<label class="text-slate-600 font-medium">PEC</label>
|
|
<input type="email" name="banche_mapping[${idx}][target][pec]" class="netgescon-input" oninput="syncBancheJson()" style="padding:.35rem .5rem;">
|
|
</div>
|
|
</div>
|
|
<input type="hidden" name="banche_mapping[${idx}][codice_legacy]" value="${escapeHtml(codice)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][descrizione_legacy]" value="${escapeHtml(legacyDescr)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][descrizione]" value="${escapeHtml(legacyDescr)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][iban]" value="${escapeHtml(legacyIban)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][abi]" value="${escapeHtml(legacyAbi)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][cab]" value="${escapeHtml(legacyCab)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][cin]" value="${escapeHtml(legacyCin)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][conto]" value="${escapeHtml(legacyConto)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][intestatario]" value="${escapeHtml(legacyIntestatario)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][swift]" value="${escapeHtml(legacySwift)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][cuc]" value="${escapeHtml(legacyCuc)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][filiale]" value="${escapeHtml(legacyFiliale)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][indirizzo]" value="${escapeHtml(legacyIndirizzo)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][cap]" value="${escapeHtml(legacyCap)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][citta]" value="${escapeHtml(legacyCitta)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][provincia]" value="${escapeHtml(legacyProvincia)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][telefono]" value="${escapeHtml(legacyTelefono)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][email]" value="${escapeHtml(legacyEmail)}">
|
|
<input type="hidden" name="banche_mapping[${idx}][legacy][pec]" value="${escapeHtml(legacyPec)}">
|
|
`;
|
|
container.appendChild(row);
|
|
if (data) {
|
|
populateBancaMappingRow(row, data, legacy);
|
|
}
|
|
enforceDefaultForRow(row, legacy, codice);
|
|
syncBancheJson();
|
|
return row;
|
|
}
|
|
function enforceDefaultForRow(row, legacy, codice) {
|
|
if (!row) return;
|
|
const tipo = row.querySelector('select[name*="[tipo_conto]"]');
|
|
if (tipo && !tipo.value) {
|
|
tipo.value = (codice === 'CON') ? 'contanti' : 'bancario';
|
|
}
|
|
const denominazione = row.querySelector('input[name*="[denominazione_banca]"]');
|
|
if (denominazione && !denominazione.value) {
|
|
denominazione.value = legacy?.descrizione || (codice === 'CON' ? 'Cassa contanti' : '');
|
|
}
|
|
const intestazione = row.querySelector('input[name*="[intestazione_conto]"]');
|
|
if (intestazione && !intestazione.value) {
|
|
intestazione.value = legacy?.intestatario || '';
|
|
}
|
|
const numero = row.querySelector('input[name*="[numero_conto]"]');
|
|
if (numero && !numero.value) {
|
|
numero.value = legacy?.conto || codice;
|
|
}
|
|
const cucInput = row.querySelector('input[name*="[target][cuc]"]');
|
|
if (cucInput && !cucInput.value && legacy?.cuc) {
|
|
cucInput.value = legacy.cuc;
|
|
}
|
|
const stato = row.querySelector('select[name*="[stato_conto]"]');
|
|
if (stato) {
|
|
stato.value = 'attivo';
|
|
}
|
|
const valuta = row.querySelector('input[name*="[valuta]"]');
|
|
if (valuta && !valuta.value) {
|
|
valuta.value = 'EUR';
|
|
}
|
|
const saldo = row.querySelector('input[name*="[saldo_iniziale]"]');
|
|
const saldoLegacy = (legacy?.saldo_euro ?? legacy?.saldo);
|
|
if (saldo && !saldo.value && saldoLegacy !== undefined && saldoLegacy !== null && saldoLegacy !== '') {
|
|
saldo.value = saldoLegacy;
|
|
}
|
|
const dataSaldo = row.querySelector('input[name*="[data_saldo_iniziale]"]');
|
|
if (dataSaldo && !dataSaldo.value && legacy?.data_saldo) {
|
|
try {
|
|
const d = new Date(legacy.data_saldo);
|
|
if (!Number.isNaN(d.getTime())) {
|
|
dataSaldo.value = d.toISOString().substring(0, 10);
|
|
}
|
|
} catch (e) {
|
|
dataSaldo.value = legacy.data_saldo;
|
|
}
|
|
}
|
|
const principale = row.querySelector('input[name*="[is_nostro_conto]"]');
|
|
if (principale && codice === 'CON') {
|
|
principale.checked = true;
|
|
}
|
|
const filiale = row.querySelector('input[name*="[target][filiale]"]');
|
|
if (filiale && !filiale.value && legacy?.filiale) {
|
|
filiale.value = legacy.filiale;
|
|
}
|
|
const indirizzo = row.querySelector('input[name*="[target][indirizzo]"]');
|
|
if (indirizzo && !indirizzo.value && legacy?.indirizzo) {
|
|
indirizzo.value = legacy.indirizzo;
|
|
}
|
|
const cap = row.querySelector('input[name*="[target][cap]"]');
|
|
if (cap && !cap.value && legacy?.cap) {
|
|
cap.value = legacy.cap;
|
|
}
|
|
const citta = row.querySelector('input[name*="[target][citta]"]');
|
|
if (citta && !citta.value && legacy?.citta) {
|
|
citta.value = legacy.citta;
|
|
}
|
|
const provincia = row.querySelector('input[name*="[target][provincia]"]');
|
|
if (provincia && !provincia.value && legacy?.provincia) {
|
|
provincia.value = legacy.provincia;
|
|
}
|
|
const telefono = row.querySelector('input[name*="[target][telefono_ufficio]"]');
|
|
if (telefono && !telefono.value && legacy?.telefono) {
|
|
telefono.value = legacy.telefono;
|
|
}
|
|
const email = row.querySelector('input[name*="[target][email]"]');
|
|
if (email && !email.value && legacy?.email) {
|
|
email.value = legacy.email;
|
|
}
|
|
const pec = row.querySelector('input[name*="[target][pec]"]');
|
|
if (pec && !pec.value && legacy?.pec) {
|
|
pec.value = legacy.pec;
|
|
}
|
|
}
|
|
function populateBancaMappingRow(row, data, legacyDefaults) {
|
|
if (!row || !data) return;
|
|
const target = data.target || {};
|
|
const tipoSelect = row.querySelector('select[name*="[tipo_conto]"]');
|
|
const tipoValue = target.tipo_conto || data.tipo_conto || (row.getAttribute('data-mapping-cod') === 'CON' ? 'contanti' : 'bancario');
|
|
if (tipoSelect && tipoValue) tipoSelect.value = tipoValue;
|
|
|
|
const mapping = {
|
|
'[denominazione_banca]': target.denominazione_banca || data.denominazione_banca || data.descrizione_legacy || legacyDefaults?.descrizione || '',
|
|
'[intestazione_conto]': target.intestazione_conto || data.intestazione_conto || legacyDefaults?.intestatario || '',
|
|
'[numero_conto]': target.numero_conto || data.numero_conto || data.target_cod_cassa || legacyDefaults?.conto || data.codice_legacy || row.getAttribute('data-mapping-cod'),
|
|
'[iban]': target.iban || data.iban || data.legacy?.iban || legacyDefaults?.iban || '',
|
|
'[bic_swift]': target.bic_swift || data.swift || data.bic_swift || legacyDefaults?.swift || '',
|
|
'[abi]': target.abi || data.abi || data.legacy?.abi || legacyDefaults?.abi || '',
|
|
'[cab]': target.cab || data.cab || data.legacy?.cab || legacyDefaults?.cab || '',
|
|
'[target][cuc]': target.cuc || data.cuc || data.legacy?.cuc || legacyDefaults?.cuc || '',
|
|
'[cin]': target.cin || data.cin || data.legacy?.cin || legacyDefaults?.cin || '',
|
|
'[valuta]': target.valuta || data.valuta || 'EUR',
|
|
'[saldo_iniziale]': target.saldo_iniziale ?? data.saldo_iniziale ?? '',
|
|
'[data_saldo_iniziale]': target.data_saldo_iniziale || data.data_saldo_iniziale || '',
|
|
'[note]': target.note || data.note || '',
|
|
'[target][filiale]': target.filiale || data.filiale || data.target_filiale || legacyDefaults?.filiale || '',
|
|
'[target][indirizzo]': target.indirizzo || data.indirizzo || data.target_indirizzo || legacyDefaults?.indirizzo || '',
|
|
'[target][cap]': target.cap || data.cap || data.target_cap || legacyDefaults?.cap || '',
|
|
'[target][citta]': target.citta || data.citta || data.target_citta || legacyDefaults?.citta || '',
|
|
'[target][provincia]': target.provincia || data.provincia || data.target_provincia || legacyDefaults?.provincia || '',
|
|
'[target][telefono_ufficio]': target.telefono_ufficio || data.telefono_ufficio || data.telefono || legacyDefaults?.telefono || '',
|
|
'[target][email]': target.email || data.email || data.target_email || legacyDefaults?.email || '',
|
|
'[target][pec]': target.pec || data.pec || data.target_pec || legacyDefaults?.pec || ''
|
|
};
|
|
Object.entries(mapping).forEach(([suffix, value]) => {
|
|
const selector = suffix === '[note]'
|
|
? `textarea[name*="${suffix}"]`
|
|
: `input[name*="${suffix}"]`;
|
|
const el = row.querySelector(selector);
|
|
if (el !== null && value !== undefined && value !== null) {
|
|
if (el.type === 'date' && typeof value === 'string' && value.includes('/')) {
|
|
const [d, m, y] = value.split(/[\/\-]/);
|
|
if (d && m && y) {
|
|
const iso = `${y.length === 2 ? '20' + y : y}-${String(m).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
|
|
el.value = iso;
|
|
} else {
|
|
el.value = value;
|
|
}
|
|
} else {
|
|
el.value = String(value);
|
|
}
|
|
}
|
|
});
|
|
const stato = row.querySelector('select[name*="[stato_conto]"]');
|
|
if (stato) {
|
|
stato.value = target.stato_conto || data.stato_conto || 'attivo';
|
|
}
|
|
const principale = row.querySelector('input[name*="[is_nostro_conto]"]');
|
|
if (principale) {
|
|
const checked = target.is_nostro_conto ?? data.is_nostro_conto ?? data.target_is_nostro_conto ?? (row.getAttribute('data-mapping-cod') === 'CON');
|
|
principale.checked = Boolean(checked);
|
|
}
|
|
}
|
|
function removeBancaMappingRow(trigger) {
|
|
const row = trigger?.closest('.banca-mapping-row');
|
|
const container = row?.parentElement;
|
|
if (row) row.remove();
|
|
if (container && !container.querySelector('.banca-mapping-row')) {
|
|
renderBanchePlaceholder(container);
|
|
}
|
|
syncBancheJson();
|
|
}
|
|
function ensureMandatoryConMapping() {
|
|
if (__legacyCasse.find(c => c.codice === 'CON')) {
|
|
const container = document.getElementById('banche-mapping-rows');
|
|
if (container && !container.querySelector('[data-mapping-cod="CON"]')) {
|
|
addBancaMapping('CON');
|
|
}
|
|
const conRow = container?.querySelector('[data-mapping-cod="CON"]');
|
|
if (conRow) {
|
|
const tipo = conRow.querySelector('select[name*="[tipo_conto]"]');
|
|
if (tipo) tipo.value = 'contanti';
|
|
const principale = conRow.querySelector('input[name*="[is_nostro_conto]"]');
|
|
if (principale) principale.checked = true;
|
|
}
|
|
syncBancheJson();
|
|
}
|
|
}
|
|
function collectValue(row, selector) {
|
|
const el = row.querySelector(selector);
|
|
if (!el) return null;
|
|
const value = el.value;
|
|
if (typeof value === 'string') {
|
|
const trimmed = value.trim();
|
|
return trimmed === '' ? null : trimmed;
|
|
}
|
|
return value ?? null;
|
|
}
|
|
function syncBancheJson() {
|
|
const container = document.getElementById('banche-mapping-rows');
|
|
const rows = [...(container?.querySelectorAll('.banca-mapping-row') || [])];
|
|
const normalized = rows.map(row => {
|
|
const legacy = {
|
|
descrizione: collectValue(row, 'input[name*="[legacy][descrizione]"]'),
|
|
iban: collectValue(row, 'input[name*="[legacy][iban]"]'),
|
|
abi: collectValue(row, 'input[name*="[legacy][abi]"]'),
|
|
cab: collectValue(row, 'input[name*="[legacy][cab]"]'),
|
|
cin: collectValue(row, 'input[name*="[legacy][cin]"]'),
|
|
cuc: collectValue(row, 'input[name*="[legacy][cuc]"]'),
|
|
conto: collectValue(row, 'input[name*="[legacy][conto]"]'),
|
|
intestatario: collectValue(row, 'input[name*="[legacy][intestatario]"]'),
|
|
swift: collectValue(row, 'input[name*="[legacy][swift]"]')
|
|
};
|
|
Object.keys(legacy).forEach(key => { if (legacy[key] === null) delete legacy[key]; });
|
|
|
|
const target = {
|
|
tipo_conto: collectValue(row, 'select[name*="[tipo_conto]"]'),
|
|
denominazione_banca: collectValue(row, 'input[name*="[denominazione_banca]"]'),
|
|
intestazione_conto: collectValue(row, 'input[name*="[intestazione_conto]"]'),
|
|
numero_conto: collectValue(row, 'input[name*="[numero_conto]"]'),
|
|
iban: collectValue(row, 'input[name*="[target][iban]"]'),
|
|
bic_swift: collectValue(row, 'input[name*="[bic_swift]"]'),
|
|
abi: collectValue(row, 'input[name*="[abi]"]'),
|
|
cab: collectValue(row, 'input[name*="[cab]"]'),
|
|
cuc: collectValue(row, 'input[name*="[target][cuc]"]'),
|
|
cin: collectValue(row, 'input[name*="[cin]"]'),
|
|
valuta: collectValue(row, 'input[name*="[valuta]"]'),
|
|
saldo_iniziale: collectValue(row, 'input[name*="[saldo_iniziale]"]'),
|
|
data_saldo_iniziale: collectValue(row, 'input[name*="[data_saldo_iniziale]"]'),
|
|
note: collectValue(row, 'textarea[name*="[note]"]'),
|
|
stato_conto: collectValue(row, 'select[name*="[stato_conto]"]'),
|
|
filiale: collectValue(row, 'input[name*="[target][filiale]"]'),
|
|
indirizzo: collectValue(row, 'input[name*="[target][indirizzo]"]'),
|
|
cap: collectValue(row, 'input[name*="[target][cap]"]'),
|
|
citta: collectValue(row, 'input[name*="[target][citta]"]'),
|
|
provincia: collectValue(row, 'input[name*="[target][provincia]"]'),
|
|
telefono_ufficio: collectValue(row, 'input[name*="[target][telefono_ufficio]"]'),
|
|
email: collectValue(row, 'input[name*="[target][email]"]'),
|
|
pec: collectValue(row, 'input[name*="[target][pec]"]'),
|
|
is_nostro_conto: row.querySelector('input[name*="[is_nostro_conto]"]')?.checked || false
|
|
};
|
|
Object.keys(target).forEach(key => {
|
|
const value = target[key];
|
|
if (key === 'is_nostro_conto') {
|
|
if (!value) delete target[key];
|
|
return;
|
|
}
|
|
if (value === null || value === undefined || value === '') {
|
|
delete target[key];
|
|
}
|
|
});
|
|
const entry = {
|
|
codice_legacy: row.getAttribute('data-mapping-cod') || null,
|
|
descrizione_legacy: row.getAttribute('data-descrizione-legacy') || null,
|
|
tipo_conto: target.tipo_conto || 'bancario',
|
|
legacy: Object.keys(legacy).length ? legacy : null,
|
|
target
|
|
};
|
|
entry.iban = target.iban || legacy.iban || null;
|
|
entry.swift = target.bic_swift || legacy.swift || null;
|
|
entry.cuc = target.cuc || legacy.cuc || null;
|
|
entry.numero_conto = target.numero_conto || null;
|
|
entry.is_nostro_conto = Boolean(target.is_nostro_conto);
|
|
return entry;
|
|
});
|
|
const hidden = document.getElementById('banche_mapping_json'); if (hidden) hidden.value = JSON.stringify(normalized);
|
|
}
|
|
async function saveBancheMapping(e) {
|
|
e.preventDefault();
|
|
syncBancheJson();
|
|
const form = e.target;
|
|
const fd = new FormData(form);
|
|
try {
|
|
const res = await fetch(R('mappingSave'), { method: 'POST', headers: { 'X-CSRF-TOKEN': CSRF }, body: fd });
|
|
if (res.redirected) { window.location.href = res.url; return false; }
|
|
alert(res.ok ? 'Mapping banche salvato' : 'Errore salvataggio banche');
|
|
} catch (err) { alert('Errore rete'); }
|
|
return false;
|
|
}
|
|
|
|
// ===== Unità (singolo_anno.mdb / condomin) =====
|
|
let __legacyYears = [];
|
|
let __currentUnitaYearIdx = 0;
|
|
async function loadLegacyYears() {
|
|
const nav = document.getElementById('unita-year-nav');
|
|
const label = document.getElementById('unita-year-label');
|
|
const badges = document.getElementById('years-badges');
|
|
if (!nav || !label) return;
|
|
try {
|
|
const url = R('years') + '?legacy_code=' + encodeURIComponent(LEGACY);
|
|
const res = await fetch(url);
|
|
if (!res.ok) throw new Error('HTTP ' + res.status);
|
|
const js = await res.json();
|
|
__legacyYears = Array.isArray(js.years) ? js.years.map(y => String(y)) : [];
|
|
if (__legacyYears.length) {
|
|
nav.style.display = 'flex';
|
|
__currentUnitaYearIdx = __legacyYears.length - 1;
|
|
label.textContent = __legacyYears[__currentUnitaYearIdx];
|
|
const l2 = document.getElementById('unita-anno-label-2'); if (l2) l2.textContent = label.textContent;
|
|
// Render years badges if container exists
|
|
if (badges) {
|
|
badges.innerHTML = '<span>Anni:</span>' + __legacyYears.map(y => '<span class="netgescon-badge netgescon-badge-light">' + escapeHtml(y) + '</span>').join('');
|
|
}
|
|
// Pre-set Staging Loader base URL (without specific file)
|
|
try { const btn = document.getElementById('btn-unita-loader'); if (btn && R('archiveUi')) { btn.href = R('archiveUi'); } } catch (_) { }
|
|
try { await refreshUnitaPreview(); } catch (e) { }
|
|
} else {
|
|
// Nessun anno rilevato: mostra la nav con placeholder e prova fallback su staging (senza anno)
|
|
nav.style.display = 'flex';
|
|
label.textContent = '—';
|
|
const l2 = document.getElementById('unita-anno-label-2'); if (l2) l2.textContent = '—';
|
|
if (badges) { badges.innerHTML = ''; }
|
|
try { const btn = document.getElementById('btn-unita-loader'); if (btn && R('archiveUi')) { btn.href = R('archiveUi'); } } catch (_) { }
|
|
try { await refreshUnitaPreview(); } catch (e) { }
|
|
}
|
|
} catch (e) {
|
|
// In caso di errore nel recupero anni, visualizza comunque la nav e tenta preview fallback
|
|
nav.style.display = 'flex';
|
|
label.textContent = '—';
|
|
const l2 = document.getElementById('unita-anno-label-2'); if (l2) l2.textContent = '—';
|
|
if (badges) { badges.innerHTML = ''; }
|
|
try { const btn = document.getElementById('btn-unita-loader'); if (btn && R('archiveUi')) { btn.href = R('archiveUi'); } } catch (_) { }
|
|
try { await refreshUnitaPreview(); } catch (_) { }
|
|
}
|
|
}
|
|
function browseUnitaYear(delta) {
|
|
if (!__legacyYears.length) return;
|
|
__currentUnitaYearIdx = Math.min(__legacyYears.length - 1, Math.max(0, __currentUnitaYearIdx + (delta || 0)));
|
|
const label = document.getElementById('unita-year-label'); if (label) label.textContent = __legacyYears[__currentUnitaYearIdx] || '—';
|
|
const l2 = document.getElementById('unita-anno-label-2'); if (l2) l2.textContent = label?.textContent || '—';
|
|
}
|
|
async function syncUnitaCurrentYear() {
|
|
const year = __legacyYears[__currentUnitaYearIdx];
|
|
if (!year) { alert('Nessun anno disponibile.'); return; }
|
|
if (!confirm('Sincronizzare le unità per l\'anno ' + year + '? L\'operazione è idempotente.')) return;
|
|
try {
|
|
const payload = { legacy_code: LEGACY, steps: ['unita', 'soggetti', 'diritti'], anno: Number(year), dry_run: false };
|
|
const res = await fetch(R('importUnita'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF }, body: JSON.stringify(payload) });
|
|
const js = await res.json().catch(() => ({}));
|
|
if (!res.ok || js.ok === false) {
|
|
const failing = (js.results || []).filter(r => r && r.ok === false).map(r => r.step).join(', ');
|
|
alert('Sync Unità fallita: ' + (js.error || failing || res.status));
|
|
return;
|
|
}
|
|
alert('Sync Unità eseguita su ' + year + ': ' + (js.results || []).map(r => r.step + ':' + (r.ok ? 'OK' : 'FAIL')).join(' | '));
|
|
} catch (e) { alert('Errore rete sync unità'); }
|
|
}
|
|
async function refreshUnitaPreview() {
|
|
const years = __legacyYears || [];
|
|
const idx = __currentUnitaYearIdx || 0;
|
|
const year = years[idx];
|
|
const lbl2 = document.getElementById('unita-anno-label-2'); if (lbl2) lbl2.textContent = year || '—';
|
|
const head = document.getElementById('unita-legacy-head'); const body = document.getElementById('unita-legacy-body');
|
|
if (!LEGACY || !head || !body) { if (body) body.innerHTML = '<tr><td class="text-xs text-gray-500">Dati non disponibili.</td></tr>'; return; }
|
|
body.innerHTML = '<tr><td class="text-xs text-gray-500">Caricamento…</td></tr>';
|
|
try {
|
|
let url = R('unitaYear') + '?legacy_code=' + encodeURIComponent(LEGACY) + '&limit=50';
|
|
if (year) { url += '&anno=' + encodeURIComponent(year); }
|
|
const res = await fetch(url);
|
|
const js = await res.json().catch(() => ({}));
|
|
if (!res.ok || js.ok === false) { head.innerHTML = '<th>—</th>'; body.innerHTML = '<tr><td class="text-xs text-danger">Errore o nessun dato</td></tr>'; return; }
|
|
renderUnitaPreview(js.headers || [], js.rows || []);
|
|
} catch (e) { head.innerHTML = '<th>—</th>'; body.innerHTML = '<tr><td class="text-xs text-danger">Errore rete</td></tr>'; }
|
|
}
|
|
function renderUnitaPreview(headers, rows) {
|
|
const head = document.getElementById('unita-legacy-head'); const body = document.getElementById('unita-legacy-body');
|
|
if (!head || !body) { return; }
|
|
const shown = (headers || []).filter(h => !/^memo$/i.test(h)).slice(0, 12);
|
|
if (!shown.length) { head.innerHTML = '<th>—</th>'; body.innerHTML = '<tr><td class="text-xs text-gray-500">Nessun dato.</td></tr>'; return; }
|
|
head.innerHTML = shown.map(h => '<th>' + escapeHtml(h) + '</th>').join('');
|
|
if (!rows || !rows.length) { body.innerHTML = '<tr><td colspan="' + shown.length + '" class="text-xs text-gray-500">Nessuna riga.</td></tr>'; return; }
|
|
body.innerHTML = rows.map(r => '<tr>' + shown.map(h => '<td class="text-xs legacy-value" data-field-value="' + escapeHtml(h) + '">' + escapeHtml(String(r[h] ?? '')) + '</td>').join('') + '</tr>').join('');
|
|
}
|
|
|
|
// ===== Import & actions =====
|
|
function handleImportConfirm(form, blocked, legacyCode) {
|
|
if (blocked) { return false; }
|
|
if (!legacyCode) { return confirm('Importare lo STABILE (solo anagrafica)?'); }
|
|
return confirm('Importare lo STABILE (solo anagrafica) per il legacy ' + legacyCode + '?');
|
|
}
|
|
function saveMapping() { return true; }
|
|
function resetMapping() { document.querySelectorAll('#mapping-form select').forEach(s => s.value = ''); }
|
|
async function giCreaGestione() {
|
|
try {
|
|
const anno = parseInt(document.getElementById('giAnno').value || (new Date()).getFullYear());
|
|
const tipo = document.getElementById('giTipo').value;
|
|
const legacy = document.getElementById('giLegacy').value || '';
|
|
const mesi = {};
|
|
document.querySelectorAll('.giMese').forEach(c => { if (c.checked) { mesi[c.dataset.mese] = 'on'; } });
|
|
const url = CFG.routes.stabiliGestioneStore || '#';
|
|
if (!url || url === '#') throw new Error('Nessuno stabile selezionato');
|
|
const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF }, body: JSON.stringify({ anno_gestione: anno, tipo_gestione: tipo, codice_archivio_legacy: legacy, mesi }) });
|
|
if (!res.ok) throw new Error('Errore durante la creazione');
|
|
window.location.href = (CFG.routes.stabileShow || '') + '#tab-gestioni';
|
|
} catch (e) { alert(e.message || 'Errore'); }
|
|
}
|
|
async function applyMappingImport(legacyCode, stabileId) {
|
|
if (!legacyCode || !stabileId) return;
|
|
if (!confirm('Applicare il mapping (conti + gestioni) allo stabile selezionato?')) return;
|
|
try {
|
|
const payload = { legacy_code: legacyCode, stabile_id: stabileId };
|
|
const res = await fetch(R('applyMapping'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF }, body: JSON.stringify(payload) });
|
|
const js = await res.json().catch(() => ({}));
|
|
if (!res.ok || !js.ok) { alert('Errore applicazione mapping: ' + (js.error || res.status)); return; }
|
|
alert('Mapping applicato. Conti creati: ' + js.conti.created + ' (upd ' + js.conti.updated + '). Gestioni create: ' + js.gestioni.created + ' (upd ' + js.gestioni.updated + ').');
|
|
setTimeout(() => { if (CFG.routes.stabileShow) { window.location.href = CFG.routes.stabileShow + '#tab-gestioni'; } }, 600);
|
|
} catch (e) { alert('Errore rete / runtime'); }
|
|
}
|
|
async function quickSaveAdminCf() {
|
|
try {
|
|
const url = CFG.routes.stabileAdminQuick || '';
|
|
if (!url) { alert('Stabile non selezionato'); return; }
|
|
const cf = (document.getElementById('quickAdminCf')?.value || '').trim();
|
|
const res = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF }, body: JSON.stringify({ cod_fisc_amministratore: cf }) });
|
|
const js = await res.json().catch(() => ({}));
|
|
if (!res.ok || js.ok === false) { alert('Errore salvataggio CF amministratore'); return; }
|
|
alert('CF amministratore aggiornato');
|
|
} catch (e) { alert('Errore rete'); }
|
|
}
|
|
async function quickImportStabile(legacy) {
|
|
if (!legacy) return; if (!confirm('Eseguire import rapido per lo stabile ' + legacy + '?')) return;
|
|
try {
|
|
const res = await fetch(R('quickStabile'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF }, body: JSON.stringify({ legacy_code: legacy }) });
|
|
const js = await res.json().catch(() => ({}));
|
|
if (!res.ok || !js.ok) { alert('Errore import rapido: ' + (js.error || res.status)); return; }
|
|
alert('Import rapido OK: ' + (js.created ? 'Creato' : 'Aggiornato') + ' ID ' + js.stabile_id);
|
|
setTimeout(() => window.location.reload(), 600);
|
|
} catch (e) { alert('Errore rete import rapido'); }
|
|
}
|
|
async function microImportStabile(legacy) {
|
|
if (!legacy) return; if (!confirm('Eseguire MICRO import per lo stabile ' + legacy + '?')) return;
|
|
try {
|
|
const res = await fetch(R('microImportStabile'), { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': CSRF }, body: JSON.stringify({ legacy_code: legacy }) });
|
|
const js = await res.json().catch(() => ({}));
|
|
if (!res.ok || !js.ok) { alert('Errore micro import: ' + (js.error || res.status)); return; }
|
|
alert('Micro import OK: ' + (js.created ? 'Creato' : 'Aggiornato') + ' ID ' + js.stabile_id + '\nFonte: ' + (js.source || '-'));
|
|
setTimeout(() => window.location.reload(), 600);
|
|
} catch (e) { alert('Errore rete micro import'); }
|
|
}
|
|
|
|
// Expose minimal API for inline handlers in markup
|
|
window.switchSegment = switchSegment;
|
|
window.syncMappingSearch = syncMappingSearch;
|
|
window.setMappingFilter = setMappingFilter;
|
|
window.applyPreset = applyPreset;
|
|
window.updatePresetMeta = updatePresetMeta;
|
|
window.updateMappingPreviews = updateMappingPreviews;
|
|
window.promptAddField = promptAddField;
|
|
window.browseSample = function (delta) { return browseSample(delta); };
|
|
window.loadSample = function (idx) { return loadSample(idx); };
|
|
window.syncLegacyPreview = syncLegacyPreview;
|
|
window.__toggleInlineCreate = function (trigger, show) { toggleInlineCreate(trigger, show !== false); };
|
|
window.handleImportConfirm = handleImportConfirm;
|
|
window.saveMapping = saveMapping;
|
|
window.resetMapping = resetMapping;
|
|
window.populateGestioneRatesFromData = populateGestioneRatesFromData;
|
|
window.browseGestioneYear = browseGestioneYear;
|
|
window.loadGestioneYearData = loadGestioneYearData;
|
|
window.loadLegacyCasse = loadLegacyCasse;
|
|
window.renderLegacyCasse = renderLegacyCasse;
|
|
window.filterLegacyCasse = filterLegacyCasse;
|
|
window.addBancaMapping = addBancaMapping;
|
|
window.removeBancaMappingRow = removeBancaMappingRow;
|
|
window.syncBancheJson = syncBancheJson;
|
|
window.saveBancheMapping = saveBancheMapping;
|
|
window.loadLegacyYears = loadLegacyYears;
|
|
window.browseUnitaYear = browseUnitaYear;
|
|
window.syncUnitaCurrentYear = syncUnitaCurrentYear;
|
|
window.refreshUnitaPreview = refreshUnitaPreview;
|
|
window.giCreaGestione = giCreaGestione;
|
|
window.applyMappingImport = applyMappingImport;
|
|
window.quickSaveAdminCf = quickSaveAdminCf;
|
|
window.quickImportStabile = quickImportStabile;
|
|
window.microImportStabile = microImportStabile;
|
|
window.addManualValueRow = addManualValueRow;
|
|
window.syncManualValueRow = syncManualValueRow;
|
|
window.removeManualValueRow = removeManualValueRow;
|
|
window.escapeHtml = escapeHtml;
|
|
|
|
// Init on DOM ready
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
// Export target fields
|
|
window.__targetFields = Array.isArray(CFG.targetFields) ? CFG.targetFields : [];
|
|
initializeManualValueRows();
|
|
// Presets
|
|
try {
|
|
const sel = document.getElementById('preset-select');
|
|
if (sel) {
|
|
sel.value = CFG.savedPresetKey || (CFG.defaultPreset || 'stabili_full');
|
|
document.getElementById('preset_key').value = sel.value || '';
|
|
updatePresetMeta();
|
|
if (!CFG.savedPresetKey) applyPreset();
|
|
}
|
|
} catch (e) { }
|
|
// Initial sample
|
|
browseSample(0);
|
|
// Init filter state
|
|
setMappingFilter('all');
|
|
// Init years and casse if legacy selected
|
|
if (LEGACY) {
|
|
loadLegacyYears();
|
|
loadLegacyCasse();
|
|
(async () => {
|
|
try {
|
|
const hasYears = Array.isArray(CFG.availableYears) && CFG.availableYears.length;
|
|
if (!hasYears) {
|
|
const res = await fetch(R('years') + '?legacy_code=' + encodeURIComponent(LEGACY));
|
|
if (res.ok) {
|
|
const js = await res.json();
|
|
const yrs = Array.isArray(js.years) ? js.years : [];
|
|
if (yrs.length) {
|
|
__gestioniYears = yrs;
|
|
__gestioniYearIndex = Math.max(0, __gestioniYears.length - 1);
|
|
updateGestioneYearUI();
|
|
try { await loadGestioneYearData(); } catch (e) { }
|
|
}
|
|
}
|
|
} else {
|
|
try { await loadGestioneYearData(); } catch (e) { }
|
|
}
|
|
} catch (e) { }
|
|
})();
|
|
}
|
|
// Progress bar feedback on import submits
|
|
document.querySelectorAll('.js-import-form').forEach(f => {
|
|
f.addEventListener('submit', () => {
|
|
const box = document.getElementById('import-progress');
|
|
if (box) box.classList.remove('d-none');
|
|
let p = 15; const bar = document.getElementById('import-progress-bar');
|
|
const timer = setInterval(() => { p = Math.min(90, p + Math.random() * 7); if (bar) bar.style.width = p + '%'; }, 400);
|
|
f.querySelectorAll('button[type="submit"]').forEach(b => b.setAttribute('disabled', 'disabled'));
|
|
}, { once: true });
|
|
});
|
|
// Year UI update
|
|
(function () { const lbl = document.getElementById('gestione-year-label'); if (lbl) { updateGestioneYearUI(); } })();
|
|
});
|
|
|
|
// Diagnostic: capture JS errors to help debug
|
|
window.addEventListener('error', function (ev) {
|
|
try {
|
|
const boxId = 'gescon-mapping-diagnostics';
|
|
let box = document.getElementById(boxId);
|
|
if (!box) {
|
|
box = document.createElement('div');
|
|
box.id = boxId;
|
|
box.style.cssText = 'position:fixed;bottom:6px;right:6px;z-index:9999;background:#fee;border:1px solid #f99;padding:6px 10px;font:12px monospace;max-width:420px;max-height:180px;overflow:auto;';
|
|
box.innerHTML = '<strong>JS Error</strong><br>';
|
|
document.body.appendChild(box);
|
|
}
|
|
box.innerHTML += (ev.message + ' @' + (ev.filename || '') + ':' + ev.lineno + '<br>');
|
|
} catch (e) { }
|
|
});
|
|
})();
|