"""Explicit purchase-mail linking, without changing purchase fulfilment or running workflows.""" import json from fastapi import HTTPException from app.core.database import atomic_transaction, execute_query_single, execute_update def link_purchase_mail(email_id, purchase_id, kind, tracking_number=None, user_id=None): if kind not in {'order_confirmation', 'freight_note'}: raise HTTPException(400, 'Ukendt indkøbsmailtype') tracking = str(tracking_number or '').strip() or None if tracking and (kind != 'freight_note' or len(tracking) > 100): raise HTTPException(400, 'Trackingnummer må højst være 100 tegn og bruges kun ved levering') with atomic_transaction(): mail = execute_query_single( 'SELECT id, linked_case_id FROM email_messages WHERE id = %s AND deleted_at IS NULL FOR UPDATE', (email_id,)) if not mail: raise HTTPException(404, 'Mailen blev ikke fundet') purchase = execute_query_single(""" SELECT p.id, p.sag_id, p.description, s.titel AS case_title FROM sag_salgsvarer p JOIN sag_sager s ON s.id = p.sag_id WHERE p.id = %s AND p.type = 'purchase' AND p.status <> 'cancelled' AND s.deleted_at IS NULL FOR UPDATE OF p, s """, (purchase_id,)) if not purchase: raise HTTPException(404, 'Bestillingen findes ikke eller er annulleret') if mail.get('linked_case_id') and mail['linked_case_id'] != purchase['sag_id']: raise HTTPException(409, 'Mailen er allerede knyttet til en anden sag. Ret sagstilknytningen først.') metadata = {'purchase_id': purchase_id, 'sag_id': purchase['sag_id'], 'kind': kind, 'tracking_number': tracking} previous = execute_query_single("""SELECT metadata FROM email_activity_log WHERE email_id = %s AND event_type = 'purchase_mail_link' ORDER BY id DESC LIMIT 1""", (email_id,)) if previous: if previous['metadata'] != metadata: raise HTTPException(409, 'Mailen er allerede behandlet som indkøbsmail med andre oplysninger.') return {'success': True, 'sag_id': purchase['sag_id'], 'idempotent': True, 'message': 'Mailen er allerede knyttet til bestillingen'} execute_update('''INSERT INTO sag_emails (sag_id, email_id) VALUES (%s, %s) ON CONFLICT (sag_id, email_id) DO NOTHING''', (purchase['sag_id'], email_id)) execute_update("""UPDATE email_messages SET linked_case_id = %s, classification = %s, confidence_score = 1.0, extracted_tracking_number = COALESCE(%s, extracted_tracking_number), status = 'processed', folder = 'Processed', processed_at = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP WHERE id = %s""", (purchase['sag_id'], kind, tracking, email_id)) execute_update("""INSERT INTO email_activity_log (email_id, event_type, event_category, description, metadata, user_id, created_by) VALUES (%s, 'purchase_mail_link', 'user', %s, %s::jsonb, %s, 'mailindbakke')""", (email_id, ('Ordrebekræftelse' if kind == 'order_confirmation' else 'Levering / tracking') + ': ' + purchase['description'], json.dumps(metadata), user_id)) return {'success': True, 'sag_id': purchase['sag_id'], 'message': 'Mailen er knyttet til bestillingen og sagen'}