Lors de la sauvegarde, interagir avec l'utilisateur

0000003000     -      23/02/2021

Le processus de sauvegarde de données modifiables (signalétiques, actions du CRM, documents de la gestion commerciale, inventaires, transferts de dépôts) est pris essentiellement en charge par MercatorPenguinServer. Cela permet l'exécution de customizers contenant du code personnalisant ce processus de sauvegarde. Etant donné cette architecture, il n'est pas trivial d'interagir avec l'utilisateur (qui est devant son application mobile) durant ce processus. Ceci est toutefois possible depuis MercatorPenguin 2.9.5. 

Pour les signalétiques, ceci doit se faire via du code spécifique dans l'événement PenguinServerBeforeValidateData, tandis que pour les autres données modifiables, ce sera via l'événement BeforeSave de l'engine correspondant. Le mécanisme est basé sur une interruption du processus de sauvegarde dans le serveur, simultanée avec l'envoi d'une question dans l'application mobile. Ce mécanisme peut être utilisé plusieurs fois pour poser plusieurs questions à l'utilisateur. Chaque fois que l'utilisateur valide une réponse, le processus de sauvegarde est automatiquement relancé, pour conduire à la question suivante ou à la validation finale si toutes les questions ont trouvé réponse.

Chaque question doit être numérotée avec un numéro unique. Chaque réponse aux questions va être "accumulée" dans e.BeforeSaveAnswers, qui est un Dictionnary<int, object>, où la clé est le n° de la question et la valeur le contenu de la réponse. Le customizer doit dès lors implémenter une logique qui détermine à quelles questions il a été répondu et qui exploite par ailleurs les réponses données. Cette logique doit intégrer le fait que le customizer sera appelé autant de fois que nécessaire afin que toutes questions puissent être soumises à l'utilisateur. (donc n questions -> n+1 sauvegardes)

Une question est posée en spécifiant ceci dans l'eventArgs de l'événement :

e.PenguinQuestion = new MercatorPenguin.Question();

Cette question doit au moins avoir ces propriétés complétées :

  • Id : n° de la question (voir ci-dessus)
  • Text : message affiché à l'utilisateur
  • Type : le type de question.

Les types de questions sont les suivants :

  • YesNo : boîte de dialogue "Oui / Non". Résultat boolean : Oui = True / Non = False
  • OkCancel : boîte de dialogue "OK / Annuler". Résultat boolean : OK = True / Annuler = False
  • String : boîte de dialogue permettant la saisie d'une chaîne de caractères (null si annulation)
    • La valeur par défaut peut être définie dans AskStringDefaultText
    • AskStringUpperCase permet de déterminer si la saisie doit être uniquement en majuscules ou pas
  • Decimal : boîte de dialogue permettant la saisie d'un nombre (decimal.MinValue si annulation)
    • La valeur par défaut peut être définie dans AskDecimalDefaultValue
    • AskDecimalDecimals permet de fixer le nombre de décimales souhaitées
  • Date : boîte de dialogue permettant la saisie d'une date (DateTime.MinValueDateTime.MinValue si annulation)
    •  La valeur par défaut peut être définie dans AskDateTimeDefaultValue
  • DateTime : boîte de dialogue permettant la saisie d'une date et d'un temps (DateTime.MinValueDateTime.MinValue si annulation)
    • La valeur par défaut peut être définie dans AskDateTimeDefaultValue
  • ListStrings : boîte de dialogue affichant une liste de chaînes de caractères (null si annulation)
    • La propriété AskListStringsItemsSource doit contenir un string[] et est obligatoire.
    • La propriété AskListStringsDefaultValue peut contenir la valeur par défaut.
  • ListItemStrings : boîte de dialogue affichant une liste de MercatorPenguin.Question.ItemStrings
    • La propriété AskListItemStringsItemsSource doit contenir un MercatorPenguin.Question.ItemString[] et est obligatoire. La propriété Lib sera affichée dans la liste et la valeur renvoyée sera Id (string). (null si annulation)
    • La propriété AskListItemStringsDefaultValue peut contenir l'Id de ItemString par défaut.
  • ListItemInts : boîte de dialogue affichant une liste de MercatorPenguin.Question.ItemInt
    • La propriété AskListItemIntsItemsSource doit contenir un MercatorPenguin.Question.ItemInt[] et est obligatoire. La propriété Lib sera affichée dans la liste et la valeur renvoyée sera Id (int).
    • La propriété AskListItemIntsDefaultValue peut contenir l'Id de l'ItemInt par défaut.

 

La propriété AbortIfCancel permet de déterminer si une réponse de l'utilisateur "Annuler / Non" doit immédiatement interrompre le processus de sauvegarde sans plus solliciter MercatorPenguinServer. Cette propriété sera en général à True, sauf si le customizer doit tenir compte à la fois des réponses "positives" et "négatives".

Le code ci-dessous montre comment poser deux questions lors de la sauvegarde d'une fiche client. La première question se fait sous la forme d'une boîte de dialogue "Oui / Non". La seconde question permettra la saisie d'une chaîne de caractères utilisée par le customizer.

Zoom
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using MercatorApi;
using MercatorExtensions;
using MercatorUi;
using MercatorDatabase;
using System.Windows.Forms;

// <CompileWithRoslyn />

namespace SigCli
{
    public class Customizer : MercatorUi.ICustomizers.ISigCreated
    {
        public void SigCreated(MercatorUi.Sig.Sig Sig)
        {
            Sig.PenguinServerBeforeValidateData += Sig_PenguinServerBeforeValidateData;
        }

        void Sig_PenguinServerBeforeValidateData(object sender, MercatorUi.Sig.Sig.PenguinServerBeforeValidateDataEventArgs e)
        {
            if (!e.BeforeSaveAnswers.ContainsKey(1))
            {
                e.PenguinQuestion = new MercatorPenguin.Question
                {
                    Id = 1,
                    Text = "Confirmer dans customizer ?",
                    Type = MercatorPenguin.Question.QuestionTypeEnum.YesNo,
                    AbortIfCancel = true
                };
                return;
            }
            if (!e.BeforeSaveAnswers.ContainsKey(2))
            {
                e.PenguinQuestion = new MercatorPenguin.Question
                {
                    Id = 2,
                    Text = "Nom du contact ?",
                    Type = MercatorPenguin.Question.QuestionTypeEnum.String,
                    AbortIfCancel = true
                };
                return;
            }
            else
            {
                e.Data.AddOrUpdate("C_CONTACT", e.BeforeSaveAnswers[2].ToString());
            }
        }
    }
}

 

Ce second code montre comment implémenter un comportement similaire dans un document de la gestion commerciale (BillingEngine). Le même processus peut être mis en place dans un ActionEngine, InventoryEngine ou TransferEngine.

Zoom
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Windows.Forms;
using MercatorApi;
using MercatorExtensions;
using MercatorUi;

namespace Billing
{
    public class Customizer : MercatorUi.ICustomizers.IBillingEngineCreated, MercatorUi.ICustomizers.IBillingEngineClosed
    {
        public void BillingEngineCreated(MercatorUi.Engine.Gescom.BillingEngine BillingEngine)
        {
            BillingEngine.BeforeSave += BillingEngine_BeforeSave;
        }

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

        void BillingEngine_BeforeSave(object sender, MercatorUi.Engine.Gescom.BillingEngine.BeforeSaveEventArgs e)
        {
            MercatorUi.Engine.Gescom.BillingEngine billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)sender;
            if (MercatorUi.Globals.IsMercatorPenguinServer)
            {
                if (!billingEngine.PenguinBeforeSaveAnswers.ContainsKey(1))
                {
                    e.PenguinQuestion = new MercatorPenguin.Question
                    {
                        Id = 1,
                        Text = "Confirmer dans customizer ?",
                        Type = MercatorPenguin.Question.QuestionTypeEnum.YesNo,
                        AbortIfCancel = true
                    };
                    return;
                }
                if (!billingEngine.PenguinBeforeSaveAnswers.ContainsKey(2))
                {
                    e.PenguinQuestion = new MercatorPenguin.Question
                    {
                        Id = 2,
                        Text = "Chaîne libre pour note 1 ?",
                        Type = MercatorPenguin.Question.QuestionTypeEnum.String,
                        AskStringDefaultText = billingEngine.PiedsVRecord.NOTE1,
                        AbortIfCancel = true
                    };
                    return;
                }
                else
                {
                    billingEngine.PiedsVRecord.NOTE1 = billingEngine.PenguinBeforeSaveAnswers[2].ToString();
                }
            }
        }
    }
}

 

Ce deuxième exemple présentera à l'utilisateur successivement ces deux boîtes de dialogue :