feat: conversión lead→oportunidad (Agendo) y alta ligada a apartado
- Mis leads: botón 'Agendo →' convierte el lead en oportunidad (etapa Agendo Cita, con sus datos, asesor = vendedor del lead o quien convierte), marca el lead Calificado y guarda el mapping LeadOportunidad; 409 si ya fue convertido - Mis oportunidades: se quitan No Asistio y Abandono (redundantes con Descartar); quedan Cotizar, Afluencia, Agendo Cita y Aparto - Mis apartados: 'Firma cliente (venta) →' abre el alta de cliente con TODO lo recolectado prellenado (ficha del apartado + contacto + oportunidad + cotización vinculada vía GET /altas/prefill-apartado/:id) - El alta con apartadoMondayId se LIGA al apartado existente y lo enriquece (curp, teléfono, email, precio final, enganche, forma de pago, unidad) en vez de crear un duplicado - monday.service: actualizarApartado + ApartadoMonday con curp, forma de pago, enganche y monto apartado - Tests: 470 API + 120 alta-clientes + 16 mi-dia, verde
This commit is contained in:
@@ -84,6 +84,10 @@ export interface ApartadoMonday {
|
||||
email?: string // columna email 'Correo electrónico' ('' si no tiene)
|
||||
precioFinal?: number // columna numbers 'Precio Final' (0 si no tiene)
|
||||
fechaCompra?: string // 'YYYY-MM-DD' de 'Fecha Compra' ('' si no tiene)
|
||||
curp?: string // columna text 'curp' ('' si no tiene)
|
||||
formaPago?: string // dropdown 'Forma de Pago' ('' si no tiene)
|
||||
enganche?: number // columna numbers 'Enganche' (0 si no tiene)
|
||||
montoApartado?: number // columna numbers 'Monto apartado' (0 si no tiene)
|
||||
}
|
||||
|
||||
/** Contacto del tablero Contactos (módulo Contactos de la landing) */
|
||||
@@ -510,13 +514,15 @@ export class MondayService {
|
||||
* Oportunidad en etapa 'Afluencia' con todo el perfil de captura (la
|
||||
* afluencia ES la oportunidad: no hay item aparte en el tablero Leads).
|
||||
* La columna date 'Fecha' lleva la fecha de captura (hoy, hora local).
|
||||
* estadoLabel permite crearla en otra etapa (p. ej. 'Agendo Cita' al
|
||||
* convertir un lead del tablero Leads).
|
||||
*/
|
||||
async crearOportunidadAfluencia(datos: DatosOportunidadAfluencia): Promise<string> {
|
||||
const boardId = config.monday.boards.oportunidades
|
||||
const hoy = new Date()
|
||||
const fechaHoy = `${hoy.getFullYear()}-${String(hoy.getMonth() + 1).padStart(2, '0')}-${String(hoy.getDate()).padStart(2, '0')}`
|
||||
const columnValues = await this.construirColumnValues(boardId, {
|
||||
Estado: 'Afluencia',
|
||||
Estado: datos.estadoLabel ?? 'Afluencia',
|
||||
Fecha: fechaHoy,
|
||||
'Cliente teléfono': datos.telefono,
|
||||
'Cliente email': datos.email,
|
||||
@@ -682,6 +688,41 @@ export class MondayService {
|
||||
return this.crearItem(boardId, datos.clienteNombre, columnValues)
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualiza un apartado existente con los campos presentes (mismo builder de
|
||||
* valores que crearApartado) — usado cuando el alta de cliente arranca desde
|
||||
* un apartado ya creado (botón "Firma Cliente (Venta)" de Mis apartados):
|
||||
* se enriquece el item en vez de crear uno duplicado.
|
||||
*/
|
||||
async actualizarApartado(itemId: string, datos: Partial<DatosApartado>): Promise<void> {
|
||||
const boardId = config.monday.boards.apartado
|
||||
const valores = JSON.parse(
|
||||
await this.construirColumnValues(boardId, {
|
||||
Unidad: datos.unidadCodigo,
|
||||
'Monto apartado': datos.montoApartado,
|
||||
'Fecha apartado': datos.fechaApartado,
|
||||
'Fecha límite': datos.fechaLimite,
|
||||
Estado: datos.estadoLabel,
|
||||
Teléfono: datos.telefono,
|
||||
'Correo electrónico': datos.email,
|
||||
curp: datos.curp,
|
||||
'Precio Final': datos.precioFinal,
|
||||
Enganche: datos.enganche,
|
||||
'Fecha Compra': datos.fechaCompra,
|
||||
Vendedor: datos.vendedorId,
|
||||
'Forma de Pago': datos.formaPagoLabel,
|
||||
Observaciones: datos.observaciones,
|
||||
}),
|
||||
) as Record<string, unknown>
|
||||
if (datos.clienteNombre !== undefined && datos.clienteNombre !== '') valores['name'] = datos.clienteNombre
|
||||
await this.graphql(
|
||||
`mutation ($boardId: ID!, $itemId: ID!, $columnValues: JSON!) {
|
||||
change_multiple_column_values(board_id: $boardId, item_id: $itemId, column_values: $columnValues) { id }
|
||||
}`,
|
||||
{ boardId, itemId, columnValues: JSON.stringify(valores) },
|
||||
)
|
||||
}
|
||||
|
||||
async actualizarDisponibilidadUnidad(codigo: string, status: 'DISPONIBLE' | 'APARTADA' | 'VENDIDA'): Promise<void> {
|
||||
const boardId = config.monday.boards.unidades
|
||||
// Asegura cache fresco para resolver el itemId
|
||||
@@ -1190,6 +1231,10 @@ export class MondayService {
|
||||
const colEmail = cols.get('Correo electrónico')
|
||||
const colPrecioFinal = cols.get('Precio Final')
|
||||
const colFechaCompra = cols.get('Fecha Compra')
|
||||
const colCurp = cols.get('curp')
|
||||
const colFormaPago = cols.get('Forma de Pago')
|
||||
const colEnganche = cols.get('Enganche')
|
||||
const colMontoApartado = cols.get('Monto apartado')
|
||||
|
||||
const items: ItemMonday[] = []
|
||||
let cursor: string | null = null
|
||||
@@ -1241,6 +1286,10 @@ export class MondayService {
|
||||
email: colEmail ? (porId.get(colEmail.id)?.text ?? '') : '',
|
||||
precioFinal: colPrecioFinal ? Number(porId.get(colPrecioFinal.id)?.text ?? 0) || 0 : 0,
|
||||
fechaCompra: colFechaCompra ? (porId.get(colFechaCompra.id)?.text ?? '') : '',
|
||||
curp: colCurp ? (porId.get(colCurp.id)?.text ?? '') : '',
|
||||
formaPago: colFormaPago ? (porId.get(colFormaPago.id)?.text ?? '') : '',
|
||||
enganche: colEnganche ? Number(porId.get(colEnganche.id)?.text ?? 0) || 0 : 0,
|
||||
montoApartado: colMontoApartado ? Number(porId.get(colMontoApartado.id)?.text ?? 0) || 0 : 0,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1515,6 +1564,8 @@ export interface DatosOportunidad {
|
||||
|
||||
export interface DatosOportunidadAfluencia {
|
||||
nombre: string // name del item = nombre del interesado
|
||||
/** Etapa inicial (default 'Afluencia'; 'Agendo Cita' al convertir un lead) */
|
||||
estadoLabel?: string | undefined
|
||||
telefono?: string | undefined
|
||||
email?: string | undefined
|
||||
desarrolloLabel?: string | undefined // label tal cual de la columna status 'Desarrollo'
|
||||
|
||||
Reference in New Issue
Block a user