fix: dedup de leads por telefonoNorm + lock anti-carrera (duplicados)

- Migracion: columna LeadCaptura.telefonoNorm (ultimos 10 digitos) con
  backfill de los 873 registros e indice
- buscarPorTelefono usa telefonoNorm exacto: la busqueda anterior
  'telefono contains' fallaba con telefonos guardados con espacios
  ('+52 664 225 7841' no contiene '6642257841') y dejaba pasar duplicados
- Mutex en memoria por telefono/email: dos envios simultaneos ya no pasan
  juntos la validacion
- convertirLead/apartar propagan telefonoNorm; email se guarda en minusculas
- 8 tests nuevos (normalizacion, dedup con espacios, lock)
This commit is contained in:
2026-09-26 21:19:31 +00:00
parent 19a8a5b037
commit db28af1c58
4 changed files with 209 additions and 28 deletions

View File

@@ -0,0 +1,20 @@
-- Dedup de leads/afluencias: teléfono normalizado (solo dígitos, últimos 10)
-- en su propia columna indexada. La búsqueda anterior `telefono contains`
-- fallaba contra teléfonos guardados con espacios ("+52 664 225 7841" no
-- contiene "6642257841"), permitiendo duplicados.
-- Patrón manual: sqlite3 + _prisma_migrations. NUNCA migrate dev.
ALTER TABLE "LeadCaptura" ADD COLUMN "telefonoNorm" TEXT;
-- Backfill: últimos 10 dígitos cuando hay al menos 10; si no, todos los
-- dígitos (coincide con normalizaTelefono() del servicio).
UPDATE "LeadCaptura"
SET "telefonoNorm" = CASE
WHEN length(replace(replace(replace(replace(replace(coalesce("telefono", ''), '+', ''), ' ', ''), '-', ''), '(', ''), ')', '')) >= 10
THEN substr(replace(replace(replace(replace(replace("telefono", '+', ''), ' ', ''), '-', ''), '(', ''), ')', ''), -10)
WHEN length(replace(replace(replace(replace(replace(coalesce("telefono", ''), '+', ''), ' ', ''), '-', ''), '(', ''), ')', '')) >= 7
THEN replace(replace(replace(replace(replace("telefono", '+', ''), ' ', ''), '-', ''), '(', ''), ')', '')
ELSE NULL
END;
CREATE INDEX IF NOT EXISTS "LeadCaptura_telefonoNorm_idx" ON "LeadCaptura"("telefonoNorm");