diff --git a/app/routers/planning_import.py b/app/routers/planning_import.py index 81f3fdd..cc06b8d 100644 --- a/app/routers/planning_import.py +++ b/app/routers/planning_import.py @@ -1151,17 +1151,56 @@ def _fetch_pct_cc_emails(db, row_ids): _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 + s.referent_nom, s.referent_email, + r.responsable_domaine_dts, r.referent_technique FROM patch_planning_import_rows r JOIN servers s ON s.id = r.server_id WHERE r.id IN ({placeholders}) """)).fetchall() + legacy_names = set() # noms à matcher dans contacts si email manquant for row in legacy: _add(row.responsable_nom, row.responsable_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()) return out