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

Envoyer un devis pour acceptation via eSignature (Ok!Sign)

0000003141     -      13/06/2023

La programmation illustrée ici montre comment automatiser l'envoi d'un devis à un client afin de le soumettre à son acceptation via signature externe via le service OkSign.

Pour le mettre en place, il faut :

  • activer la production des duplicatas PDF dans la séquence de devis
  • placer dans le modèle d'impression une marque de signature _Signature_ (modèle d'exemple disponible dans le fichier zip ci-dessous)
  • ajouter les colonnes dans la table PIEDS_V via le script SQL repris plus bas
  • ajouter les zones éditables correspondant à ces colonnes (fichier tab disponible dans le fichier zip ci-dessous).
alter table PIEDS_V add NOM char(30) not null default ''
alter table PIEDS_V add FONCTION char(20) not null default ''
alter table PIEDS_V add EMAIL char(40) not null default ''
alter table PIEDS_V add NUM_GSM char(20) not null default ''
alter table PIEDS_V add OKSIGN_DOC_ID char(50) not null default ''
alter table PIEDS_V add OKSIGN_SENT datetime not null default '19000101'

 

L'onglet proposé se présente comme ceci :

La signature sera demandée dans le PDF sous cette forme :

Le customizer Billing dont le code est repris ci-dessous doit être référencé dans la séquence.

Zoom
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
using MercatorApi;
using MercatorExtensions;
using MercatorUi;
using IneoSmtp;
using System.Text.RegularExpressions;
using System.Linq;

// <CompileWithRoslyn />

namespace Billing
{
    public class Customizer : MercatorUi.ICustomizers.IBillingEngineCreated, MercatorUi.ICustomizers.IBillingEngineClosed
    {
        public void BillingEngineCreated(MercatorUi.Engine.Gescom.BillingEngine billingEngine)
        {
            billingEngine.TagString = "999999;999999-9FB99999-99CD-9F99-9B99-B9EAE99DDC99;As99ErT999XX999XxxXXxxXx9";
            billingEngine.BeforeSave += BillingEngine_BeforeSave;
            billingEngine.PdfDuplicateCreated += BillingEngine_PdfDuplicateCreated;
        }

        public void BillingEngineClosed(MercatorUi.Engine.Gescom.BillingEngine billingEngine)
        {
            billingEngine.BeforeSave -= BillingEngine_BeforeSave;
            billingEngine.PdfDuplicateCreated -= BillingEngine_PdfDuplicateCreated;
        }

        private void BillingEngine_BeforeSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.BeforeSaveEventArgs e)
        {
            MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
            if (billingEngine.IsNew)
            {
                Dictionary<string, string> dicoNotEmpty = new Dictionary<string, string>
                {
                    { "NOM", _Divers.Iif_langue(Globals.Langue, "Name", "Naam", "Nom") },
                    { "EMAIL", _Divers.Iif_langue(Globals.Langue, "Email", "Email", "Email") },
                    { "FONCTION", _Divers.Iif_langue(Globals.Langue, "Function", "Functie", "Fonction") },
                    { "NUM_GSM", _Divers.Iif_langue(Globals.Langue, "Mobile", "GSM", "GSM") },
                };
                foreach (KeyValuePair<string, string> kvp in dicoNotEmpty)
                {
                    if (string.IsNullOrWhiteSpace(billingEngine.PIEDS[kvp.Key].ToString()))
                    {
                        Dialogs.Stop(string.Format(_Divers.Iif_langue(Globals.Langue,
                            "The \"{0}\" field is mandatory!",
                            "Het veld \"{0}\" is verplicht!",
                            "Le champ \"{0}\" est obligatoire !"), kvp.Value));
                        List<Control> l = billingEngine.BillingForm.FindMovableControlsBySource(kvp.Key);
                        if (l.Any())
                            _Divers.FocusError(l[0]);
                        e.CancelSave = true;
                        return;
                    }
                }

                Regex regex = new Regex(@"^\+?[1-9]\d{1,14}$");
                if (!regex.IsMatch(billingEngine.PiedsVRecord.NUM_GSM))
                {
                    Dialogs.Stop(_Divers.Iif_langue(Globals.Langue,
                        "The mobile phone number must start with + and contain only digits!",
                        "Het GSM nummer moet beginnen met + en mag alleen cijfers bevatten!",
                        "Le numéro de GSM doit commencer par + et ne contenir que des chiffres !"));
                    List<Control> l = billingEngine.BillingForm.FindMovableControlsBySource("NUM_GSM");
                    if (l.Any())
                        _Divers.FocusError(l[0]);
                    e.CancelSave = true;
                    return;
                }
            }
        }


        private void BillingEngine_PdfDuplicateCreated(object sender, MercatorUi.Engine.Gescom.BillingEngine.PdfDuplicateCreatedEventArgs e)
        {
            MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
            if (billingEngine.IsNew)
            {
                MercatorSigning.OkSign.FormDescriptor.FormHelper formHelper1 = new MercatorSigning.OkSign.FormDescriptor.FormHelper
                {
                    FieldMarker = "_Signature_",
                    FieldWidth = 175,
                    FieldHeight = 70,
                    FieldSigningOptions = MercatorSigning.OkSign.FormDescriptor.FormHelper.SigningOptionsEnum.Tan | MercatorSigning.OkSign.FormDescriptor.FormHelper.SigningOptionsEnum.Eid | MercatorSigning.OkSign.FormDescriptor.FormHelper.SigningOptionsEnum.Pen | MercatorSigning.OkSign.FormDescriptor.FormHelper.SigningOptionsEnum.Itsme,
                    SignerInfoName = billingEngine.PiedsVRecord.NOM,
                    SignerInfoMobile = billingEngine.PiedsVRecord.NUM_GSM,
                    SignerInfoActingAs = billingEngine.PiedsVRecord.FONCTION,
                    SignerInfoEmail = billingEngine.PiedsVRecord.EMAIL
                };
                MercatorSigning.OkSign.FormDescriptor formDescriptor = new MercatorSigning.OkSign.FormDescriptor
                {
                    SendToMeEmail = "info@mercator.eu", // pas obligatoire si le mail à utiliser est celui dans le compte OkSign
                    Logo = "https://www.mercator.eu/assets/images/logo.png", // pas obligatoire si le logo à utiliser est celui dans le compte OkSign
                    FileName = $"Devis_{billingEngine.Piece}.pdf" // nom du fichier visible par le signataire. Peut contenir une chaîne libre terminant par .pdf
                };
                formDescriptor.FormHelpers.Add(formHelper1);

                MercatorUi.Wait.WaitStatic.WaitWindow("OkSign...");

                MercatorSigning.OkSign.OkSignResponse response = MercatorSigning.OkSign.UploadPdfForSignature(e.PdfFile, formDescriptor, billingEngine.TagString, out string error);;
                if (!string.IsNullOrEmpty(error))
                {
                    MercatorUi.Wait.WaitStatic.WaitClear();
                    Dialogs.Stop(error);
                }
                else
                {
                    bool isOk;
                    using (SqlCommand cmd = new SqlCommand("update PIEDS_V set OKSIGN_DOC_ID=@OKSIGN_DOC_ID,OKSIGN_SENT=getdate() where (id=@id) and (journal=@journal) and (piece=@piece)"))
                    {
                        cmd.Parameters.AddWithValue("@id", billingEngine.Id).SqlDbType = SqlDbType.Char;
                        cmd.Parameters.AddWithValue("@journal", billingEngine.Journal).SqlDbType = SqlDbType.Char;
                        cmd.Parameters.AddWithValue("@piece", billingEngine.Piece);
                        cmd.Parameters.AddWithValue("@OKSIGN_DOC_ID", response.DocId);
                        isOk = Api.SqlExec(MercatorUi.Globals.RepData, cmd);
                    }
                    if (!isOk)
                    {
                        MercatorUi.Wait.WaitStatic.WaitClear();
                    }
                    else
                    {
                        billingEngine.PIEDS["OKSIGN_DOC_ID"] = response.DocId;
                        billingEngine.PIEDS["OKSIGN_SENT"] = DateTime.Now;

                        string msg = "Cher client<br><br>"
                                   + "Nous vous remercions de bien vouloir utiliser le lien ci-dessous si vous désirez accepter notre devis.<br>"
                                   + string.Format("<a href=\"{0}\">Lien</a><br>", response.Result[0].Url)
                                   + response.Result[0].Url // URL du premier signataire. Foreach nécessaire si plusieurs signataires pour envoyer un mail différent à chaque signataire.
                                   + "<br><br>"
                                   + "Nous vous en remercions.<br><br>"
                                   + "Sales Team";

                        Smtp mail = new Smtp
                        {
                            MailServer = Globals.Params["SMTP_HOST"],
                            Recipient = billingEngine.PiedsVRecord.EMAIL,
                            SenderEmail = Globals.CurrentUserRecord.CRM_MAIL,
                            SenderName = Globals.CurrentUserRecord.CRM_NOM,
                            Subject = billingEngine.BillingForm.Text,
                            ForceHtml = true,
                            Message = "<html><body>" + msg + "</body></html>"
                        };
                        if (!mail.SendMail())
                        {
                            MercatorUi.Wait.WaitStatic.WaitClear();
                            Dialogs.Stop(mail.Error);
                        }
                        else
                        {
                            MercatorUi.Wait.WaitStatic.WaitClear();
                            Dialogs.Stop("Devis correctement envoyé pour acceptation via Ok!Sign !");
                         }
                    }
                }
            }
        }
    }
}

 

Le code du customizer doit être adapté en plaçant le x-oksign-authorization obtenu sur le portail Ok!Sign dans billingEngine.TagString. Cela permet de fixer ce paramètre une seule fois et de l'utiliser à différents endroits du devis.

Lors de la sauvegarde initiale du devis,

  • l'API de Mercator est utilisée pour communiquer avec les serveurs de Ok!Sign et transmettre le duplicata PDF à signer, ainsi que le formulaire de signature.
  • en cas de succès, un email est envoyé au signataire externe avec un lien lui permettant de signer ce document en ligne.

Le bouton "Statut Signature" permet de savoir si

  • le document est en attente de signature,
  • a été partiellement signé,
  • a été signé par toutes les parties.

Quand ce 3ème état est atteint, il est possible de télécharger le document signé via le bouton "Récupérer Document Signé". Le fichier ainsi téléchargé sera directement placé dans le SqlFileView ou le FileView du devis avec le nom signed.pdf. Le système propose ensuite de supprimer le fichier du portail Ok!Sig. Ceci est recommandé afin de limiter la consommation d'espace sur le portail. (Note : les fichiers ne sont jamais supprimés automatiquement, hormis via ce processus.)

 

 

Mots clés : OkSign

A télécharger : 0000003141.zip (37 Kb - 20/03/2023)