Aller au contenu

Téléchargement et Téléversement de Codeunit Personnalisé

Le système des Portails d'Affaires intégré avec Document Central peut être personnalisé selon le désir de l'utilisateur lorsqu'il y a un processus de téléversement ou de téléchargement utilisant la fonctionnalité Document Central.

Cette section fournit un exemple de la façon d'implémenter un codeunit personnalisé qui est utilisé lorsque l'utilisateur téléverse ou télécharge des documents via Document Central.

Exemple de Code

Dans cet exemple, nous utiliserons la table Temp dans un scénario où le téléversement de documents remplira le Type de Contenu pour filtrer le contenu par leur extension et il est également utilisé pour le téléchargement des fichiers.

AL
codeunit 5492859 "SIM_DPS Exemple de Téléversement CU"
{
    TableNo = "SIM_DPS Temp Table";

    /// <summary>
    /// Point d'entrée pour la procédure de téléversement personnalisée configurée dans la configuration SIM_DPS.
    /// Il garde l'exemple à l'intérieur de l'application DPS et délègue le véritable téléversement aux applications connecteurs installées via les événements d'intégration DPS.
    /// </summary>
    /// <returns></returns>
    trigger OnRun()
    var
        LocalCodeunitTempBlob: Codeunit "Temp Blob";
        LocalSucceedBoolean: Boolean;
        LocalUploadEntryNoBigInteger: BigInteger;
        LocalErrorText: Text;
        LocalHasCachedUploadBlobBoolean: Boolean;
    begin
        // Commencer avec un résultat négatif afin que le connecteur doive explicitement marquer le téléversement comme traité.
        LocalSucceedBoolean := false;

        // Remplir Rec.ContentType lorsque DPS ne l'a pas passé, car le connecteur DMS utilise cette valeur comme catégorie/type de contenu de l'attachement.
        EnsureAttachmentCategoryName(Rec);

        // Garder une copie du fichier téléversé afin que la page de Téléversement SIM_DPS puisse toujours l'apercevoir après que le connecteur ait effacé FileData.
        LocalHasCachedUploadBlobBoolean := CacheUploadFileData(Rec, LocalCodeunitTempBlob, LocalUploadEntryNoBigInteger);

        // Effacer les erreurs d'exécution précédentes afin que GetLastErrorText() ne rapporte que les erreurs de l'appel d'événement du connecteur ci-dessous.
        ClearLastError();

        // Garder l'exemple dans DPS et laisser les applications connecteurs installées gérer la véritable cible d'archive.
        if not TryUploadThroughConnector(LocalSucceedBoolean, Rec, Rec."Table No." = Database::"SIM_DPS OL") then begin
            // TryFunction supprime l'erreur du connecteur ; la lire à nouveau et l'afficher comme un message pour un retour d'information plus clair sur la configuration du portail.
            LocalErrorText := GetLastErrorText();
            if LocalErrorText = '' then
                LocalErrorText := GlobalNoConnectorErrorLabelMsg;
            Message(GlobalUploadFailedWithReasonLabelMsg, LocalErrorText);
            exit;
        end;

        // Un appel d'événement réussi peut encore signifier qu'aucun connecteur n'a accepté le téléversement, donc le signaler séparément.
        if not LocalSucceedBoolean then
            Message(GlobalUploadFailedWithReasonLabelMsg, GlobalNoConnectorErrorLabelMsg);

        // Le connecteur archive le fichier puis efface SIM_DPS Upload.FileData ; le restaurer pour la visualisation de documentation/démonstration.
        if LocalSucceedBoolean and LocalHasCachedUploadBlobBoolean then
            RestoreUploadFileData(LocalUploadEntryNoBigInteger, LocalCodeunitTempBlob);
    end;

    /// <summary>
    /// Déclenche l'événement d'intégration de téléversement DPS auquel les applications connecteurs s'abonnent.
    /// La TryFunction convertit les erreurs du connecteur en un échec booléen afin que OnRun puisse afficher l'erreur avec Message() au lieu de Error() dur.
    /// </summary>
    /// <param name="ParamSucceedBoolean">Défini sur vrai par le connecteur lorsque le téléversement a été traité avec succès.</param>
    /// <param name="TempParamRecordSIMDPSTempTable">Enregistrement de contexte DPS temporaire contenant des informations sur la table, l'enregistrement, l'entreprise et le type de contenu.</param>
    /// <param name="ParamOrderUploadBoolean">Vrai lorsque le téléversement appartient à un flux de commande SIM_DPS OL ; faux pour les téléversements normaux/manuels.</param>
    /// <returns></returns>
    [TryFunction]
    local procedure TryUploadThroughConnector(var ParamSucceedBoolean: Boolean; var TempParamRecordSIMDPSTempTable: Record "SIM_DPS Temp Table" temporary; ParamOrderUploadBoolean: Boolean)
    begin
        // Les téléversements de commande ont besoin de l'événement spécifique à la commande car la logique de téléversement du connecteur résout le document cible créé à partir de SIM_DPS OL.
        if ParamOrderUploadBoolean then
            GlobalCodeunitSIMDPSEventPublisher.OnCheckUploadsOrder(ParamSucceedBoolean, TempParamRecordSIMDPSTempTable)
        else
            // Les téléversements normaux/manuels utilisent l'événement de téléversement standard et identifient le téléversement en attente par le Numéro d'Entrée.
            GlobalCodeunitSIMDPSEventPublisher.OnCheckUploads(ParamSucceedBoolean, TempParamRecordSIMDPSTempTable);
    end;

    /// <summary>
    /// S'assure que le contexte temporaire DPS contient le nom de la catégorie/type de contenu de l'attachement.
    /// Le connecteur DMS vers DPS lit Rec.ContentType lors de la création de l'entrée Document Central, mais les téléversements de commande peuvent arriver sans cette valeur définie.
    /// </summary>
    /// <param name="TempParamRecordSIMDPSTempTable">Enregistrement de contexte DPS temporaire passé au codeunit de téléversement personnalisé configuré.</param>
    /// <returns></returns>
    local procedure EnsureAttachmentCategoryName(var TempParamRecordSIMDPSTempTable: Record "SIM_DPS Temp Table" temporary)
    var
        LocalRecordSIMDPSUpload: Record "SIM_DPS Upload";
    begin
        // Si DPS a déjà fourni la catégorie/type de contenu, la garder inchangée.
        if TempParamRecordSIMDPSTempTable.ContentType <> '' then
            exit;

        LocalRecordSIMDPSUpload.Reset();

        // Les téléversements manuels passent le numéro d'entrée dans No. BigInt, qui est la recherche la plus précise.
        if TempParamRecordSIMDPSTempTable."No. BigInt" <> 0 then
            LocalRecordSIMDPSUpload.SetRange("Entry No.", TempParamRecordSIMDPSTempTable."No. BigInt")
        else
            // Les téléversements de commande ne passent pas de numéro d'entrée ; ils sont liés à l'enregistrement SIM_DPS Upload par l'ID d'Enregistrement.
            LocalRecordSIMDPSUpload.SetRange("Record ID", TempParamRecordSIMDPSTempTable.RecID);

        // Restreindre à l'entreprise actuelle et aux fichiers téléchargés en attente afin que les lignes complètes/annulées ne puissent pas fournir une catégorie obsolète.
        LocalRecordSIMDPSUpload.SetRange(Company, TempParamRecordSIMDPSTempTable.Company);
        LocalRecordSIMDPSUpload.SetRange(Status, LocalRecordSIMDPSUpload.Status::Uploaded);

        // Copier le type de contenu du téléversement dans l'enregistrement temporaire ; les applications connecteurs le reçoivent ensuite via le paramètre d'événement.
        if LocalRecordSIMDPSUpload.FindFirst() then
            TempParamRecordSIMDPSTempTable.ContentType := CopyStr(LocalRecordSIMDPSUpload."Content Type", 1, MaxStrLen(TempParamRecordSIMDPSTempTable.ContentType));
    end;

    /// <summary>
    /// Copie le SIM_DPS Upload.FileData original dans un Temp Blob avant que le connecteur ne traite le téléversement.
    /// La copie n'est nécessaire que pour les entrées de liste de téléversement normales, car l'action de Visualiser lit le fichier à partir de SIM_DPS Upload.FileData.
    /// </summary>
    /// <param name="TempParamRecordSIMDPSTempTable">Enregistrement de contexte DPS temporaire passé au codeunit de téléversement personnalisé configuré.</param>
    /// <param name="ParamCodeunitTempBlob">Temp Blob qui reçoit une copie du contenu du fichier téléversé.</param>
    /// <param name="ParamUploadEntryNoBigInteger">Numéro d'Entrée de la ligne SIM_DPS Upload qui doit être restaurée plus tard.</param>
    /// <returns>Vrai lorsqu'un blob de fichier a été trouvé et mis en cache ; sinon faux.</returns>
    local procedure CacheUploadFileData(TempParamRecordSIMDPSTempTable: Record "SIM_DPS Temp Table" temporary; var ParamCodeunitTempBlob: Codeunit "Temp Blob"; var ParamUploadEntryNoBigInteger: BigInteger): Boolean
    var
        LocalRecordSIMDPSUpload: Record "SIM_DPS Upload";
    begin
        // Seuls les téléversements normaux passent un Numéro d'Entrée ; les téléversements de commande peuvent contenir plusieurs fichiers liés et ne sont pas affichés sur la page 5163558.
        if TempParamRecordSIMDPSTempTable."No. BigInt" = 0 then
            exit(false);

        if not LocalRecordSIMDPSUpload.Get(TempParamRecordSIMDPSTempTable."No. BigInt") then
            exit(false);

        if not LocalRecordSIMDPSUpload.FileData.HasValue() then
            exit(false);

        // Copier le BLOB avant que le connecteur ne l'efface lors du traitement réussi du téléversement.
        LocalRecordSIMDPSUpload.CalcFields(FileData);
        Clear(ParamCodeunitTempBlob);
        ParamCodeunitTempBlob.FromRecord(LocalRecordSIMDPSUpload, LocalRecordSIMDPSUpload.FieldNo(FileData));
        ParamUploadEntryNoBigInteger := LocalRecordSIMDPSUpload."Entry No.";
        exit(true);
    end;

    /// <summary>
    /// Restaure SIM_DPS Upload.FileData après un téléversement réussi du connecteur.
    /// Cela garde l'action de Visualiser de la page de Téléversement utilisable tout en permettant au connecteur de terminer son processus d'archive.
    /// </summary>
    /// <param name="ParamUploadEntryNoBigInteger">Numéro d'Entrée de la ligne SIM_DPS Upload à restaurer.</param>
    /// <param name="ParamCodeunitTempBlob">Temp Blob contenant le contenu original du fichier téléversé mis en cache.</param>
    local procedure RestoreUploadFileData(ParamUploadEntryNoBigInteger: BigInteger; var ParamCodeunitTempBlob: Codeunit "Temp Blob")
    var
        LocalRecordSIMDPSUpload: Record "SIM_DPS Upload";
        LocalInStream: InStream;
        LocalOutStream: OutStream;
    begin
        if not LocalRecordSIMDPSUpload.Get(ParamUploadEntryNoBigInteger) then
            exit;

        // Ne pas écraser le contenu si un autre gestionnaire a déjà conservé ou restauré le fichier.
        if LocalRecordSIMDPSUpload.FileData.HasValue() then
            exit;

        ParamCodeunitTempBlob.CreateInStream(LocalInStream);
        LocalRecordSIMDPSUpload.FileData.CreateOutStream(LocalOutStream);
        CopyStream(LocalOutStream, LocalInStream);
        LocalRecordSIMDPSUpload.Modify();
    end;

    var
        GlobalCodeunitSIMDPSEventPublisher: Codeunit "SIM_DPS Event Publisher";
        GlobalNoConnectorErrorLabelMsg: Label 'Aucun connecteur n'a traité le téléversement. Veuillez vérifier que le connecteur est installé, publié et configuré.';
        GlobalUploadFailedWithReasonLabelMsg: Label 'Le téléversement n'a pas pu être traité. Raison : %1', Comment = '%1 = Raison de l\'erreur';
}
AL
codeunit 5492860 "SIM_DPS Exemple de Téléchargement CU"
{
    TableNo = "SIM_DPS Temp Table";

    /// <summary>
    /// Point d'entrée pour la procédure de téléchargement personnalisée configurée dans la configuration SIM_DPS.
    /// Il délègue la liste des fichiers et le téléchargement de fichiers aux applications connecteurs installées via les événements d'intégration DPS.
    /// </summary>
    /// <returns></returns>
    trigger OnRun()
    begin
        case UpperCase(Rec.Param) of
            // Premier appel du portail : le connecteur écrit le fichier XML de la liste dans Blob.
            'GETFILES':
                GlobalCodeunitSIMDPSEventPublisher.OnDeserializeDownloadGetFile(Rec);

            // Deuxième appel du portail : le connecteur écrit le contenu du fichier sélectionné dans le Blob de Fichier.
            'DOWNLOADFILE':
                begin
                    FetchDocumentAttachment(Rec);

                    EnsureDownloadedFileWasReturned(Rec);
                end;
            else
                // Les actions inconnues ne sont pas envoyées au code du connecteur car le connecteur ne gère que les deux actions de téléchargement du portail ci-dessus.
                Message(GlobalUnknownDownloadActionLabelMsg, Rec.Param);
        end;
    end;

    /// <summary>
    /// Récupère le fichier demandé directement à partir de la table des Attachements de Document de Business Central.
    /// </summary>
    /// <returns></returns>
    local procedure FetchDocumentAttachment(var TempParamRecordSIMDPSTempTable: Record "SIM_DPS Temp Table" temporary)
    var
        LocalRecordDocumentAttachment: Record "Document Attachment";
        LocalRecordTenantMedia: Record "Tenant Media";
        LocalCodeunitDocumentAttachmentMgmt: Codeunit "Document Attachment Mgmt";
        LocalRecordRef: RecordRef;
        LocalBaseFileNameText: Text;
        LocalFileExtText: Text;
        LocalInStream: InStream;
        LocalOutStream: OutStream;
    begin
        // Ouvrir l'enregistrement commercial cible basé sur l'ID d'Enregistrement entrant
        if not LocalRecordRef.Get(TempParamRecordSIMDPSTempTable.RecID) then
            exit;

        // Filtrer la table des Attachements de Document pour cet enregistrement spécifique
        LocalCodeunitDocumentAttachmentMgmt.SetDocumentAttachmentFiltersForRecRef(LocalRecordDocumentAttachment, LocalRecordRef);

        // Diviser le nom de fichier demandé en Nom de Base et Extension pour correspondre à la structure de table de BC
        SplitFilename(TempParamRecordSIMDPSTempTable.Filename, LocalBaseFileNameText, LocalFileExtText);

        LocalRecordDocumentAttachment.SetRange("File Name", CopyStr(LocalBaseFileNameText, 1, MaxStrLen(LocalRecordDocumentAttachment."File Name")));
        if LocalFileExtText <> '' then
            LocalRecordDocumentAttachment.SetRange("File Extension", CopyStr(LocalFileExtText, 1, MaxStrLen(LocalRecordDocumentAttachment."File Extension")));

        // Si le fichier est trouvé, streamer le contenu Media dans le Blob de Fichier de la Table Temp
        if LocalRecordDocumentAttachment.FindFirst() then
            if LocalRecordDocumentAttachment."Document Reference ID".HasValue then
                if LocalRecordTenantMedia.Get(LocalRecordDocumentAttachment."Document Reference ID".MediaId) then begin
                    LocalRecordTenantMedia.CalcFields(Content);
                    LocalRecordTenantMedia.Content.CreateInStream(LocalInStream);

                    TempParamRecordSIMDPSTempTable."File Blob".CreateOutStream(LocalOutStream);
                    CopyStream(LocalOutStream, LocalInStream);
                end;
    end;

    /// <summary>
    /// Divise un nom de fichier complet en nom de base et extension pour le filtrage des Attachements de Document.
    /// </summary>
    /// <returns></returns>
    local procedure SplitFilename(ParamFilenameText: Text; var ParamBaseFilenameText: Text; var ParamExtensionText: Text)
    var
        LocalInteger: Integer;
    begin
        ParamBaseFilenameText := ParamFilenameText;
        ParamExtensionText := '';

        for LocalInteger := StrLen(ParamFilenameText) downto 1 do
            if ParamFilenameText[LocalInteger] = '.' then begin
                ParamBaseFilenameText := CopyStr(ParamFilenameText, 1, LocalInteger - 1);
                ParamExtensionText := CopyStr(ParamFilenameText, LocalInteger + 1);
                exit;
            end;
    end;

    local procedure EnsureDownloadedFileWasReturned(var TempParamRecordSIMDPSTempTable: Record "SIM_DPS Temp Table" temporary)
    begin
        if TempParamRecordSIMDPSTempTable."File Blob".HasValue() then
            exit;

        Error(GlobalEmptyDownloadFileLabelErr, TempParamRecordSIMDPSTempTable.Filename);
    end;

    var
        GlobalCodeunitSIMDPSEventPublisher: Codeunit "SIM_DPS Event Publisher";
        GlobalEmptyDownloadFileLabelErr: Label 'Le téléchargement n\'a pas renvoyé de contenu de fichier pour %1. Veuillez vérifier l\'entrée de document DMS et la configuration du connecteur.', Comment = '%1 = Nom de fichier';
        GlobalUnknownDownloadActionLabelMsg: Label 'Action de téléchargement inconnue %1.', Comment = '%1 = Action de téléchargement';
}