Configuracion para guardar en base de datos

This commit is contained in:
unknown
2026-06-02 23:11:46 -04:00
parent fc6a7044b0
commit e5c8956b64
3 changed files with 86 additions and 23 deletions

View File

@@ -332,14 +332,14 @@ Reglas para valor_extraido:
}
const valoresPermitidos = this.leadsService.getValoresPermitidos(estado);
const valor = clasificacion.valor_extraido?.trim().toLowerCase();
const valor = this.normalizarTexto(clasificacion.valor_extraido ?? '');
if (!valor) {
return { valido: false, valorNormalizado: null };
}
const coincide = valoresPermitidos.some(
(v) => v === valor || valor.includes(v),
(v) => v === valor || valor.includes(v) || v.includes(valor),
);
if (!coincide) {
@@ -347,11 +347,21 @@ Reglas para valor_extraido:
}
const valorNormalizado =
valoresPermitidos.find((v) => v === valor || valor.includes(v)) ?? valor;
valoresPermitidos.find(
(v) => v === valor || valor.includes(v) || v.includes(valor),
) ?? valor;
return { valido: true, valorNormalizado };
}
private normalizarTexto(valor: string): string {
return valor
.trim()
.toLowerCase()
.normalize('NFD')
.replace(/\p{Diacritic}/gu, '');
}
private claveReintento(leadId: number, estado: string): string {
return `${leadId}:${estado}`;
}
@@ -603,6 +613,11 @@ Devuelve SOLO el mensaje final listo para enviar, sin explicaciones ni JSON.
const campo = this.leadsService.getCampoParaEstado(estadoFlujo);
if (campo) {
entidad = { [campo]: validacion.valorNormalizado };
} else if (
estadoFlujo === 'apertura' &&
clasificacion.valor_extraido?.trim()
) {
entidad = { nombre: clasificacion.valor_extraido.trim() };
}
}

View File

@@ -116,8 +116,11 @@ export class LeadsService {
}
async updateEstado(lead: Lead, estado: EstadoLead | string): Promise<Lead> {
lead.estado_actual = estado as EstadoLead;
return this.leadRepo.save(lead);
await this.leadRepo.update(lead.id, {
estado_actual: estado as EstadoLead,
});
this.logger.log(`Lead id=${lead.id} estado_actual=${estado}`);
return this.leadRepo.findOne({ where: { id: lead.id } });
}
/**
@@ -125,14 +128,62 @@ export class LeadsService {
* Solo actualiza los campos que se pasan en el partial.
*/
async updateDatos(leadId: number, datos: Partial<Lead>): Promise<Lead> {
const campos = Object.keys(datos).filter(
(k) => datos[k as keyof Lead] !== undefined,
);
if (campos.length === 0) {
return this.leadRepo.findOne({ where: { id: leadId } });
}
await this.leadRepo.update(leadId, datos);
this.logger.log(
`Lead id=${leadId} datos guardados: ${JSON.stringify(datos)}`,
);
return this.leadRepo.findOne({ where: { id: leadId } });
}
async marcarViable(lead: Lead, viable: boolean): Promise<Lead> {
lead.viable = viable;
lead.estado_actual = viable ? 'completado' : 'no_viable';
return this.leadRepo.save(lead);
const estado = viable ? 'completado' : 'no_viable';
await this.leadRepo.update(lead.id, { viable, estado_actual: estado });
this.logger.log(`Lead id=${lead.id} viable=${viable}, estado=${estado}`);
return this.leadRepo.findOne({ where: { id: lead.id } });
}
/**
* Persiste datos del lead y cambio de estado en una sola operacion.
*/
async persistirTurno(
leadId: number,
datos: Partial<Lead>,
options?: { nuevoEstado?: string; viable?: boolean },
): Promise<Lead> {
const patch: Partial<Lead> = { ...datos };
if (options?.nuevoEstado === 'fin_viable') {
patch.viable = true;
patch.estado_actual = 'completado';
} else if (options?.nuevoEstado === 'fin_no_viable') {
patch.viable = false;
patch.estado_actual = 'no_viable';
} else if (options?.nuevoEstado) {
patch.estado_actual = options.nuevoEstado as EstadoLead;
} else if (options?.viable !== undefined && options?.viable !== null) {
patch.viable = options.viable;
patch.estado_actual = options.viable ? 'completado' : 'no_viable';
}
const campos = Object.keys(patch).filter(
(k) => patch[k as keyof Lead] !== undefined,
);
if (campos.length === 0) {
return this.leadRepo.findOne({ where: { id: leadId } });
}
await this.leadRepo.update(leadId, patch);
this.logger.log(
`Lead id=${leadId} persistido: ${JSON.stringify(patch)}`,
);
return this.leadRepo.findOne({ where: { id: leadId } });
}
/**

View File

@@ -190,7 +190,7 @@ export class WhatsappService implements OnModuleInit, OnModuleDestroy {
const telefono = jid.split("@")[0];
try {
const lead = await this.leadsService.findOrCreate(telefono);
let lead = await this.leadsService.findOrCreate(telefono);
if (ESTADOS_TERMINALES.includes(lead.estado_actual)) {
this.logger.log(
@@ -299,21 +299,18 @@ export class WhatsappService implements OnModuleInit, OnModuleDestroy {
this.logger.log(`LUISA [${telefono}]: ${respuesta}`);
if (entidad && Object.keys(entidad).length > 0) {
await this.leadsService.updateDatos(lead.id, entidad);
}
if (nuevoEstado === "fin_viable" || nuevoEstado === "fin_no_viable") {
await this.leadsService.marcarViable(
lead,
nuevoEstado === "fin_viable",
if (
(entidad && Object.keys(entidad).length > 0) ||
nuevoEstado ||
(viable !== undefined && viable !== null)
) {
lead = await this.leadsService.persistirTurno(lead.id, entidad ?? {}, {
nuevoEstado,
viable,
});
this.logger.log(
`Lead id=${lead.id} en DB — estado=${lead.estado_actual}, espacio=${lead.espacio ?? "-"}, rango_m2=${lead.rango_m2 ?? "-"}, estilo=${lead.estilo ?? "-"}, urgencia=${lead.urgencia ?? "-"}, presupuesto=${lead.presupuesto_declarado ?? "-"}`,
);
this.logger.log(`Lead id=${lead.id} finalizado como ${nuevoEstado}`);
} else if (nuevoEstado) {
await this.leadsService.updateEstado(lead, nuevoEstado);
this.logger.log(`Lead id=${lead.id} avanzado a estado=${nuevoEstado}`);
} else if (viable !== undefined && viable !== null) {
await this.leadsService.marcarViable(lead, viable);
}
await this.conversacionService.guardarMensaje(