fix(pct): CC = FK contacts ET champs legacy responsable_email/referent_email

Cause: les FK servers.responsable_domaine_contact_id / referent_technique_contact_id
n'etaient pas remplies dans la DB SANEF actuelle, mais les emails sont presents
dans les champs legacy texte servers.responsable_email / referent_email.

Solution: _fetch_pct_cc_emails() cherche maintenant en 2 etapes:
1. Via FK -> contacts.email (si modele moderne renseigne)
2. Via champs legacy texte sur servers (responsable_email/referent_email)

Dedoublonne par email lowercase. Garde le nom (legacy: responsable_nom/referent_nom,
moderne: contacts.name).
This commit is contained in:
Pierre & Lumière 2026-05-07 21:50:51 +02:00
parent 00998e9320
commit d32a04c9ca

View File

@ -1105,39 +1105,66 @@ def _build_pct_email(rows, intervenant_name=""):
def _fetch_pct_cc_emails(db, row_ids):
"""Récupère les emails distincts (responsable domaine + référent technique
+ référents additionnels) pour les rows sélectionnées, à mettre en CC du mail PCT."""
+ référents additionnels) pour les rows sélectionnées, à mettre en CC du mail PCT.
Cherche dans 3 sources, dédoublonne par email :
1. FK contacts via servers.responsable_domaine_contact_id / referent_technique_contact_id
2. Table server_additional_referents (multi-référents)
3. Champs legacy texte servers.responsable_email / referent_email
(avec recherche du nom complet dans contacts si dispo)"""
if not row_ids:
return []
placeholders = ",".join(str(i) for i in row_ids)
contact_ids_rows = db.execute(text(f"""
SELECT DISTINCT contact_id FROM (
SELECT s.responsable_domaine_contact_id AS contact_id
FROM patch_planning_import_rows r
JOIN servers s ON s.id = r.server_id
seen = set()
out = []
def _add(name, email):
em = (email or "").strip()
if not em:
return
key = em.lower()
if key in seen:
return
seen.add(key)
out.append({"name": (name or em).strip(), "email": em})
# 1) Via FK contact_id (modèle moderne) + 2) référents additionnels
fk_rows = db.execute(text(f"""
SELECT DISTINCT c.name, c.email FROM contacts c
WHERE c.email IS NOT NULL AND c.email <> ''
AND c.id IN (
SELECT s.responsable_domaine_contact_id
FROM patch_planning_import_rows r JOIN servers s ON s.id = r.server_id
WHERE r.id IN ({placeholders}) AND s.responsable_domaine_contact_id IS NOT NULL
UNION
SELECT s.referent_technique_contact_id
FROM patch_planning_import_rows r
JOIN servers s ON s.id = r.server_id
FROM patch_planning_import_rows r JOIN servers s ON s.id = r.server_id
WHERE r.id IN ({placeholders}) AND s.referent_technique_contact_id IS NOT NULL
UNION
SELECT sar.contact_id
FROM patch_planning_import_rows r
JOIN server_additional_referents sar ON sar.server_id = r.server_id
WHERE r.id IN ({placeholders})
) x WHERE contact_id IS NOT NULL
)
""")).fetchall()
cids = [r.contact_id for r in contact_ids_rows if r.contact_id]
if not cids:
return []
contacts = db.execute(text(f"""
SELECT id, name, email FROM contacts
WHERE id IN ({','.join(str(c) for c in cids)})
AND email IS NOT NULL AND email <> ''
AND is_active = true
ORDER BY name
for c in fk_rows:
_add(c.name, c.email)
# 3) Champs legacy texte sur servers (responsable_email / referent_email)
# + tentative de récupérer le nom propre depuis la table contacts par email
legacy = db.execute(text(f"""
SELECT DISTINCT s.responsable_nom, s.responsable_email,
s.referent_nom, s.referent_email
FROM patch_planning_import_rows r
JOIN servers s ON s.id = r.server_id
WHERE r.id IN ({placeholders})
""")).fetchall()
return [{"name": c.name, "email": c.email} for c in contacts]
for row in legacy:
_add(row.responsable_nom, row.responsable_email)
_add(row.referent_nom, row.referent_email)
out.sort(key=lambda c: c["name"].lower())
return out
@router.post("/patching/import/pct-prevenance/preview")