Resultado de llamada
Tarjeta de resultado de llamada
Después de que termina la conversación, se le puede dar al gerente la opción de registrar el Resultado de la llamada. La ventana modal de Resultado de llamada muestra información sobre quien llama e incluye opciones para seleccionar la entidad (lead, contacto o compañía) con la que se asociará la llamada, adjuntar la grabación de la llamada, añadir una tarea con una hora específica y dejar notas sobre la conversación, si las hubiera. Si el gerente no responde la llamada, se puede guardar un registro con duración cero. La apariencia de la ventana de resultado de llamada se controla desde la parte JavaScript del widget, mientras que la actualización real de la llamada se realiza a través del backend de la integración.
Un ejemplo de la ventana de resultado de llamada:
La ventana modal puede estar compuesta por los siguientes elementos:
- Nombre de la ventana: Resumen de la llamada
- Entidad vinculada (lead/contacto/compañía)
- Título del lead es un campo con búsqueda para encontrar el lead/cliente adecuado
- Panel de grabación de la llamada (que indica la duración de la llamada y un botón de reproducción)
- Hora y nota para una tarea
- Botones Guardar o Cancelar
Plantilla para renderizar tu ventana modal de Resultado de llamada:
import Modal from "lib/components/base/modal";
import markup from "./markup.js";
const appendCallResultModal = () => {
/**
* * Puedes usar la clase Modal para abrir una ventana modal.
*/
const modal = new Modal({
class_name: "modal-window",
init: function ($modal_body) {
$modal_body
/**
* Activa la visualización de la ventana modal.
*/
.trigger("modal:loaded")
/**
* Muestra tu marcado.
*/
.html(markup)
/**
* Configura la ventana modal.
*/
.trigger("modal:centrify");
},
destroy: () => {},
});
/**
* Aquí va la lógica para tu ventana modal.
*/
};Después de elegir la entidad y completar los campos, debes guardar el resultado de la llamada y actualizarla cambiando su vínculo a la entidad seleccionada, si corresponde. Para ello, se crea una tarea que se enviará a la cola.
Consideremos el siguiente escenario de ejemplo:
- Se realiza una llamada desde un contacto existente.
- El servicio VoIP envía un webhook indicando que la llamada terminó. Luego, el backend de la integración debe buscar la entidad correspondiente para vincular la llamada, o crear un Lead Entrante si no existe ninguna entidad asociada al número telefónico en tu cuenta de Kommo.
- El gerente completa la ventana modal de resultado de llamada y selecciona una entidad diferente a la que sugirió el algoritmo. La nota debe vincularse a la entidad seleccionada, y el vínculo con la entidad previamente sugerida debe eliminarse desde la integración.
- El backend de la integración VoIP envía una solicitud de Nota de llamada para vincular la nota a la tarjeta del contacto seleccionado.
Como se mencionó en el artículo sobre Registro de llamadas , todas las llamadas deben obtenerse desde el servicio VoIP y almacenarse en el repositorio de llamadas dentro de la base de datos de la integración. También hemos implementado una función para obtener una llamada a partir de sus identificadores:
public static function getByCallIdAndKommoAccountId(string $callId, int $kommoAccountId): VoipCalls {
return VoipCalls::query()
->where('call_id', '=', $callId)
->where('kommo_account_id', '=', $kommoAccountId)
->first();
}Una tarea para actualizar la llamada según la información proveniente de la ventana modal de resultado de la llamada:
public function __construct(
private int $kommoAccountId,
private string $callId,
private int $entityId,
private string $entityType
);Aquí se explica un ejemplo del caso de uso responsable de actualizar la llamada según la información proveniente de la ventana modal de resultado de la llamada:
public function handle(UpdateFromModalTask $task): void
{
$widgetSettings = WidgetSettingsRepository::getByKommoAccountId($task->getKommoAccountId());
$voipCall = VoipCalls::getByCallIdAndKommoAccountId(
$task->getCallId(),
$widgetSettings->getKommoAccountId()
);
$call = Call::fromModel($voipCall);
if ($record = $voipCall->getRecording() ?? '') {
$record = sprintf(
'%s/voip/%s/get_call_record/%s',
$this->appConfig->getBaseUrl(),
$widgetSettings->getKommoAccountId(),
$voipCall->getCallId()
);
}
$call->setRecordLink($record);
$unsorted = null;
/** Si la llamada está en leads entrantes:
* a) Si el gerente elige la entidad Lead, debes adjuntarle un Contacto;
* b) Si el gerente elige la entidad Contacto/Compañía, debes tomarla del contacto en el Lead entrante
*/
if ($voipCall->getUnsortedUid() !== null) {
$unsorted = $this->unsortedService
->findUnsortedByUid($voipCall->getUnsortedUid());
$unsortedContact = $unsorted->getContacts()?->first();
$entityType = KommoEntityType::tryFrom($task->getEntityType());
switch ($entityType) {
case KommoEntityType::LEADS:
if ($unsortedContact !== null) {
$this->contactService
->linkContact($unsortedContact, $entityType, $task->getEntityId());
}
break;
case KommoEntityType::CONTACTS:
case KommoEntityType::COMPANIES:
// En el lead entrante solo está el ID del contacto. Obtendremos toda la información.
if ($unsortedContact !== null) {
$unsortedContact = $this
->contactService>getContactById($unsortedContact->getId());
$phones = $unsortedContact
->getCustomFieldsValues()
?->getBy('fieldCode', 'PHONE');
$newPhone = $phones?->getValues()?->first()->getValue();
if (!empty($newPhone)) {
$this->contactService->updatePhones($task->getEntityId(), $entityType, (string)$newPhone);
}
}
break;
default:
throw UnsupportedEntityException::create();
}
}
$this->contactService->updateCallEvent(
$call,
$voipCall->getResponsibleUserId() ?? self::BOT_USER_ID,
$voipCall->getEntityId(),
$voipCall->getEntityType(),
$task->getEntityId(),
$task->getEntityType()
);
// Rechazar el lead entrante después de descartar la nota de llamada.
if ($unsorted) {
$this->unsortedService->declineUnsorted($unsorted);
$voipCall->setUnsortedUid(null);
}
$voipCall->getEntityType())->save();
$task->setSuccess($success);
}La tarea se crea dentro del worker, el cual toma la tarea de la cola y la envía al handler:
public function run(array $data, LoggerInterface $logger): void
{
$taskData = $data['data'] ?? [];
$task = new UpdateFromModalTask(
$taskData['account_id'],
$taskData['call_id'],
$taskData['entity_id'],
$taskData['entity_type']
);
$this->updateFromModalUseCase->handle($task);
if (!$task->isSuccess()) {
throw BusinessLogicException::create('Update call event error');
}
}Nota de llamada
El registro de llamadas se realiza creando eventos dentro de la entidad correspondiente, clasificados bajo tipos de evento específicos para llamadas salientes y entrantes. Si el sistema VoIP admite la funcionalidad de grabación de llamadas, la interfaz de usuario puede mostrar una URL y un reproductor de audio para reproducir la llamada grabada. Para que el reproductor funcione correctamente, el servidor que aloja la grabación debe incluir el encabezado HTTP Accept-Ranges: bytes en su respuesta. La ausencia de este encabezado puede afectar la capacidad de desplazamiento dentro del audio (por ej.: avanzar o retroceder) durante la reproducción.
Una Nota de llamada puede añadirse mediante el endpoint POST /api/v4/calls. Este endpoint busca automáticamente las entidades asociadas al número telefónico proporcionado y adjunta el registro de la llamada a la entidad correspondiente según un algoritmo definido. La documentación detallada sobre el algoritmo de vinculación de llamadas está disponible en la especificación del método. Si no existe ninguna entidad en la base de datos del sistema que coincida con el número telefónico proporcionado, el registro de la llamada no se vinculará a ninguna entidad. El sistema ofrece múltiples opciones para mostrar la información de la llamada, dependiendo de la dirección de la llamada (entrante o saliente).
El sistema ofrece múltiples opciones para mostrar la información de la llamada, dependiendo de la dirección de la llamada (_entrante _o saliente).
Updated 6 days ago
