feat: auto-link vendor from PDF extraction, improve vendor suggestion v2.2.19
- extract_vendor_suggestion: fast path if extracted_vendor_cvr already set
- CVR lookup in vendors table → returns vendor_id if match found
- source='pdf_extraction' with confidence=0.95
- Frontend quickCreateVendor:
- If vendor_id returned → auto-link without modal (no manual input needed)
- New source label '📄 PDF-faktura' for pdf_extraction source
- Added execute_query_single import to emails router
This commit is contained in:
parent
c6d310e96d
commit
09de3c7373
@ -9,7 +9,7 @@ from typing import List, Optional, Dict
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
|
|
||||||
from app.core.database import execute_query, execute_insert, execute_update
|
from app.core.database import execute_query, execute_insert, execute_update, execute_query_single
|
||||||
from app.services.email_processor_service import EmailProcessorService
|
from app.services.email_processor_service import EmailProcessorService
|
||||||
from app.services.email_workflow_service import email_workflow_service
|
from app.services.email_workflow_service import email_workflow_service
|
||||||
from app.services.ollama_service import ollama_service
|
from app.services.ollama_service import ollama_service
|
||||||
@ -633,6 +633,33 @@ async def extract_vendor_suggestion(email_id: int):
|
|||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
own_cvr = getattr(settings, 'OWN_CVR', '')
|
own_cvr = getattr(settings, 'OWN_CVR', '')
|
||||||
|
|
||||||
|
# ── Hurtig genvej: brug allerede-udtrukket vendor-data fra PDF ──────
|
||||||
|
# (sat af email_analysis_service ved email-modtagelse, v2.2.18+)
|
||||||
|
pre_cvr = email.get('extracted_vendor_cvr')
|
||||||
|
pre_name = email.get('extracted_vendor_name')
|
||||||
|
if pre_cvr and pre_cvr != own_cvr and not is_placeholder_cvr(pre_cvr):
|
||||||
|
# Forsøg CVR-opslag i vendors-tabel
|
||||||
|
vendor_row = execute_query_single(
|
||||||
|
"SELECT id, name, cvr_number, phone, email, address FROM vendors WHERE cvr_number = %s",
|
||||||
|
(pre_cvr,)
|
||||||
|
)
|
||||||
|
suggestion = {
|
||||||
|
"name": (vendor_row and vendor_row.get('name')) or pre_name or None,
|
||||||
|
"cvr_number": pre_cvr,
|
||||||
|
"phone": (vendor_row and vendor_row.get('phone')) or None,
|
||||||
|
"email": (vendor_row and vendor_row.get('email')) or None,
|
||||||
|
"address": (vendor_row and vendor_row.get('address')) or None,
|
||||||
|
"domain": None,
|
||||||
|
"source": "pdf_extraction",
|
||||||
|
"vendor_id": vendor_row.get('id') if vendor_row else None,
|
||||||
|
"confidence": 0.95,
|
||||||
|
}
|
||||||
|
logger.info(
|
||||||
|
f"⚡ Hurtig vendor-suggestion fra PDF-extraction for email {email_id}: "
|
||||||
|
f"CVR={pre_cvr}, vendor_id={suggestion['vendor_id']}"
|
||||||
|
)
|
||||||
|
return suggestion
|
||||||
|
|
||||||
def resolve_file_path(raw_path: str) -> Optional[str]:
|
def resolve_file_path(raw_path: str) -> Optional[str]:
|
||||||
"""Løs relativ/absolut filsti — prøv /app-prefix i Docker"""
|
"""Løs relativ/absolut filsti — prøv /app-prefix i Docker"""
|
||||||
import os
|
import os
|
||||||
|
|||||||
@ -2347,6 +2347,26 @@ async function quickCreateVendor(emailId, senderName, senderEmail) {
|
|||||||
const resp = await fetch(`/api/v1/emails/${emailId}/extract-vendor-suggestion`, { method: 'POST' });
|
const resp = await fetch(`/api/v1/emails/${emailId}/extract-vendor-suggestion`, { method: 'POST' });
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
const s = await resp.json();
|
const s = await resp.json();
|
||||||
|
|
||||||
|
// ── Hurtig genvej: leverandøren kendes allerede (vendor_id fra PDF) ──
|
||||||
|
if (s.vendor_id && s.source === 'pdf_extraction') {
|
||||||
|
bootstrap.Modal.getInstance(document.getElementById('quickCreateVendorModal')).hide();
|
||||||
|
// Auto-link direkte
|
||||||
|
const linkResp = await fetch(`/api/v1/emails/${emailId}/link`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ supplier_id: s.vendor_id })
|
||||||
|
});
|
||||||
|
if (linkResp.ok) {
|
||||||
|
showSuccess(`Leverandør "${s.name || s.cvr_number}" auto-linket fra faktura-PDF`);
|
||||||
|
loadEmailDetail(parseInt(emailId));
|
||||||
|
} else {
|
||||||
|
showError('Auto-link fejlede — åbner formularen');
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (s.name && s.name !== senderName) document.getElementById('qvVendorName').value = s.name;
|
if (s.name && s.name !== senderName) document.getElementById('qvVendorName').value = s.name;
|
||||||
if (s.cvr_number) document.getElementById('qvVendorCVR').value = s.cvr_number;
|
if (s.cvr_number) document.getElementById('qvVendorCVR').value = s.cvr_number;
|
||||||
if (s.phone) document.getElementById('qvVendorPhone').value = s.phone;
|
if (s.phone) document.getElementById('qvVendorPhone').value = s.phone;
|
||||||
@ -2355,7 +2375,9 @@ async function quickCreateVendor(emailId, senderName, senderEmail) {
|
|||||||
if (s.email && !document.getElementById('qvVendorEmail').value)
|
if (s.email && !document.getElementById('qvVendorEmail').value)
|
||||||
document.getElementById('qvVendorEmail').value = s.email;
|
document.getElementById('qvVendorEmail').value = s.email;
|
||||||
|
|
||||||
const srcLabel = s.source === 'ai' ? '🤖 AI' : '🔍 Regex';
|
const srcLabel = s.source === 'pdf_extraction' ? '📄 PDF-faktura'
|
||||||
|
: s.source === 'ai' ? '🤖 AI'
|
||||||
|
: '🔍 Regex';
|
||||||
document.getElementById('qvAiStatus').innerHTML =
|
document.getElementById('qvAiStatus').innerHTML =
|
||||||
`<span class="text-success small"><i class="bi bi-check-circle me-1"></i>${srcLabel} – felter preudfyldt</span>`;
|
`<span class="text-success small"><i class="bi bi-check-circle me-1"></i>${srcLabel} – felter preudfyldt</span>`;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user