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:
Christian 2026-03-02 00:26:23 +01:00
parent c6d310e96d
commit 09de3c7373
3 changed files with 52 additions and 3 deletions

View File

@ -1 +1 @@
2.2.18
2.2.19

View File

@ -9,7 +9,7 @@ from typing import List, Optional, Dict
from pydantic import BaseModel
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_workflow_service import email_workflow_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
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]:
"""Løs relativ/absolut filsti — prøv /app-prefix i Docker"""
import os

View File

@ -2347,6 +2347,26 @@ async function quickCreateVendor(emailId, senderName, senderEmail) {
const resp = await fetch(`/api/v1/emails/${emailId}/extract-vendor-suggestion`, { method: 'POST' });
if (resp.ok) {
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.cvr_number) document.getElementById('qvVendorCVR').value = s.cvr_number;
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)
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 =
`<span class="text-success small"><i class="bi bi-check-circle me-1"></i>${srcLabel} felter preudfyldt</span>`;
} else {