Three independent bugs surfaced while debugging why Alexandre Duval
showed as "non lié" in a campaign:
1. ERPNext Customer.email_id can hold multiple addresses joined by
';' or ',' (211 records inherited from Legacy migration). The
exact-match filter missed them. Now LIKE-searches a window then
validates locally by splitting on ; , or whitespace.
2. Service Locations have duplicates at the same address — the same
"7 Rue des Merles" exists 3 times, linked to 3 different customers
(legacy migration artifact). The civic+postal strategy was taking
the first hit which could be the wrong household. Added name-aware
disambiguation: when the recipient has a name, walk the candidates
and pick the one whose linked Customer name plausibly matches.
3. New 4th matching strategy "name+civic" — kicks in when the CSV
row has no postal_code (most common Map export failure mode). Does
a street-word filtered SL search and accepts only candidates whose
Customer name plausibly matches. Confidence 0.65 (vs 0.85 for
civic+postal).
Also: SQL filter for both civic+postal and name+civic now includes a
street-word LIKE constraint so the result set isn't dominated by
unrelated "7 ..." addresses, bumped limits to 50/100. The SL
denormalized customer_name field is often empty post-import — we now
fall back to a Customer lookup for the name check.
Verified end-to-end against live ERPNext: Alexandre Duval at
7 Rue des Merles now matches correctly via email (multi-value field),
via civic+postal (despite 3 dupe SLs), and via name+civic (no postal).
Gaëtan David at the same address also matches correctly without
collision.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>