feat(pct/cc): fallback match par nom dans contacts si servers.responsable_email/referent_email vides
Cas reel: les serveurs SANEF ont responsable_nom rempli (ex 'Laurent DELCOUR') mais
responsable_email vide. Les emails ne sont QUE dans la table contacts.
Solution: 4eme source = match par nom dans la table contacts.
- On collecte les noms texte presents en DB:
* servers.responsable_nom / referent_nom (si email correspondant vide)
* patch_planning_import_rows.responsable_domaine_dts / referent_technique
(split sur '/', '-', 'et', 'ou', etc. pour les co-responsables)
- Pour chaque nom, match insensible casse: exact OR contains
- Recupere les emails associes dans contacts
This commit is contained in:
parent
ce1365e706
commit
5e5803afa2
@ -1151,17 +1151,56 @@ def _fetch_pct_cc_emails(db, row_ids):
|
|||||||
_add(c.name, c.email)
|
_add(c.name, c.email)
|
||||||
|
|
||||||
# 3) Champs legacy texte sur servers (responsable_email / referent_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"""
|
legacy = db.execute(text(f"""
|
||||||
SELECT DISTINCT s.responsable_nom, s.responsable_email,
|
SELECT DISTINCT s.responsable_nom, s.responsable_email,
|
||||||
s.referent_nom, s.referent_email
|
s.referent_nom, s.referent_email,
|
||||||
|
r.responsable_domaine_dts, r.referent_technique
|
||||||
FROM patch_planning_import_rows r
|
FROM patch_planning_import_rows r
|
||||||
JOIN servers s ON s.id = r.server_id
|
JOIN servers s ON s.id = r.server_id
|
||||||
WHERE r.id IN ({placeholders})
|
WHERE r.id IN ({placeholders})
|
||||||
""")).fetchall()
|
""")).fetchall()
|
||||||
|
legacy_names = set() # noms à matcher dans contacts si email manquant
|
||||||
for row in legacy:
|
for row in legacy:
|
||||||
_add(row.responsable_nom, row.responsable_email)
|
_add(row.responsable_nom, row.responsable_email)
|
||||||
_add(row.referent_nom, row.referent_email)
|
_add(row.referent_nom, row.referent_email)
|
||||||
|
# Si email vide côté servers, on retiendra le nom pour matcher dans contacts
|
||||||
|
if not (row.responsable_email or "").strip() and (row.responsable_nom or "").strip():
|
||||||
|
legacy_names.add(row.responsable_nom.strip())
|
||||||
|
if not (row.referent_email or "").strip() and (row.referent_nom or "").strip():
|
||||||
|
legacy_names.add(row.referent_nom.strip())
|
||||||
|
# Aussi : noms texte côté patch_planning_import_rows (responsable_domaine_dts,
|
||||||
|
# referent_technique) — peuvent contenir plusieurs noms séparés par '/' ou '-'
|
||||||
|
for nm_field in (row.responsable_domaine_dts, row.referent_technique):
|
||||||
|
if not nm_field:
|
||||||
|
continue
|
||||||
|
for part in re.split(r"[/,;\n]| - | et | ou | & ", str(nm_field)):
|
||||||
|
part = part.strip()
|
||||||
|
if len(part) >= 4 and re.search(r"[A-Za-zÀ-ÿ]{3}", part):
|
||||||
|
legacy_names.add(part)
|
||||||
|
|
||||||
|
# 4) Match par nom dans la table contacts pour les responsables/référents
|
||||||
|
# qui n'ont pas d'email côté servers. Match insensible casse + accents.
|
||||||
|
if legacy_names:
|
||||||
|
# On construit une condition ILIKE pour chaque nom + ses variantes simples
|
||||||
|
names_list = list(legacy_names)[:50] # limite de sécurité
|
||||||
|
params = {}
|
||||||
|
ors = []
|
||||||
|
for i, n in enumerate(names_list):
|
||||||
|
params[f"n{i}"] = n
|
||||||
|
# Match exact (case insensible) ou nom contenu (utile pour 'DUFOUR Antoine' vs 'Antoine Dufour')
|
||||||
|
ors.append(f"LOWER(c.name) = LOWER(:n{i})")
|
||||||
|
ors.append(f"LOWER(c.name) LIKE LOWER('%' || :n{i} || '%')")
|
||||||
|
sql = (
|
||||||
|
"SELECT DISTINCT c.name, c.email FROM contacts c "
|
||||||
|
"WHERE c.email IS NOT NULL AND c.email <> '' "
|
||||||
|
f"AND ({' OR '.join(ors)})"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
matched = db.execute(text(sql), params).fetchall()
|
||||||
|
for c in matched:
|
||||||
|
_add(c.name, c.email)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[pct_cc] match par nom failed: {e}")
|
||||||
|
|
||||||
out.sort(key=lambda c: c["name"].lower())
|
out.sort(key=lambda c: c["name"].lower())
|
||||||
return out
|
return out
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user