Vous consultez une page technique concernant le logiciel de gestion Mercator. Celle-ci contient des informations spécifiques destinées aux professionnels de Mercator. Souhaitez-vous être redirigés vers des informations plus générales ?


   Ne plus poser cette question

Action Rendez-vous (Google Calendar)

0000002950     -      20/12/2019

Pour installer cette action :

  • Dézipper le fichier ZIP ci-inclus
  • Plus d'information pour une installation rapide
  • Paramétrer le compte Google pour autoriser l'accès via l'API (voir ci-dessous)
  • Placer le fichier JSON issu de ce paramétrage dans les fichiers SQL > Autres
  • Placer ces DLL dans le répertoire principal de Mercator
    • Google.Apis.Auth.dll
    • Google.Apis.Auth.PlatformServices.dll
    • Google.Apis.Calendar.v3.dll
    • Google.Apis.Core.dll
    • Google.Apis.dll
    • Google.Apis.PlatformServices.dll
    • MercatorGoogleCalendarClient.dll
    • Newtonsoft.Json.dll
  • Modifier le customizer de l'action pour y spécifier le nom de ce fichier JSON ainsi que l'ID du calendrier qui devra recevoir les actions de Mercator.

Le fichier reprend les paramètres de l'action suivante : saisie d'un rendez-vous qui sera répercuté dans Google Calendar®.

Le formulaire de cette action reprend :

  • Sujet
  • Début : date et heure
  • Fin : date et heure
  • Le corps du rendez-vous reprenant une note.

Lorsque le rendez-vous aura le statut "Fait", un champ compte-rendu apparaîtra.

Lors de la réouverture d'une action de ce type, Mercator vérifiera si le rendez-vous existe dans Google Calendar. S'il est trouvé, les modifications éventuelles apportées dans Google Calendar seront répercutées dans Mercator.

Les adaptations souhaitées pour personnaliser le comportement de la liaison à Google Calendar peuvent être apportées dans le code C#

  • du customizer de l'action
  • des sources de MercatorGoogleCalendarClient.dll (voir ci-dessous).

 

Pour passer dans une logique de gestion des agendas par utilisateur, il faut, par exemple, remplacer cette ligne dans le customizer

Zoom
private const string calendarId = "xxx.yyy@gmail.com";

par celle-ci

Zoom
private string calendarId = MercatorUi.Globals.CurrentUserRecord.CRM_MAIL;

Paramétrer le compte Google pour autoriser l'accès via l'API

La première étape consiste à créer un compte de service. Ce compte de service peut être utilisé pour différents calendriers appartenant à différents utilisateurs. Les rendez-vous que Mercator va exporter seront marqués comme créés par ce compte de service.

  1. Accéder à la console de Google Api et services, et y cliquer sur le bouton "Sélectionner"
  2. Choisir un projet ou créer un nouveau projet
  3. Cliquer sur le bouton "Activer" ou "Gérer"
  4. Dans la marge de gauche, cliquer sur "Identifiants" et ensuite sur le lien "Identifiants des API et services"
  5. Cliquer sur le déroulant "Créer des identifiants" et choisir "Clé de compte de service"
  6. Saisir un nom de compte de service. Garder l'option par défaut "JSON". Cliquer sur le bouton "Créer"
  7. Cliquer sur le bouton "Créer sans rôle" et télécharger le fichier JSON contenant la clé privée
  8. Placer ce fichier dans les fichiers SQL de Mercator (Gestion > Fichiers SQL > Autres).

La seconde étape consiste à autoriser le compte de service à modifier le calendrier. Cette opération est à répéter dans les différents calendriers dans lesquels Mercator pourra écrire :

  1. Se rendre dans le calendrier
  2. Cliquer sur le menu "Paramètres" (engrenage) > Paramètres
  3. Cliquer sur le nom de votre calendrier à gauche et ensuite "Partager avec des personnes en particulier"
  4. Cliquer sur "Ajouter des contacts"
  5. Ajouter l'adresse mail du compte de service visible dans le fichier JSON (propriété client_email)
  6. Cliquer sur "Apporter les modifications et gérer le partage". Terminer par "Envoyer"
  7. Dans la même page, noter la valeur de "ID de l'agenda" et la reporter dans le customizer de l'action (calendarId).

Ce tutoriel est inspiré de cette page.


Modification de MercatorGoogleCalendarClient.dll

Pour modifier les sources de MercatorGoogleCalendarClient.dll, il faut, dans Visual Studio, créer un nouveau projet de type "Bibliothèque de classes (.NET Framework)" - FW 4.6, et ensuite

  • ajouter une référence vers MercatorTunnel.dll
  • ajouter le NuGet Google.Apis.Calendar.v3

Le code de l'unique classe que contient cette DLL est le suivant :

Zoom
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.Apis.Calendar.v3;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Calendar.v3.Data;
using MercatorApi;

namespace MercatorGoogleCalendarClient
{
    public static class Class
    {
        public static bool InsertOrUpdateEvent(string jsonCredentialsFile, string calendarId, EventDescriptor descriptor, out string errorMessage)
        {
            var service = getCalendarService(jsonCredentialsFile, calendarId, out errorMessage);
            if (service == null)
                return false;

            if (!string.IsNullOrWhiteSpace(descriptor.Id) && !descriptor.IsIdValid())
            {
                errorMessage = "ID invalide ! (doit contenir uniquement des chiffres ou des lettres minuscules - min. 5)";
                return false;
            }

            var eventEntry = new Event
            {
                Id = string.IsNullOrWhiteSpace(descriptor.Id) ? Api.NewId().Replace("-", "").ToLower() : descriptor.Id,
                Summary = descriptor.Summary,
                Description = descriptor.Description,
                Start = new EventDateTime { DateTime = descriptor.Start },
                End = new EventDateTime { DateTime = descriptor.End },
            };

            if (string.IsNullOrWhiteSpace(descriptor.Id)) // il s'agit d'un event qui n'a jamais été créé dans le calendrier Google
            {
                descriptor.Id = eventEntry.Id; // renvoyer le nouvel ID à l'appelant
                try
                {
                    var insertRequest = service.Events.Insert(eventEntry, calendarId);
                    insertRequest.Execute();
                }
                catch (Exception ex)
                {
                    errorMessage = "Insertion dans calendrier Google : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                    return false;
                }
            }
            else // rendez-vous normalement déjà existant dans le calendrier Google
            {
                try
                {
                    var updateRequest = service.Events.Update(eventEntry, calendarId, descriptor.Id);
                    updateRequest.Execute();
                }
                catch (Exception ex) // on gère ici l'exception levée si l'event n'existe pas dans le calendrier Google -> on crée un nouvel event
                {
                    if (ex.Message.Contains("404"))
                    {
                        try
                        {
                            var insertRequest = service.Events.Insert(eventEntry, calendarId);
                            insertRequest.Execute();
                        }
                        catch (Exception ex2)
                        {
                            errorMessage = "Insertion dans calendrier Google : " + ex2.Message + (ex2.InnerException != null ? "\r\n" + ex2.InnerException.Message : "");
                            return false;
                        }
                    }
                    else
                    {
                        errorMessage = "Mise à jour dans calendrier Google : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                        return false;
                    }
                }
            }
            return true;
        }

        public static EventDescriptor GetEvent(string jsonCredentialsFile, string calendarId, string eventId, out string errorMessage)
        {
            var service = getCalendarService(jsonCredentialsFile, calendarId, out errorMessage);
            if (service == null)
                return null;

            Event eventEntry;
            try
            {
                var getrequest = service.Events.Get(calendarId, eventId);
                eventEntry = getrequest.Execute();
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("404"))
                    return null; // l'event n'existe simplement pas dans le calendrier -> return null avec errorMessage == null
                errorMessage = "Sélection entrée calendrier Google : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }

            return new EventDescriptor
            {
                Id = eventEntry.Id,
                Summary = eventEntry.Summary,
                Description = eventEntry.Description,
                Start = eventEntry.Start.DateTime ?? new DateTime(1900, 1, 1),
                End = eventEntry.End.DateTime ?? new DateTime(1900, 1, 1)
            };
        }

        private static CalendarService getCalendarService(string jsonCredentialsFile, string calendarId, out string errorMessage)
        {
            errorMessage = null;
            string jsonCredentialsContent = Api.FileToStr("<Other\\" + jsonCredentialsFile);
            if (string.IsNullOrEmpty(jsonCredentialsContent))
            {
                errorMessage = string.Format("Fichier non trouvé \"<Other\\{0}\" !", jsonCredentialsFile);
                return null;
            }

            JsonCredentialParameters jsonCredentialParameters;
            try
            {
                jsonCredentialParameters = Google.Apis.Json.NewtonsoftJsonSerializer.Instance.Deserialize<JsonCredentialParameters>(jsonCredentialsContent);
            }
            catch (Exception ex)
            {
                errorMessage = $"Lecture de {jsonCredentialsFile} : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }
            ServiceAccountCredential serviceAccountCredential = new ServiceAccountCredential
            (
                new ServiceAccountCredential.Initializer(jsonCredentialParameters.ClientEmail)
                {
                    Scopes = new string[1] { CalendarService.Scope.Calendar },
                }.FromPrivateKey(jsonCredentialParameters.PrivateKey)
            );

            CalendarService calendarService;
            try
            {
                calendarService = new CalendarService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = serviceAccountCredential,
                    ApplicationName = "MercatorGoogleCalendarClient"
                });
            }
            catch (Exception ex)
            {
                errorMessage = "Création CalendarService Google : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }

            Calendar calendar;
            try
            {
                calendar = calendarService.Calendars.Get(calendarId).Execute();
            }
            catch (Exception ex)
            {
                errorMessage = $"Sélection du calendrier Google { calendarId } : " + ex.Message + (ex.InnerException != null ? "\r\n" + ex.InnerException.Message : "");
                return null;
            }

            return calendarService;
        }
    }

    public class EventDescriptor
    {
        public string Id { get; set; }
        public string Summary { get; set; }
        public string Description { get; set; }
        public DateTime Start { get; set; }
        public DateTime End { get; set; }

        public bool IsIdValid()
        {
            if (Id == null)
                return false;
            else
                return System.Text.RegularExpressions.Regex.Match(Id, "^[a-z0-9]{5,1024}$").Success;
        }
    }
}


A télécharger : 0000002950.zip (377 Kb - 25/11/2019)