feat(leads): captura rápida pide email y desarrollo de interés
- Columna 'Desarrollo' (status, 5 labels) creada en el board Leads de Monday (color_mm6sw4c2) - API: crearLead acepta email y desarrollo; el desarrollo se valida contra los labels reales de la columna (mismo patrón que Origen) - Mi día: formulario de captura con campos Email y Desarrollo de interés (select con los 5 desarrollos, opcional) - Tests: api 296, mi-dia 12
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
import type { LeadMonday } from '../services/monday.service.js'
|
||||
|
||||
/** Monday mockeado: registra escrituras y devuelve catálogos controlados */
|
||||
function mondayMock(opts: { labelsOrigen?: string[]; duplicado?: LeadMonday | null } = {}) {
|
||||
function mondayMock(opts: { labelsOrigen?: string[]; labelsDesarrollo?: string[]; duplicado?: LeadMonday | null } = {}) {
|
||||
return {
|
||||
cambios: [] as { boardId: string; itemId: string; columna: string; valor: unknown }[],
|
||||
motivos: [] as { nombre: string; categoria: string; descripcion?: string }[],
|
||||
@@ -25,7 +25,10 @@ function mondayMock(opts: { labelsOrigen?: string[]; duplicado?: LeadMonday | nu
|
||||
async buscarLeadPorTelefono(_telefono: string) {
|
||||
return opts.duplicado ?? null
|
||||
},
|
||||
async labelsDeColumna(_boardId: string, _titulo: string) {
|
||||
async labelsDeColumna(_boardId: string, titulo: string) {
|
||||
if (titulo === 'Desarrollo') {
|
||||
return opts.labelsDesarrollo ?? ['ATELIER', 'DIAGONAL', 'ESTANZA', 'SENDA', 'SOLANA']
|
||||
}
|
||||
return opts.labelsOrigen ?? ['WhatsApp', 'Web', 'Recomendado', 'Facebook', 'Otro']
|
||||
},
|
||||
async obtenerNombreItem(_itemId: string) {
|
||||
@@ -46,10 +49,36 @@ describe('crearLead (POST /api/leads)', () => {
|
||||
const r = await crearLead(monday, { ...datosBase, origen: 'Facebook', notas: 'Vio el volante' })
|
||||
expect(r).toEqual({ id: 'lead-nuevo-1' })
|
||||
expect(monday.leadsCreados).toEqual([
|
||||
{ nombre: 'Lead Prueba', telefono: '4771234567', email: undefined, origenLabel: 'Facebook', notas: 'Vio el volante' },
|
||||
{
|
||||
nombre: 'Lead Prueba',
|
||||
telefono: '4771234567',
|
||||
email: undefined,
|
||||
origenLabel: 'Facebook',
|
||||
desarrolloLabel: undefined,
|
||||
notas: 'Vio el volante',
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
it('pasa email y desarrollo al item de Monday cuando vienen en la captura', async () => {
|
||||
const monday = mondayMock()
|
||||
const r = await crearLead(monday, {
|
||||
...datosBase,
|
||||
email: 'lead@correo.com',
|
||||
desarrollo: 'SENDA',
|
||||
})
|
||||
expect(r).toEqual({ id: 'lead-nuevo-1' })
|
||||
expect(monday.leadsCreados[0]).toMatchObject({ email: 'lead@correo.com', desarrolloLabel: 'SENDA' })
|
||||
})
|
||||
|
||||
it('rechaza un desarrollo que no sea label real de la columna Desarrollo', async () => {
|
||||
const monday = mondayMock()
|
||||
await expect(crearLead(monday, { ...datosBase, desarrollo: 'MONTEBELLO' })).rejects.toThrow(
|
||||
/Desarrollo inválido/,
|
||||
)
|
||||
expect(monday.leadsCreados).toEqual([])
|
||||
})
|
||||
|
||||
it('duplicado por teléfono: no crea nada y devuelve el lead existente (endpoint → 409)', async () => {
|
||||
const existente: LeadMonday = {
|
||||
id: 'lead-viejo-9',
|
||||
|
||||
@@ -19,6 +19,7 @@ const crearLeadSchema = z.object({
|
||||
telefono: z.string().trim().min(1).optional(),
|
||||
email: z.string().trim().email('Email inválido').optional(),
|
||||
origen: z.string().trim().min(1).optional(),
|
||||
desarrollo: z.string().trim().min(1).optional(),
|
||||
notas: z.string().trim().min(1).optional(),
|
||||
})
|
||||
|
||||
@@ -93,11 +94,19 @@ export async function crearLead(
|
||||
}
|
||||
}
|
||||
|
||||
if (datos.desarrollo !== undefined) {
|
||||
const labels = await monday.labelsDeColumna(boardLeads, 'Desarrollo')
|
||||
if (!labels.includes(datos.desarrollo)) {
|
||||
throw new AppError(400, `Desarrollo inválido: "${datos.desarrollo}". Labels válidos: ${labels.join(', ')}`)
|
||||
}
|
||||
}
|
||||
|
||||
const id = await monday.crearLead({
|
||||
nombre: datos.nombre,
|
||||
telefono: datos.telefono,
|
||||
email: datos.email,
|
||||
origenLabel: datos.origen,
|
||||
desarrolloLabel: datos.desarrollo,
|
||||
notas: datos.notas,
|
||||
})
|
||||
return { id }
|
||||
|
||||
Reference in New Issue
Block a user