Aller au contenu

Comment Développer dans Smart Processing (Documentation Développeur)

Statut : 01.08.2026 • Temps de lecture : ~8 minutes

Smart Processing fournit des points d'extension où vous pouvez implémenter une logique personnalisée pour démarrer vos propres processus ou adapter le traitement aux exigences des clients. Ce document explique le concept clé du développement : travailler à travers la session active et déclencher des codeunits personnalisés dans le processus correspondant en utilisant les données de session.

1. Concept de Base : Travailler à Travers la Session de Traitement Active

Smart Processing exécute une “session de brouillon active” pendant qu'un document est traité. Pendant ce temps, l'état pertinent est maintenu de manière centrale (contexte du document, contexte du modèle, lignes correspondantes, écarts et données intermédiaires utilisées par l'interface utilisateur et le pipeline de traitement).

En tant que développeur, l'approche recommandée est :

  • Lire le contexte de traitement actuel à partir de la session.
  • Effectuer votre logique en utilisant le contexte et les références fournis.
  • Écrire les résultats/l'état dans la session lorsque le flux de travail en a besoin.
  • Compter sur la plateforme pour maintenir l'interface utilisateur et le traitement alignés grâce à l'architecture de session.

Cela rend les personnalisations stables et évite un état incohérent entre ce que les utilisateurs voient et ce que votre logique a changé.


2. L'Objet Central : “SIM_DI Process Session SI”

Le codeunit “SIM_DI Process Session SI” est le point d'entrée central pour accéder et manipuler la session Smart Processing actuellement active. Il agit comme un hub pour obtenir des données d'exécution pertinentes (document entrant, modèle de processus, tampons de ligne, métadonnées d'écart) et pour communiquer les résultats au pipeline (par exemple, quel en-tête a été traité).

Vue d'ensemble des fonctions publiques (à partir des exemples fournis)

Le tableau suivant répertorie les fonctions publiques qui sont réellement utilisées dans votre code d'exemple. Si une fonction existe dans plusieurs variantes (surcharges), les paramètres qui peuvent ne pas être présents dans chaque variante sont marqués comme optionnels.

Fonction Ce qu'elle fait Paramètres (optionnels marqués) Retourne
InitSession Initialise la session avec un document entrant et résout le modèle de processus associé. InboundDocument aucun
InitSession Initialise la session avec un document entrant et un modèle de processus explicitement fourni (et efface d'abord les données de session précédentes). InboundDocument, ProcessTemplate aucun
GetInboundDocument Récupère le document entrant stocké dans la session actuelle. var InboundDocument aucun
GetProcessTemplate Récupère le modèle de processus stocké dans la session actuelle. var ProcessTemplate aucun
ClearProcessSession Efface l'intégralité du contexte de session, y compris le document entrant, le modèle de processus, les clés de mappage et les données de processus. - aucun
ClearProcessData Efface uniquement les données de traitement (en-têtes/lignes/observations temporaires, enregistrements de recherche mappés, id d'en-tête traité) et efface les données correspondantes. - aucun
SetProcessedHeaderRecordId Stocke la référence d'enregistrement de l'en-tête de document cible créé/correspondant dans la session pour un traitement ultérieur (par exemple, achèvement/archivage). RecordId aucun
GetProcessedHeaderRecordId Retourne la référence d'enregistrement d'en-tête traité stockée et l'efface de la session par la suite. - RecordId
SetDocumentHeaderVariableRef Stocke une copie de la variable d'en-tête temporaire fournie dans la session (utilisée comme état d'en-tête de session de style référence). var TempDocumentHeader (temporaire) aucun
GetDocumentHeaderVariable Copie les données d'en-tête temporaire actuelles de la session dans la variable d'enregistrement temporaire fournie. var TempDocumentHeader (temporaire) aucun
SetDocumentLineVariableRef Stocke une copie de la variable de ligne temporaire fournie dans la session (utilisée comme état de ligne de session de style référence). var TempDocumentLine (temporaire) aucun
GetDocumentLineVariable Copie les données de ligne temporaires actuelles de la session dans la variable d'enregistrement temporaire fournie. var TempDocumentLine (temporaire) aucun
SetRemarkVariableRef Stocke une copie de la variable d'observation temporaire fournie dans la session (utilisée comme état d'observation de session de style référence). var DocumentRemark (temporaire) aucun
RemoveDocumentRemark Supprime une observation de la session en fonction du numéro de ligne, du numéro de champ et de la zone de validation. LineNo, FieldNo, FieldValidationArea aucun
GetRemarks Copie toutes les observations de session dans la variable d'enregistrement d'observation temporaire fournie. var DocumentRemark (temporaire) aucun
RemoveMappedLookupRecord Supprime la référence d'enregistrement de recherche mappée pour un champ de modèle donné. TemplateFieldRecordId aucun
GetMappedLookupRecord Récupère la référence d'enregistrement de recherche mappée pour un champ de modèle donné (si disponible). TemplateFieldRecordId, var MappedRecordId Boolean
GetDevitatingLinesJsonObject Retourne l'objet JSON décrivant les lignes déviantes et leurs champs non correspondants (y compris le nom de configuration de correspondance et les détails de non correspondance). - JsonObject
GetExecuteCodeunitRefRecordIds Récupère les références d'enregistrement assignées pour exécution par un codeunit spécifique (typiquement des lignes correspondantes à traiter). ExecuteCodeunitNo, var RecordIds Boolean
GetMatchedDocumentHeader Récupère la référence d'enregistrement d'en-tête de document correspondant pour un nom de configuration de correspondance donné (si disponible). MatchingSetupName, var MatchedDocumentHeaderRecordId Boolean

Remarque : Ce sont toutes les fonctions publiques qui peuvent être confirmées à partir de vos exemples. Si vous fournissez le code source complet du codeunit, j'élargirai ce tableau pour qu'il inclue toutes les fonctions publiques.


3. Personnalisations dans le Processus de Correspondance

Un scénario d'extension courant consiste à déclencher des codeunits personnalisés lors de la correspondance, en particulier lorsque l'utilisateur termine le brouillon et que l'enregistrement d'en-tête cible a été créé.

Un détail clé de ce mécanisme est que le codeunit personnalisé est exécuté avec l'enregistrement d'en-tête du type de document correspondant (par exemple, un en-tête d'achat). Cet enregistrement devient votre ancre stable : vous pouvez en dériver le contexte, créer ou importer des lignes, mettre à jour des enregistrements connexes, puis renvoyer le résultat à la session afin que la plateforme puisse continuer son flux de travail.


4. Exemples de Codeunits de Processus Personnalisés (Code Inchangé)

Exemple 1 : Importer les lignes de réception correspondantes après la création de l'en-tête

codeunit 5673320 "SIM_DI Purch.-Get Receipts"
{
    Description = 'Ce codeunit est utilisé comme codeunit d\'importation de correspondance pour recevoir des lignes de réception d\'achat et créer des lignes de facture d\'achat basées sur les lignes de document correspondantes.';
    TableNo = "Purchase Header"; // <-- Ceci est l'en-tête créé après avoir terminé le traitement
    Access = Internal;

    var
        GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Process Session SI";
        GlobalCodeunitGetReceipts: Codeunit "Purch.-Get Receipt";
        GlobalNoPurchaseReceiptLinesFoundLbl: Label 'Il n\'y a pas de lignes de réception d\'achat pouvant être traitées. Veuillez vérifier les lignes de réception d\'achat et vérifier si elles ont déjà été facturées.';

    trigger OnRun()
    var
        LocalRecordPurchRcptLine: Record "Purch. Rcpt. Line";
        LocalMatchedLineRecordId: RecordId;
        LocalToExecuteRecordIds: List of [RecordId];
    begin
        // Recevoir les lignes correspondantes qui doivent être exécutées
        GlobalCodeunitSIMDIProcessSessionSI.GetExecuteCodeunitRefRecordIds(Codeunit::"SIM_DI Purch.-Get Receipts", LocalToExecuteRecordIds);

        // Filtrer les lignes de réception d'achat en fonction des lignes correspondantes entrantes
        foreach LocalMatchedLineRecordId in LocalToExecuteRecordIds do
            if LocalRecordPurchRcptLine.Get(LocalMatchedLineRecordId) then
                LocalRecordPurchRcptLine.Mark(true);

        // Obtenir les lignes de réception d'achat qui n'ont pas été facturées
        LocalRecordPurchRcptLine.MarkedOnly(true);
        LocalRecordPurchRcptLine.SetFilter("Qty. Rcd. Not Invoiced", '<>0');

        // Si aucune ligne de réception d'achat n'est trouvée, lancer une erreur
        if LocalRecordPurchRcptLine.IsEmpty() then
            Error(GlobalNoPurchaseReceiptLinesFoundLbl);

        // Exécuter le processus pour obtenir les lignes de réception
        GlobalCodeunitGetReceipts.SetPurchHeader(Rec);
        GlobalCodeunitGetReceipts.CreateInvLines(LocalRecordPurchRcptLine);
        Commit();
    end;
}

Cet exemple montre un processus typique piloté par la correspondance : la session fournit la liste des “enregistrements à exécuter”, et votre codeunit effectue un import basé exactement sur ces références correspondantes.


Exemple 2 : Mettre à jour les champs déviants lorsque la déviation est acceptée

codeunit 5673350 "SIM_DI Update Deviating Fields"
{
    Description = 'Ce codeunit peut être utilisé pour mettre à jour les lignes de document liées avec les valeurs entrantes pour les champs qui ont été déviants pendant le processus de correspondance et où la déviation est acceptée.';
    Access = Public;

    var
        GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Process Session SI";
        GlobalCodeunitSIMCOREEvaluate: Codeunit "SIM_CORE Evaluate";
        GlobalCodeunitSIMCOREJSON: Codeunit "SIM_CORE JSON";

    trigger OnRun()
    var
        TempLocalRecordSIMDITempDocumentLine: Record "SIM_DI Temp. Document Line" temporary;
        LocalRecordSIMDIProcessTemplate: Record "SIM_DI Process Template";
        LocalRecordSIMDIInboundDocument: Record "SIM_DI Inbound Document";
        LocalCodeunitSIMDILogManagement: Codeunit "SIM_DI Log Management";
        LocalDocumentHeaderRecordId: RecordId;
        LocalRecordId: RecordId;
        LocalRecordRef: RecordRef;
        LocalFieldRef: FieldRef;
        LocalRecordIdText: Text;
        LocalDevitatingLinesJsonObject: JsonObject;
        LocalLineMatchingValidationFieldsJsonObject: JsonObject;
        LocalJsonToken: JsonToken;
        LocalFieldNoInteger: Integer;
        LocalFieldNoText: Text;
        LocalCellIndexInteger: Integer;
        LocalMatchingSetupNameText: Text;
        LocalOldValueText: Text;
        LocalNewValueText: Text;
        LocalValueVariant: Variant;
        LocalDevitatingFieldUpdateLbl: Label 'La ligne %1 a été mise à jour.\Le champ "%2" a été changé de la valeur "%3" à la valeur "%4".', Comment = '%1 = Numéro de ligne, %2 = Nom du champ, %3 = Ancienne valeur, %4 = Nouvelle valeur';
    begin
        /// Recevoir les données de la session de processus
        LocalDevitatingLinesJsonObject := GlobalCodeunitSIMDIProcessSessionSI.GetDevitatingLinesJsonObject();
        GlobalCodeunitSIMDIProcessSessionSI.GetDocumentLineVariable(TempLocalRecordSIMDITempDocumentLine);
        GlobalCodeunitSIMDIProcessSessionSI.GetInboundDocument(LocalRecordSIMDIInboundDocument);
        GlobalCodeunitSIMDIProcessSessionSI.GetProcessTemplate(LocalRecordSIMDIProcessTemplate);

        // Itérer sur les 
        foreach LocalRecordIdText in LocalDevitatingLinesJsonObject.keys() do begin
            if not Evaluate(LocalRecordId, LocalRecordIdText) then continue;
            if not LocalRecordRef.Get(LocalRecordId) then continue;

            // Obtenir l'enregistrement de ligne actuel
            LocalDevitatingLinesJsonObject.Get(LocalRecordIdText, LocalJsonToken);
            // Obtenir le nom de configuration de correspondance
            LocalMatchingSetupNameText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'MatchingSetupName');

            // Obtenir les champs non correspondants sous forme d'objet json
            if not LocalJsonToken.AsObject().Get('MissMatchedFields', LocalJsonToken) then continue;
            LocalLineMatchingValidationFieldsJsonObject := LocalJsonToken.AsObject();
            // Itérer sur les champs non correspondants et mettre à jour la ligne de document liée avec la valeur entrante si la déviation est acceptée
            foreach LocalFieldNoText in LocalLineMatchingValidationFieldsJsonObject.keys() do begin
                if not Evaluate(LocalFieldNoInteger, LocalFieldNoText) then continue;
                LocalLineMatchingValidationFieldsJsonObject.Get(LocalFieldNoText, LocalJsonToken);

                if not GlobalCodeunitSIMCOREJSON.GetJsonPathValueBoolean(LocalJsonToken.AsObject(), 'AcceptDeviation') then
                    continue;
                if not Evaluate(LocalCellIndexInteger, GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'CellIndex')) then
                    continue;

                LocalFieldRef := LocalRecordRef.Field(LocalFieldNoInteger);
                LocalNewValueText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'IncomingValue');
                LocalOldValueText := LocalFieldRef.Value;

                // Mettre à jour le champ avec la valeur entrante
                GlobalCodeunitSIMCOREEvaluate.EvaluateVariable(
                   LocalNewValueText,
                   Format(LocalFieldRef.Type),
                   LocalValueVariant,
                   false
               );
                LocalFieldRef.Validate(LocalValueVariant);
                LocalRecordRef.Modify();

                // Ajouter une entrée de journal
                LocalCodeunitSIMDILogManagement.AddInformationInTheLog(
                    StrSubstNo(LocalDevitatingFieldUpdateLbl, Format(LocalRecordIdText), LocalFieldRef.Caption, LocalOldValueText, LocalNewValueText),
                    'SIM_DI Update Deviating Fields',
                    LocalRecordSIMDIInboundDocument."Entry No."
                );
            end;

            // Se souvenir de l'id d'enregistrement d'en-tête de document pour archiver le document plus tard
            GlobalCodeunitSIMDIProcessSessionSI.GetMatchedDocumentHeader(LocalMatchingSetupNameText, LocalDocumentHeaderRecordId);
        end;

        // Définir l'id d'enregistrement d'en-tête de document correspondant dans la session
        GlobalCodeunitSIMDIProcessSessionSI.SetProcessedHeaderRecordId(LocalDocumentHeaderRecordId);
        Commit();
    end;
}

Cet exemple illustre le “traitement des déviations piloté par la session” : la session fournit un ensemble de données de déviation structurées ; votre code applique les déviations acceptées, enregistre ce qui a changé et rapporte l'en-tête traité dans la session.


5. Points de Personnalisation Supplémentaires

Il existe d'autres endroits où des codeunits personnalisés peuvent être intégrés, mais le principe directeur reste constant : utilisez la session pour récupérer le contexte de traitement actif et pour écrire les résultats pertinents au flux de travail. Cela maintient vos extensions cohérentes avec le flux de Smart Processing et empêche l'écart entre l'interface utilisateur et le processus.