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:
@@ -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");
|
||||
@@ -173,6 +173,10 @@ model LeadCaptura {
|
||||
usuarioId String // Usuario.id del capturista
|
||||
nombreLead String
|
||||
telefono String?
|
||||
// Teléfono normalizado (solo dígitos, últimos 10) para el dedup de
|
||||
// capturas: la búsqueda por `telefono contains` fallaba con formatos
|
||||
// con espacios. Se mantiene en cada escritura vía normalizaTelefono().
|
||||
telefonoNorm String?
|
||||
// Board del embudo donde vive el registro: LEADS | OPORTUNIDADES | APARTADO
|
||||
board String @default("LEADS")
|
||||
// Etapa/estado local actual (NUEVO al capturar)
|
||||
@@ -198,6 +202,7 @@ model LeadCaptura {
|
||||
@@index([usuarioId])
|
||||
@@index([mondayItemId])
|
||||
@@index([nombreLead])
|
||||
@@index([telefonoNorm])
|
||||
}
|
||||
|
||||
// Espejo local del inventario (tablero Unidades de Monday). Lo siembra
|
||||
|
||||
Reference in New Issue
Block a user