Guide voice management

LE GUIDE UTILISATEUR DE VOTRE SOLUTION CALL CENTER

Extension du comportement du connecteur

1 - Extension du comportement du connecteur

Depuis la version 2.0 il est possible de faire du travail avant, après ou à la place de la recherche du numéro de l’appelant.

Il est possible de créer un Contact en amont si vous en avez besoin avant de le rechercher par notre méthode par exemple.
Il est aussi possible de créer ou rechercher un Case et de retourner cet Id au lieu de notre recherche.
Ou alors de complètement revoir vous même l’intégralité de la recherche selon vos propres besoins ex : recherche différente en fonction du profil de l’opérateur.

2 - Activer mes redéfinitions

Créer une classe qui hérite de AxiaVM.Extension :

				
					global class MyAxialysExtension extends AxiaVM.Extension {
    // code d'extension ici
}



				
			

Pour utiliser cette extension de code il faut insérer dans la table AxiaVM__ConfigCTI__c un élément avec

Name = 'redefined_class'et AxiaVM__value__c = 'MyAxialysExtension'

ou

AxiaVM__value__c = 'MyOrgNamespace.MyAxialysExtension'

si votre classe est dans un Namespace

3 - Méthode de recherche (appel entrant / sortant)

Version supérieure à 2.0

La recherche reçoit un JSON sérialisé en entrée et renvoie une Liste d’Id.
Le json contient actuellement deux valeurs :

				
					

{
    "e164": "[numéro_appelant]" ,  // numéro en String de l'appelant, ex : 33123456789
    "numSVI": "[numéro_appelé]"    // numéro en String du SVI appelé
}


				
			

Le retour doit être une List<Id> même si il n’y a qu’un seul élément.

Exemple de redéfinition

Dans cet exemple, on souhaite créer un Case et l’ouvrir à la place du Contact.
On va exécuter le code parent, créer le Case et renvoyer l’Id de ce case.

				
					global class MyAxialysExtension extends AxiaVM.Extension {

    /**
     * @description Retourne une liste d'Id d'objet à ouvrir.
     *
     * - un seul élément retourné sera ouvert
     * - plusieurs va déclencher une ouverture de la recherche avec le numéro de téléphone
     *
     * @param   params   Chaine en Json sérialisé qui contient les paramètres
     * @return  List<Id>
     */
    global override List<Id> getIdsByPhone(String params) {

        // si je veux récupérer les champs du paramètre js
        Map<String, Object> tmp = (Map<String, Object>) JSON.deserializeUntyped(params);
        String e164 = (String) tmp.get('e164');
        String numSVI = (String) tmp.get('numSVI');

        // On peut faire du travail en amont

        // On peut récupérer le résultat de la méthode parente
        List<Id> s = super.getIdsByPhone(params);

        // On peut aussi faire quelque chose après pour changer le retours ou ajouter un Objet
        Case c = new Case(
            Subject = 'Appel en cours',
            Origin = 'Phone',
            ContactId = s[0],
            Status = 'Working',
            SVI__c = numSVI
        );
        insert c;

        return new List<Id>{ c.Id };
    }

}

				
			

Version supérieure à 2.30

Vue globale de la classe SeekPhone

Dans le connecteur du Voice-management, SeekPhone est utilisé afin de rechercher le numéro de l’appelant dans les différents objets possibles (Account, Contact, Lead) et de retourner le résultat trouvé à la fenêtre du Voice-management.
Selon les options on peut au choix :

  • créer la fiche si on ne la trouve pas
  • ouvrir une fenêtre de recherche
  • ne rien faire du tout.

 

				
					global class SeekPhone {
    /**
     * Recherche la fiche de l'appelant et permet plusieurs comportement différents en retour
     * @param js JSON Sérialisé, (voir plus bas)
     * @return JSON sérialisé. Il est conseillé d'utiliser le helper SeekPhone.response
     */
    public static String get(string js) {
        // travail de recherche
        return SeekPhone.response('OBJECT', (String) objectId);
    }

    /**
     * Helper qui fournit une réponse en JSON sérialisé pour retours de la méthode `get`
     * @params type Type d'ouverture que l'on va demander au voicemanagement pour l'appel
     *         valeurs possibles : 'OBJECT'|'SEARCH'|'URL'|'NOTHING'
     * @param value id ou numéro de téléphone à rechercher
     */
    global static String  response (String type, String value) {
        return json.serialize(new Map<String, Object> {
            'type' => type,
            'values' => new List<String>{value}
        });
    }
}

				
			
  • Le retour conditionne l’affichage en sortie du Voice-management :
  • OBJECT : Ouvre un objet Salesforce peut importe sa classe. values est un tableau d’un seul élément qui contient l’id de l’objet.
  • SEARCH : Ouvre la recherche peut importe le résultat. values est un tableau d’un seul élément qui contient le critère à recherche (par exemple le numéro de l’appelant).
  • URL : Ouvre une page sur un composant Lightning de votre organisation. values est un tableau d’un seul élément qui contient l’url à ouvrir.
  • NOTHING : Ne fait rien du tout.

 

Redéfinition du comportement de SeekPhone.get

Pour faire du travail en amont, en aval, ou à la place de SeekPhone.get, il est possible d’utiliser l’héritage de cette sorte

				
					global class MyAxialysExtension extends AxiaVM.Extension {
    global override String seekPhone(String js) {
        // ici je peux faire du travail en amont
        [...]

        // execution du code parent (optionnel)
        String s = super.seekPhone(js);

        // ici je peux faire du travail en aval
        [...]

        // selon mon retour je peux changer complètement le comportement
        return SeekPhone.response('SOBJECT|URL|SEARCH...', value);
    }
}

				
			

Les éléments présents dans la variable js sont les suivants :

				
					{
    "e164": "33123456789",
    "numSVI": "33800800800",
    "inOut": "in/out"
}

				
			

4 - Méthode d’ajout de Tâche

Version supérieure à 2.0

La recherche reçoit un JSON sérialisé en entrée et renvoie une Liste d’Id.
Le json contient actuellement deux valeurs :

				
					

{
    "e164": "[numéro_appelant]" ,       // numéro en String de l'appelant, ex : 33123456789
    "dt": "[date_appel]",               // date de l'appel au format DateTime apex
    "id_appel": "[id_appel_voice]",     // id de l'appel du voice management
    "inOut": "[appel_entrant_sortant]", // "in" ou "out" sens de l'appel
    "op_email": "[email_operateur]",    // email de l'opérateur pour attribution
    "groupe": "[groupe]",               // nom du groupe qui à eu l'appel
    "duree": "[temps_de_l_appel]",      // temps de l'appel en secondes
    "rec": "[presence_enregistrement]"  // Booléen qui détermine la présence d'un enregistrement
}


				
			

Le retour doit être l’Id de la tache.

 

Exemple de redéfinition

Dans cet exemple, on souhaite ajouter la tache à l’appel et non au Contact de l’appelant. On va exécuter le code de la recherche de l’apelant et trouver le Case associé et y attacher la tâche.

				
					

global class MyNewExtension extends AxiaVM.Extension {

    global override Id recordTask(String params) {

        Map<String, Object> tmp = (Map<String, Object>) JSON.deserializeUntyped(params);
        String e164 = (String) tmp.get('e164');
        String op_email = (String) tmp.get('op_email');
        String op_email = (String) tmp.get('op_email');
        Datetime date = (Datetime) tmp.get('dt');
        String inout = (String) tmp.get('inOut');

        User[] operator = [SELECT Id FROM User WHERE FederationIdentifier =: op_email ];
        List<List<Contact>> tmp = [FIND :e164 IN PHONE FIELDS  RETURNING Contact(Id)];
        Id id_contact = tmp[0].Id;
        Case c = [SELECT Id FROM Case WHERE ContactId =: id_contact];

        Task task = new Task(
            OwnerId = operator.Id,
            CreatedDate = date,
            WhatId = c.Id,
            Subject = 'appel ' + inout
            //[...]
        );
        insert task;

        return new List<Id>{ task.Id };
    }
    
}


				
			

Version supérieure à 2.30

Depuis cette version il existe deux JSON différent en fonction d’une tâche d’appel ou d’une tâche d’envoi de sms :

JSON de tâche d’appel

				
					{
    "e164": "numero appelant",
    "id_call": "id de l'appel",
    "inOut": "in|out",
    "group_name": "Nom du groupe",
    "call_duration": 123, // en secondes
    "wait_duration": 0,   // en secondes
    "type": 'CALL',
    "numSVI": "numéro du SVI",
    "objectType": "Classe de l'objet dans lequel l'opérateur est ex : Account|Contact|Lead|Case...",
    "recordId": "Id de l'objectType",
    "url": "URL de l'objectType",
    "mode": "task|cron",
    "op_mail": "operator@email",
    "begin_ts":  159269489, // timestamp du début de l'appel
    "end_ts": 159269489,    // timestamp de fin de l'appel
    "transferred_to": "info de transfert"
}

				
			

JSON de tâche d’un SMS

				
					{
    "e164": "numero appelant",
    "content": "contenu du sms (optionnel)",
    "success": true|false, // si tout c'est bien passé pendant l'envoie
    "objectType": "Classe de l'objet dans lequel l'opérateur est ex : Account|Contact|Lead|Case...",
    "recordId": "Id de l'objectType",
    "url": "URL de l'objectType",
    "type": "SMS",
    "mode": "task",
    "op_mail": "operator@email"
}

				
			

Exemple de redéfinition d’une Tache

Dans cet exemple, on souhaite ajouter la tache à l’appel et non au Contact de l’appelant. On va exécuter le code de la recherche de l’appelant et trouver le Case associé et y attacher la tâche.

				
					global class MyNewExtension extends AxiaVM.Extension {

    global override Id recordTask(String params) {

        Map<String, Object> tmp = (Map<String, Object>) JSON.deserializeUntyped(params);
        String e164 = (String) tmp.get('e164');
        String op_mail = (String) tmp.get('op_mail');
        String inout = (String) tmp.get('inOut');
        String type = (String) tmp.get('type');
        //[...]

        if (type == 'CALL') {
            User[] operator = [SELECT Id FROM User WHERE FederationIdentifier =: op_mail ];
            List<List<Contact>> tmp = [FIND :e164 IN PHONE FIELDS  RETURNING Contact(Id)];
            Id id_contact = tmp[0].Id;
            Case c = [SELECT Id FROM Case WHERE ContactId =: id_contact];

            Task task = new Task(
                OwnerId = operator.Id,
                WhatId = c.Id,
                Subject = 'appel ' + inout == 'in' ? 'entrant' : 'sortant'
                //[...]
            );
            insert task;

            return task.Id ;
        }
        return super.recordTask(params)
    }

}

				
			

5 - Déclarer ma classe d’extension

Procédure temporaire, dans une version ultérieure sera ajouté un sélecteur dans la page de paramétrage du Voice Management.

On va signaler au connecteur VoiceManagement qu’il y a une classe d’extension.

Il faut pour ce faire définir un nouvel objet dans la table AxiaVM__ConfigCTI__c.
Par exemple pour une classe MyNewExtension qui étend AxiaVM.Extension, il faut créer un objet AxiaVM__ConfigCTI__cName = "redefined_class" et AxiaVM__value__c = "MyNewExtension".