Call result

When the conversation is over, you can provide the managers the ability to provide call result. The call result window contains information about the caller, a field to choose the entity to which the call will be connected, attaching the call record and adding a task with specific time, notes about the call, if there were any. If the manager does not accept the call, information about the call with zero duration is recorded. The appearance of the call result window is implemented in the UI/UX, while updating the call is done in the integration.

An example of the call result window.

This modal window consists of the following elements:

  1. Window name: Call summary
  2. Linked entity (contact / company)
  3. Lead/Customer is a field with search property to find the suitable lead/customer
  4. Call recording panel (indicating the duration of the call and the ability to listen)
  5. Time and note for task
  6. Save or Cancel buttons

An example about the call result implementation in the UI/UX is given in our VoIP API.

After choosing the entity and filling the fields, you should save the call result, update the call by changing its link to the chosen entity if it’s done. For that, a task is created to be added to the queue.
Let’s consider the following scenario

  1. A call from a known contact is done.
  2. A webhook about ending the call could be launched. It comes from the VoIP service. Then the integration backend should affect one of the lead/customer/contact/company, or create an incoming lead if no entity connected to the phone number exists.
  3. The manager adds the call result as a note, chooses a different entity than the one chosen by the algorithm. The note should be linked to the chosen entity. The link to the suggested entity should be deleted programmatically.
  4. The VoIP service sends the call recording, and it will be linked to the call card.

As we mentioned in the call logging use case, all calls should be grabbed from the VoIP service and stored in the calls repository in the integration database. We also implemented a function to choose a call by its identifiers.

public static function getByCallIdAndKommoAccountId(string $callId, int $KommoAccountId): voipCalls{
    return voipCalls::query() 
		->where('call_id', '=', $callId)
		->where('Kommo_account_id', '=', $KommoAccountId)
		->first();
}

A task to update the call according to the information that came from the modal call result window

//UpdateFromModalTask
public function __construct(
    int $kommoAccountId,
    string $callId,
    protected int $entityId,
    protected string $entityType
);

An example about the use case which is responsible for updating the call according to the information that came from the call result modal window is explained here

//UpdateFromModalUseCase
public function handle(UpdateFromModalTask $task): void
    {
        $widgetSettings = WidgetSettingsRepository::getByKommoAccountId($task->getKommoAccountId());
        $VoIPCall = VoIPCalls::getByCallIdAndKommoAccountId(
            $task->getCallId(),
            $widgetSettings->getKommoAccountId()
        );
        $call = Call::fromModel($ringcentralCall);
        if ($record = $VoIPCall->getRecording() ?? '') {
            $record = sprintf(
                '%s/voip/%s/get_call_record/%s',
                $this->appConfig->getBaseUrl(),
                $widgetSettings->getKommoAccountId(),
                $VoIPCall->getCallId()
            );
        }
        $call->setRecordLink($record);
        $apiClient = $this->KommoApiClient;
        $unsorted = null;
        /** If the call is in incoming leads:
        * a) If the manager choose lead/customer entity, you need to attach a contact to it;
        * b) If the manager choose contact/company entity, you need to pick it up from the contact in the incoming lead
        */
        if ($VoIPCall->getUnsortedUid() !== null) {
                $unsorted = $apiClient->findUnsortedByUid($VoIPCall->getUnsortedUid());
                $unsortedContact = $unsorted->getContacts()?->first();

                $entityType = KommoEntityType::tryFrom($task->getEntityType());
                switch ($entityType) {
                    case KommoEntityType::LEADS:
                    case KommoEntityType::CUSTOMERS:
                        if ($unsortedContact !== null) {
                            $apiClient->linkContact($unsortedContact, $entityType, $task->getEntityId());
                        }
                        break;
                    case KommoEntityType::CONTACTS:
                    case KommoEntityType::COMPANIES:
                        // in the incoming lead only the contact id. We'll get all the information.
                        if ($unsortedContact !== null) {
                            $unsortedContact = $apiClient->getContactById($unsortedContact->getId());
                            $phones = $unsortedContact->getCustomFieldsValues()?->getBy('fieldCode', 'PHONE');
                            $newPhone = $phones?->getValues()?->first()->getValue();
                            if (!empty($newPhone)) {
                                $apiClient->updatePhones($task->getEntityId(), $entityType, (string)$newPhone);
                            }
                        }
                        break;
                    default:
                        throw UnsupportedEntityException::create();
                }
        }
        $apiClient->updateCallEvent(
                $call,
                $VoIPCall->getResponsibleUserId() ?? self::BOT_USER_ID,
                $VoIPCall->getEntityId(),
                $VoIPCall->getEntityType(),
                $task->getEntityId(),
                $task->getEntityType()
        );

        // reject incoming lead after declining the call note
        if ($unsorted) {
                $apiClient->declineUnsorted($unsorted);
                $VoIPCall->setUnsortedUid(null);
        }
        $VoIPCall->setEntityType($task->getEntityType());
        $success = $VoIPCall->save();
        $task->setSuccess($success);
}

The task is created inside the worker, which grabs the task from the queue and sends it to the handler.

//UpdateFromModalWorker
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');
	}
}

Next Caller ID use case.