feat(apartado): ficha completa en Monday + estado visible en la app
- El alta (directa y progresiva) llena el Apartado con telefono, correo, curp, Precio Final, Enganche, Fecha Compra, Vendedor (el capturista con Monday vinculado) y Forma de Pago; el path webhook/cron hereda contacto, precio y asesor de la oportunidad. - Bidireccional: Mis clientes en /hoy muestra el estado actual del Apartado leyendolo de Monday (si lo mueven en Monday, la app lo refleja en el siguiente refresh). - getApartados con la correccion value-null al leer Estado. - Test del mapa de Tipo propuesta del cotizador (los 502 del log eran de un proceso previo al fix 4f31d1c; queda cubierto).
This commit is contained in:
@@ -743,4 +743,99 @@ describe('MondayService', () => {
|
||||
expect(Object.keys(parsed).sort()).toEqual(['color_estado', 'date_fecha'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('crearApartado (ficha completa del tablero Apartado)', () => {
|
||||
// Columnas reales del board (verificadas en Monday 2026-09-04)
|
||||
const COLUMNAS_APARTADO = [
|
||||
{ id: 'text_u', title: 'Unidad', type: 'text' },
|
||||
{ id: 'numeric_ma', title: 'Monto apartado', type: 'numbers' },
|
||||
{ id: 'date_fa', title: 'Fecha apartado', type: 'date' },
|
||||
{ id: 'date_fl', title: 'Fecha límite', type: 'date' },
|
||||
{ id: 'color_e', title: 'Estado', type: 'status' },
|
||||
{ id: 'phone_t', title: 'Teléfono', type: 'phone' },
|
||||
{ id: 'email_c', title: 'Correo electrónico', type: 'email' },
|
||||
{ id: 'text_curp', title: 'curp', type: 'text' }, // minúscula en el board
|
||||
{ id: 'numeric_pf', title: 'Precio Final', type: 'numbers' },
|
||||
{ id: 'numeric_en', title: 'Enganche', type: 'numbers' },
|
||||
{ id: 'date_fc', title: 'Fecha Compra', type: 'date' },
|
||||
{ id: 'people_v', title: 'Vendedor', type: 'people' },
|
||||
{ id: 'dropdown_fp', title: 'Forma de Pago', type: 'dropdown' },
|
||||
{ id: 'long_obs', title: 'Observaciones', type: 'long_text' },
|
||||
]
|
||||
|
||||
it('serializa cada columna según su tipo (phone, email, numbers, date, people, dropdown, long_text)', async () => {
|
||||
const llamadas = mockearFetch((body) => {
|
||||
if (body.query.includes('settings_str')) {
|
||||
return respuestaOk({
|
||||
boards: [
|
||||
{
|
||||
columns: [
|
||||
{ id: 'color_e', title: 'Estado', settings_str: '{"labels":{"1":"Pago Apartado"}}' },
|
||||
{ id: 'dropdown_fp', title: 'Forma de Pago', settings_str: '{"labels":[{"name":"Infonavit"},{"name":"Contado"}]}' },
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
if (body.query.includes('columns')) return respuestaOk({ boards: [{ columns: COLUMNAS_APARTADO }] })
|
||||
return respuestaOk({ create_item: { id: 'ap-1' } })
|
||||
})
|
||||
|
||||
const id = await crearServicio().crearApartado({
|
||||
clienteNombre: 'Cliente Demo',
|
||||
unidadCodigo: 'U-101',
|
||||
montoApartado: 20000,
|
||||
fechaApartado: '2026-09-04',
|
||||
fechaLimite: '2026-09-19',
|
||||
estadoLabel: 'Pago Apartado',
|
||||
telefono: '6641112233',
|
||||
email: 'cli@correo.com',
|
||||
curp: 'CURP123',
|
||||
precioFinal: 1500000,
|
||||
enganche: 20000,
|
||||
fechaCompra: '2026-09-04',
|
||||
vendedorId: 12345,
|
||||
formaPagoLabel: 'INFONAVIT', // el resolver lo ajusta al label real
|
||||
observaciones: 'Venta con descuento autorizado',
|
||||
})
|
||||
expect(id).toBe('ap-1')
|
||||
|
||||
const mutacion = llamadas.find((l) => l.body.query.includes('create_item'))
|
||||
expect(mutacion?.body.variables['boardId']).toBe('666') // tablero Apartado
|
||||
const parsed = JSON.parse(String(mutacion?.body.variables['columnValues'])) as Record<string, unknown>
|
||||
expect(parsed['phone_t']).toEqual({ phone: '6641112233', countryShortName: 'MX' })
|
||||
expect(parsed['email_c']).toEqual({ email: 'cli@correo.com', text: 'cli@correo.com' })
|
||||
expect(parsed['text_curp']).toBe('CURP123')
|
||||
expect(parsed['numeric_pf']).toBe(1500000)
|
||||
expect(parsed['numeric_en']).toBe(20000)
|
||||
expect(parsed['date_fc']).toEqual({ date: '2026-09-04' })
|
||||
expect(parsed['people_v']).toEqual({ personsAndTeams: [{ id: 12345, kind: 'person' }] })
|
||||
expect(parsed['dropdown_fp']).toEqual({ labels: ['Infonavit'] }) // dropdown resuelto case-insensitive
|
||||
expect(parsed['long_obs']).toEqual({ text: 'Venta con descuento autorizado' })
|
||||
})
|
||||
|
||||
it('omite las columnas opcionales no capturadas', async () => {
|
||||
const llamadas = mockearFetch((body) => {
|
||||
if (body.query.includes('settings_str')) {
|
||||
return respuestaOk({
|
||||
boards: [{ columns: [{ id: 'color_e', title: 'Estado', settings_str: '{"labels":{"1":"Pago Apartado"}}' }] }],
|
||||
})
|
||||
}
|
||||
if (body.query.includes('columns')) return respuestaOk({ boards: [{ columns: COLUMNAS_APARTADO }] })
|
||||
return respuestaOk({ create_item: { id: 'ap-2' } })
|
||||
})
|
||||
|
||||
await crearServicio().crearApartado({
|
||||
clienteNombre: 'Cliente Demo',
|
||||
unidadCodigo: 'U-101',
|
||||
fechaApartado: '2026-09-04',
|
||||
fechaLimite: '2026-09-19',
|
||||
estadoLabel: 'Pago Apartado',
|
||||
})
|
||||
|
||||
const mutacion = llamadas.find((l) => l.body.query.includes('create_item'))
|
||||
const parsed = JSON.parse(String(mutacion?.body.variables['columnValues'])) as Record<string, unknown>
|
||||
expect(Object.keys(parsed).sort()).toEqual(['color_e', 'date_fa', 'date_fl', 'text_u'])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user