feat: auto-reprocess faktura når panel åbnes uden AI-data v2.2.29
This commit is contained in:
parent
d561a063f6
commit
8a0dbcd1cc
@ -2115,67 +2115,145 @@ async function openQuickVendorCreate(fileId, filename) {
|
||||
modal.show();
|
||||
|
||||
// Async: load extracted data and pre-fill form
|
||||
await qvLoadAndPrefill(fileId);
|
||||
}
|
||||
|
||||
async function qvLoadAndPrefill(fileId) {
|
||||
const statusEl = document.getElementById('qvStatusAlert');
|
||||
try {
|
||||
const resp = await fetch(`/api/v1/supplier-invoices/files/${fileId}/extracted-data`);
|
||||
if (resp.ok) {
|
||||
const data = await resp.json();
|
||||
if (!resp.ok) { throw new Error(`HTTP ${resp.status}`); }
|
||||
const data = await resp.json();
|
||||
|
||||
// Brug det server-normaliserede llm_data objekt som primær kilde
|
||||
// Backend normaliserer feltnavne fra både AI (vendor_name) og invoice2data (issuer)
|
||||
const ld = data.llm_data || {};
|
||||
const ext = data.extraction || {};
|
||||
// Brug det server-normaliserede llm_data objekt som primær kilde
|
||||
const ld = data.llm_data || {};
|
||||
const ext = data.extraction || {};
|
||||
|
||||
// llm_response_json kan være objekt (JSONB) eller string – parse sikkert som fallback
|
||||
let rawAi = {};
|
||||
const rawLlm = ext.llm_response_json;
|
||||
if (rawLlm) {
|
||||
if (typeof rawLlm === 'string') {
|
||||
try { rawAi = JSON.parse(rawLlm); } catch(e) {}
|
||||
} else if (typeof rawLlm === 'object') {
|
||||
rawAi = rawLlm;
|
||||
// llm_response_json kan være objekt (JSONB) eller string – parse sikkert som fallback
|
||||
let rawAi = {};
|
||||
const rawLlm = ext.llm_response_json;
|
||||
if (rawLlm) {
|
||||
if (typeof rawLlm === 'string') {
|
||||
try { rawAi = JSON.parse(rawLlm); } catch(e) {}
|
||||
} else if (typeof rawLlm === 'object') {
|
||||
rawAi = rawLlm;
|
||||
}
|
||||
}
|
||||
|
||||
// Prioriter llm_data (server-normaliseret) → extraction kolonne → raw AI JSON
|
||||
const name = ld.vendor_name || ext.vendor_name || rawAi.vendor_name || rawAi.issuer || '';
|
||||
const cvr = (ld.vendor_cvr || ext.vendor_cvr || rawAi.vendor_cvr || rawAi.vendor_vat || '').toString().replace(/^DK/i, '').trim();
|
||||
const email = ld.vendor_email || rawAi.vendor_email || rawAi.supplier_email || '';
|
||||
const addr = ld.vendor_address || rawAi.vendor_address || rawAi.supplier_address || rawAi.vendor_street || '';
|
||||
const postal = ld.vendor_postal_code || rawAi.vendor_postal_code || rawAi.postal_code || '';
|
||||
const city = ld.vendor_city || rawAi.vendor_city || rawAi.city || '';
|
||||
|
||||
// Ingen data endnu – start automatisk reprocess
|
||||
if (!name && !cvr && !ext) {
|
||||
await qvAutoReprocess(fileId);
|
||||
return;
|
||||
}
|
||||
// Har extraction-række men ingen vendordata – prøv reprocess én gang
|
||||
if (!name && !cvr && !data._reprocessed) {
|
||||
await qvAutoReprocess(fileId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (name) document.getElementById('qvName').value = name;
|
||||
if (cvr) document.getElementById('qvCVR').value = cvr;
|
||||
if (email) document.getElementById('qvEmail').value = email;
|
||||
|
||||
if (addr) {
|
||||
const parts = addr.split(/,|\n/).map(s => s.trim()).filter(Boolean);
|
||||
if (parts.length >= 1) document.getElementById('qvAddress').value = parts[0];
|
||||
if (!postal && !city && parts.length >= 2) {
|
||||
const postalCity = parts[parts.length - 1];
|
||||
const m = postalCity.match(/^(\d{4})\s+(.+)$/);
|
||||
if (m) {
|
||||
document.getElementById('qvPostal').value = m[1];
|
||||
document.getElementById('qvCity').value = m[2];
|
||||
} else {
|
||||
document.getElementById('qvCity').value = postalCity;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (postal) document.getElementById('qvPostal').value = postal;
|
||||
if (city) document.getElementById('qvCity').value = city;
|
||||
|
||||
// Prioriter llm_data (server-normaliseret) → extraction kolonne → raw AI JSON
|
||||
const name = ld.vendor_name || ext.vendor_name || rawAi.vendor_name || rawAi.issuer || '';
|
||||
const cvr = (ld.vendor_cvr || ext.vendor_cvr || rawAi.vendor_cvr || rawAi.vendor_vat || '').toString().replace(/^DK/i, '').trim();
|
||||
const email = ld.vendor_email || rawAi.vendor_email || rawAi.supplier_email || '';
|
||||
const addr = ld.vendor_address || rawAi.vendor_address || rawAi.supplier_address || rawAi.vendor_street || '';
|
||||
const postal = ld.vendor_postal_code || rawAi.vendor_postal_code || rawAi.postal_code || '';
|
||||
const city = ld.vendor_city || rawAi.vendor_city || rawAi.city || '';
|
||||
|
||||
if (name) document.getElementById('qvName').value = name;
|
||||
if (cvr) document.getElementById('qvCVR').value = cvr;
|
||||
if (email) document.getElementById('qvEmail').value = email;
|
||||
|
||||
if (addr) {
|
||||
// Forsøg at splitte samlet adresse i gade / postnr / by
|
||||
const parts = addr.split(/,|\n/).map(s => s.trim()).filter(Boolean);
|
||||
if (parts.length >= 1) document.getElementById('qvAddress').value = parts[0];
|
||||
if (!postal && !city && parts.length >= 2) {
|
||||
const postalCity = parts[parts.length - 1];
|
||||
const m = postalCity.match(/^(\d{4})\s+(.+)$/);
|
||||
if (m) {
|
||||
document.getElementById('qvPostal').value = m[1];
|
||||
document.getElementById('qvCity').value = m[2];
|
||||
} else {
|
||||
document.getElementById('qvCity').value = postalCity;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Separate adressefelter
|
||||
if (postal) document.getElementById('qvPostal').value = postal;
|
||||
if (city) document.getElementById('qvCity').value = city;
|
||||
|
||||
// Vis advarsel hvis ingen relevante data overhovedet
|
||||
if (!name && !cvr) {
|
||||
const statusEl = document.getElementById('qvStatusAlert');
|
||||
statusEl.className = 'alert alert-warning py-2 small';
|
||||
statusEl.textContent = 'Ingen AI-data fundet for denne fil. Kør fakturaen igennem igen (↺) og åbn panelet igen.';
|
||||
}
|
||||
if (name || cvr) {
|
||||
statusEl.className = 'alert alert-success py-2 small';
|
||||
statusEl.textContent = `✅ Data hentet fra faktura${name ? ': ' + name : ''}`;
|
||||
setTimeout(() => { statusEl.className = 'alert d-none py-2 small'; }, 3000);
|
||||
} else {
|
||||
statusEl.className = 'alert alert-warning py-2 small';
|
||||
statusEl.innerHTML = 'AI fandt ingen leverandørdata (fx mangler CVR på fakturaen). Udfyld manuelt eller søg herover.';
|
||||
}
|
||||
} catch(e) {
|
||||
console.warn('Could not pre-fill vendor form:', e);
|
||||
statusEl.className = 'alert alert-danger py-2 small';
|
||||
statusEl.textContent = 'Fejl ved hentning af fakturadata.';
|
||||
}
|
||||
}
|
||||
|
||||
async function qvAutoReprocess(fileId) {
|
||||
const statusEl = document.getElementById('qvStatusAlert');
|
||||
statusEl.className = 'alert alert-info py-2 small';
|
||||
statusEl.innerHTML = '<span class="spinner-border spinner-border-sm me-2"></span>Analyserer faktura med AI – vent venligst…';
|
||||
|
||||
try {
|
||||
const r = await fetch(`/api/v1/supplier-invoices/reprocess/${fileId}`, { method: 'POST' });
|
||||
if (!r.ok) { throw new Error(`Reprocess HTTP ${r.status}`); }
|
||||
|
||||
// Reload data efter reprocess og marker at vi allerede har forsøgt
|
||||
const resp2 = await fetch(`/api/v1/supplier-invoices/files/${fileId}/extracted-data`);
|
||||
if (!resp2.ok) { throw new Error(`Extracted-data HTTP ${resp2.status}`); }
|
||||
const data2 = await resp2.json();
|
||||
data2._reprocessed = true; // forhindrer uendelig løkke
|
||||
|
||||
const ld = data2.llm_data || {};
|
||||
const ext = data2.extraction || {};
|
||||
let rawAi = {};
|
||||
const rawLlm = ext.llm_response_json;
|
||||
if (rawLlm) {
|
||||
if (typeof rawLlm === 'string') { try { rawAi = JSON.parse(rawLlm); } catch(e) {} }
|
||||
else if (typeof rawLlm === 'object') { rawAi = rawLlm; }
|
||||
}
|
||||
const name = ld.vendor_name || ext.vendor_name || rawAi.vendor_name || rawAi.issuer || '';
|
||||
const cvr = (ld.vendor_cvr || ext.vendor_cvr || rawAi.vendor_cvr || rawAi.vendor_vat || '').toString().replace(/^DK/i, '').trim();
|
||||
const email = ld.vendor_email || rawAi.vendor_email || '';
|
||||
const addr = ld.vendor_address || rawAi.vendor_address || rawAi.vendor_street || '';
|
||||
const postal = ld.vendor_postal_code || rawAi.postal_code || '';
|
||||
const city = ld.vendor_city || rawAi.city || '';
|
||||
|
||||
if (name) document.getElementById('qvName').value = name;
|
||||
if (cvr) document.getElementById('qvCVR').value = cvr;
|
||||
if (email) document.getElementById('qvEmail').value = email;
|
||||
if (addr) {
|
||||
const parts = addr.split(/,|\n/).map(s => s.trim()).filter(Boolean);
|
||||
if (parts.length >= 1) document.getElementById('qvAddress').value = parts[0];
|
||||
if (!postal && !city && parts.length >= 2) {
|
||||
const postalCity = parts[parts.length - 1];
|
||||
const m = postalCity.match(/^(\d{4})\s+(.+)$/);
|
||||
if (m) { document.getElementById('qvPostal').value = m[1]; document.getElementById('qvCity').value = m[2]; }
|
||||
else { document.getElementById('qvCity').value = postalCity; }
|
||||
}
|
||||
}
|
||||
if (postal) document.getElementById('qvPostal').value = postal;
|
||||
if (city) document.getElementById('qvCity').value = city;
|
||||
|
||||
if (name || cvr) {
|
||||
statusEl.className = 'alert alert-success py-2 small';
|
||||
statusEl.textContent = `✅ AI-analyse færdig: ${name || cvr}`;
|
||||
setTimeout(() => { statusEl.className = 'alert d-none py-2 small'; }, 3000);
|
||||
} else {
|
||||
statusEl.className = 'alert alert-warning py-2 small';
|
||||
statusEl.innerHTML = 'AI fandt ingen leverandørdata (fx mangler CVR på fakturaen). Udfyld manuelt eller søg herover.';
|
||||
}
|
||||
loadUnhandledFiles(); // opdater tabel
|
||||
} catch(e) {
|
||||
console.warn('Auto-reprocess failed:', e);
|
||||
statusEl.className = 'alert alert-warning py-2 small';
|
||||
statusEl.innerHTML = 'Kunne ikke køre AI-analyse automatisk. Klik ↺ i tabellen og prøv igen.';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user