Table of Contents

File Transfer Sample

This is the overview of the sample implementation of a File Transfer Communication Method.

Objects

The following table includes links to each of the objects that are being created in this sample

Object Type Object Name See
Codeunit My IQCM Sample File Handler link
Table My IQCM Sample File link
Page My IQCM Sample File Card link
Table My IQCM Sample File Snapsh. link
Page My IQCM Sam. Fl Snapsh. Crd link
Enum Extension My Sample File Transfer link

Codeunit My IQCM Sample File Handler

/// <summary>
/// This is a sample implementation of a "IQ Communication Method".
///
/// All Communication Methods must implement the IQCM Interface and at least one of "IQCM Import", "IQCM Export" and "IQCM Function".
///
/// This sample implements the Import and Export interfaces, but depending on type of communication only one interface may be implemented.
/// </summary>
codeunit 50020 "My IQCM Sample File Handler" implements "QWESR IQCM", "QWESR IQCM Import", "QWESR IQCM Export"
{
    Access = Public;

    // ***********************************************************************************************************************************************
    //
    //     All code in between "CUSTOMIZATION begin" and "CUSTOMIZATION end" must be updated to your specific needs
    //
    // ***********************************************************************************************************************************************

    // "IQCM" Interface implementation (documented in the Interface object):
    procedure SetCommunicationMethodCode(IQCommunicationMethodCode: Code[20]) rHandled: Boolean
    begin
        // CUSTOMIZATION begin
        if not IQCMSampleFile.Get(IQCommunicationMethodCode) then begin
            IQCMSampleFile.Init();
            IQCMSampleFile.Code := IQCommunicationMethodCode;
            IQCMSampleFile.Insert(true);
        end;
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure OpenCommunicationMethodCardPage() rHandled: Boolean
    begin
        AssertInit();
        // CUSTOMIZATION begin
        IQCMSampleFile.FilterGroup := 2;
        IQCMSampleFile.SetRecFilter();
        IQCMSampleFile.FilterGroup := 0;
        Page.Run(Page::"My IQCM Sample File Card", IQCMSampleFile); // Change to the Setup Card for this Communication Method
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure ClearCommunicationMethod() rHandled: Boolean
    begin
        AssertInit();
        // CUSTOMIZATION begin
        IQCMSampleFile.Delete();
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure GetCommunicationMethodSnapshot(var Snapshot: RecordRef) rHandled: Boolean
    // CUSTOMIZATION begin
    var
        IQCMSampleFileSnapshot: Record "My IQCM Sample File Snapsh."; // Change to this implementation's Snapshot record
    begin
        // This is a working sample implementation of how Communication Method Snapshot can be handled.
        // "The trick" is to use the "Record Time Stamp" of this Communication Method record as primary key in the snapshot table,
        // in this way we will create a new snapshot record every time a Release Wave of the Communication Method record is being used
        if not IQCMSampleFileSnapshot.Get(IQCMSampleFile."Record Time Stamp") then begin
            IQCMSampleFileSnapshot.Init();
            IQCMSampleFile.CalcFields(Description);
            IQCMSampleFileSnapshot.TransferFields(IQCMSampleFile);
            IQCMSampleFileSnapshot.Description := IQCMSampleFile.Description; // TransferFields not working with FlowField, must be done manually
            IQCMSampleFileSnapshot.Insert();
        end;
        Snapshot.GetTable(IQCMSampleFileSnapshot);
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure OpenCommunicationMethodSnapshotCard(var Snapshot: RecordRef) rHandled: Boolean
    var
        // CUSTOMIZATION begin
        IQCMSampleFileSnapshot: Record "My IQCM Sample File Snapsh."; // Change to this implementation's Snapshot record
    begin
        Snapshot.SetTable(IQCMSampleFileSnapshot);
        Page.Run(Page::"My IQCM Sam. Fl Snapsh. Crd", IQCMSampleFileSnapshot); // Change to this implementation's Snapshot Card
        exit(true);
        // CUSTOMIZATION end
    end;



    // "IQCM Import" Interface implementation (documented in the Interface object):
    procedure ImportIsSupported(): Boolean
    begin
        // CUSTOMIZATION begin
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure CheckImportSettings() rHandled: Boolean
    begin
        // CUSTOMIZATION begin
        CheckSettings(); // Change to whatever setting checks that needs to be done for import
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure GetImportRecords(var tIntegrationImport: Record "QWESR tIntegrationImport" temporary) rHandled: Boolean
    begin
        if not tIntegrationImport.IsTemporary() then
            Error('Parameter tIntegrationImport must be called with a temporary variable, this is a programming error');
        AssertInit();
        // CUSTOMIZATION begin
        GetDirectoryListing(IQCMSampleFile.Path, tIntegrationImport); // Fill the tIntegrationImport record with any data that are available for import, according to the settings in this Communication Method
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure Import(var IQI: Record "QWESR Integration Queue Import") rHandled: Boolean
    var
        tTempBlob: Record "QWETB tTempBlob" temporary;
    begin
        AssertInit();
        // CUSTOMIZATION begin
        // Change this implementation::
        IQI.TestField("Import Path"); // This should have been set by the GetImportRecords() function
        GetFile(IQI."Import Path", tTempBlob);
        IQI.Data := tTempBlob.Blob;
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure Delete(var IQI: Record "QWESR Integration Queue Import") rHandled: Boolean
    var
    begin
        AssertInit();
        // CUSTOMIZATION begin
        IQI.TestField("Import Path"); // This should have been set by the GetImportRecords() function
        // A sample implementation could do something as the following
        // if FileExists(IQI."Import Path") then
        //     DeleteFile(IQI."Import Path");
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure ShowImportRecord(var tIntegrationImport: Record "QWESR tIntegrationImport" temporary) rHandled: Boolean
    var
    begin
        AssertInit();
        // CUSTOMIZATION begin
        tIntegrationImport.TestField("Is a file", true);
        ShowFile(tIntegrationImport);
        exit(true);
        // CUSTOMIZATION end
    end;



    // "IQCM Export" Interface implementation (documented in the Interface object):
    procedure ExportIsSupported(): Boolean
    begin
        // CUSTOMIZATION begin
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure CheckExportSettings() rHandled: Boolean
    begin
        // CUSTOMIZATION begin
        CheckSettings(); // Change to whatever setting checks that needs to be done for export
        exit(true);
        // CUSTOMIZATION end
    end;

    procedure Export(var pvIQ: Record "QWESR Integration Queue") rHandled: Boolean
    var
        tFileTempBlob: Record "QWETB tTempBlob" temporary;
    begin
        // CUSTOMIZATION begin
        tFileTempBlob.Blob := pvIQ.Data;
        // A sample implementation could do something as the following
        // UploadFile(tFileTempBlob, pvIQ.Name);
        exit(true);
        // CUSTOMIZATION end
    end;



    // Local support functions:
    /// <summary>
    /// This function makes sure that the SetCommunicationMethodCode() function has been called before doing any other calls that depends on this.
    /// </summary>
    local procedure AssertInit()
    var
        // CUSTOMIZATION begin
        NotInitiatedErr: Label 'Sample File Handler is not initiated, SetCommunicationMethodCode must be called first. This is a programming error', Locked = true;  // Update this text
    // CUSTOMIZATION end
    begin
        if IQCMSampleFile.Code = '' then
            Error(NotInitiatedErr);
    end;

    // CUSTOMIZATION begin
    local procedure ShowFile(tIntegrationImport: Record "QWESR tIntegrationImport" temporary)
    var
        tTempBlob: Record "QWETB tTempBlob" temporary;
        TempBlob: Codeunit "Temp Blob";
        FileManagement: Codeunit "File Management";
    begin
        // This is a sample implementation on how to show a file, by downloading it to the client
        GetFile(DelChr(tIntegrationImport.Path, '>', '/') + '/' + tIntegrationImport.Name, tTempBlob);
        tTempBlob.GetAsTempBlob(TempBlob);
        FileManagement.BLOBExport(TempBlob, tIntegrationImport.Name, true);
    end;

    local procedure GetDirectoryListing(RemotePath: Text[2048]; var tIntegrationImport: Record "QWESR tIntegrationImport" temporary)
    var
        i: Integer;
        FileNameLbl: Label 'File0%1.txt', Comment = '%1 = File Number', Locked = true;
    begin
        // This is a "dummy implementation".
        // This should be changed to list files/data in some remote service and populate the tIntegrationImport record
        for i := 1 to 5 do begin
            tIntegrationImport.Init();
            tIntegrationImport."Communication Method" := IQCMSampleFile.Code;
            tIntegrationImport.Path := RemotePath;
            tIntegrationImport."Is a file" := true;
            tIntegrationImport.Name := CopyStr(CopyStr(FileNameLbl, i), 1, MaxStrLen(tIntegrationImport.Name));
            tIntegrationImport."Full Path" := CopyStr(DelChr(tIntegrationImport.Path, '>', '/') + '/' + tIntegrationImport.Name, 1, MaxStrLen(tIntegrationImport."Full Path"));
            tIntegrationImport.Size := i * 99;
            tIntegrationImport.Created := CurrentDateTime - i * 1000000;
            tIntegrationImport.Date := DT2Date(tIntegrationImport.Created);
            tIntegrationImport.Time := DT2Time(tIntegrationImport.Created);
            tIntegrationImport.Insert();
        end;
    end;

    local procedure GetFile(Path: Text; var tTempBlob: Record "QWETB tTempBlob" temporary)
    var
        FileContentLbl: Label 'This is the file content of file "%1"', Comment = '%1 = File Path', Locked = true;
    begin
        // This is a "dummy implementation".
        // This should be changed to get file/data from some remote service and set the data to a tTempBlob record
        tTempBlob.ImportFromText(StrSubstNo(FileContentLbl, Path));
    end;


    local procedure CheckSettings()
    begin
        AssertInit();
        // This is a sample implementation
        // There could be different checks for Import and Export
        IQCMSampleFile.TestField(Path);
    end;

    var
        IQCMSampleFile: Record "My IQCM Sample File"; // Change this to this Communication Method Setup table and rename the variable to change all references in this object

    // CUSTOMIZATION end

}

Enum Extension My Sample File Transfer

An Enum Extension is created to make the new Communication Method a selectable in the UI.

The codeunit "IQCM Sample File Handler" implements the interfaces "QWESR IQCM", "QWESR IQCM Import" and "QWESR IQCM Export", the enum value Implementation property should reflect that.

enumextension 50020 "My IQCM Sample" extends "QWESR IQCM"
{
    value(50020; "My Sample File Transfer")
    {
        Caption = 'My Sample File Transfer';
        Implementation = "QWESR IQCM" = "My IQCM Sample File Handler",
                         "QWESR IQCM Import" = "My IQCM Sample File Handler";
                         "QWESR IQCM Export" = "My IQCM Sample File Handler";
    }
}

Table My IQCM Sample File

/// <summary>
/// This is the Setup Table for a sample implementation of a "IQ Communication Method".
/// </summary>
table 50020 "My IQCM Sample File"
{
    // ***********************************************************************************************************************************************
    //
    //     All code in between "CUSTOMIZATION begin" and "CUSTOMIZATION end" must be updated to your specific needs
    //
    // ***********************************************************************************************************************************************

    // CUSTOMIZATION begin
    Caption = 'Sample File Communication Method';
    // CUSTOMIZATION end

    fields
    {
        field(1; "Code"; Code[20])
        {
            DataClassification = CustomerContent;
            Caption = 'Code';
            NotBlank = true;
            TableRelation = "QWESR IQ Communication Method";
        }
        field(9; "Record Time Stamp"; BigInteger)
        {
            DataClassification = CustomerContent;
            Caption = 'Record Time Stamp';
            SqlTimestamp = true; // This is used to know if a new Snapshot records should be created or not
        }
        field(10; Description; Text[50])
        {
            Caption = 'Description';
            FieldClass = FlowField;
            CalcFormula = lookup("QWESR IQ Communication Method".Description where(Code = field(Code)));
            Editable = false;
        }
        // CUSTOMIZATION begin
        field(12; Path; Text[1024])
        {
            DataClassification = CustomerContent;
            Caption = 'Path';
        }
        // CUSTOMIZATION end
    }
    keys
    {
        key(Key1; "Code")
        {
        }
    }

    // CUSTOMIZATION begin
    internal procedure ShowFiles()
    var
        IQCommunicationMethod: Record "QWESR IQ Communication Method";
        CommunicationMethodMgt: Codeunit "QWESR Communication Method Mgt";
    begin
        IQCommunicationMethod.Get(Code);
        CommunicationMethodMgt.ShowImportRecords(IQCommunicationMethod);
    end;
    // CUSTOMIZATION end

}

Page My IQCM Sample File Card

/// <summary>
/// This is the Setup Page for a sample implementation of a "IQ Communication Method".
/// </summary>
page 50020 "My IQCM Sample File Card"
{
    // ***********************************************************************************************************************************************
    //
    //     All code in between "CUSTOMIZATION begin" and "CUSTOMIZATION end" must be updated to your specific needs
    //
    // ***********************************************************************************************************************************************

    // CUSTOMIZATION begin
    Caption = 'Sample File Communication Method Card';
    // CUSTOMIZATION end
    PageType = Card;
    DeleteAllowed = false;
    InsertAllowed = false;
    LinksAllowed = false;
    // CUSTOMIZATION begin
    SourceTable = "My IQCM Sample File";
    // CUSTOMIZATION end
    UsageCategory = None;

    layout
    {
        area(content)
        {
            group(Sample)
            {
                // CUSTOMIZATION begin
                Caption = 'Sample File';
                // CUSTOMIZATION end
                field("Code"; Rec.Code)
                {
                    ApplicationArea = All;
                    Editable = false;
                    ToolTip = 'Specifies the code.';
                }
                field(Description; Rec.Description)
                {
                    ApplicationArea = All;
                    DrillDown = false;
                    ToolTip = 'Specifies the description.';
                }
                // CUSTOMIZATION begin
                field(Path; Rec.Path)
                {
                    ApplicationArea = All;
                    ShowMandatory = true;
                    ToolTip = 'Specifies the path.';
                }
                // CUSTOMIZATION end
            }
        }
    }
    // CUSTOMIZATION begin

    actions
    {
        area(processing)
        {
            action("Show files")
            {
                // This function could be used if you want the user to be able to list files according to the current settings.
                // The retrieval of the files listed should use the same function as implemented by the Import interface
                Caption = 'Show files';
                Image = List;
                Promoted = true;
                PromotedCategory = Process;
                PromotedIsBig = true;
                PromotedOnly = true;
                ApplicationArea = All;
                ToolTip = 'Open a list with files according to the current settings. This action will show the files that will be imported when this Communication Method is used to import into the Integration Queue.';

                trigger OnAction();
                begin
                    Rec.ShowFiles();
                end;
            }
        }
    }
    // CUSTOMIZATION end
}

Table My IQCM Sample File Snapsh

/// <summary>
/// This is the Setup Snapshot Table for a sample implementation of a "IQ Communication Method".
///
/// This is populated by a TransferFields from from the Setup Table (below referred to as "Base Setup Table") of this Communication Method, so the fields should match between the two tables.
///
/// This table is created by:
///
///  - Copy the "Base Setup Table", rename and renumber
///  - Rename field 9 from "Record Time Stamp" to "Snapshot Id"
///  - Remove SqlTimestamp = true; from field 9
///  - Change field 10, Description from FlowField to a normal field and set DataClassification = CustomerContent. Do the same for other FlowFields, if any.
///  - Change Primary Key to field 9, "Snapshot Id"
///  - Add a secondary key for Code
///  - Remove any code
/// </summary>
table 50021 "Sample File Snapsh."
{

    // ***********************************************************************************************************************************************
    //
    //     All code in between "CUSTOMIZATION begin" and "CUSTOMIZATION end" must be updated to your specific needs
    //
    // ***********************************************************************************************************************************************

    // CUSTOMIZATION begin
    Caption = 'Sample File Communication Method Snapshot';
    // CUSTOMIZATION end

    fields
    {
        field(1; "Code"; Code[20])
        {
            DataClassification = CustomerContent;
            Caption = 'Code';
            NotBlank = true;
            TableRelation = "QWESR IQ Communication Method";
        }
        field(9; "Snapshot Id"; BigInteger)
        {
            DataClassification = CustomerContent;
            Caption = 'Snapshot Id';
        }
        field(10; Description; Text[50])
        {
            DataClassification = CustomerContent;
            Caption = 'Description';
        }
        // CUSTOMIZATION begin
        field(12; Path; Text[1024])
        {
            DataClassification = CustomerContent;
            Caption = 'Path';
        }
        // CUSTOMIZATION end
    }

    keys
    {
        key(Key1; "Snapshot Id")
        {
        }
        key(Key2; "Code")
        {

        }
    }
}

Page My IQCM Sam. Fl Snapsh. Crd

/// <summary>
/// This is the Setup Snapshot Page for a sample implementation of a "IQ Communication Method".
///
/// This page is created by:
///
///  - Copy the "Base Setup page", rename and renumber
///  - Change SourceTable to the snapshot table
///  - Change to Editable = false
///  - Remove any DeleteAllowed/InsertAllowed properties
///  - Add the GetDataCaptionExpression() function
///  - Set DataCaptionExpression = GetDataCaptionExpression()
///  - Add the "Snapshot Id" page field
///  - Remove any Editable, ShowMandatory or DrillDown properties on fields
///  - Remove any other code
/// </summary>
page 50021 "My IQCM Sam. Fl Snapsh. Crd"
{
    // ***********************************************************************************************************************************************
    //
    //     All code in between "CUSTOMIZATION begin" and "CUSTOMIZATION end" must be updated to your specific needs
    //
    // ***********************************************************************************************************************************************

    // CUSTOMIZATION begin
    Caption = 'Sample File Communication Method Card';
    // CUSTOMIZATION end
    PageType = Card;
    LinksAllowed = false;
    // CUSTOMIZATION begin
    SourceTable = "My IQCM Sample File Snapsh.";
    // CUSTOMIZATION end
    UsageCategory = None;
    Editable = false;
    DataCaptionExpression = GetDataCaptionExpression();

    layout
    {
        area(content)
        {
            group(Sample)
            {
                // CUSTOMIZATION begin
                Caption = 'Sample File';
                // CUSTOMIZATION end
                field("Snapshot Id"; Rec."Snapshot Id")
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the unique snapshot ID. This is used to identify this version of the settings.';
                }
                field("Code"; Rec.Code)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the code.';
                }
                field(Description; Rec.Description)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the description.';
                }
                // CUSTOMIZATION begin
                field(Path; Rec.Path)
                {
                    ApplicationArea = All;
                    ToolTip = 'Specifies the path.';
                }
                // CUSTOMIZATION end
            }
        }
    }

    local procedure GetDataCaptionExpression(): Text
    var
        DataCaptionLbl: Label '%1, %2', Comment = '%1 = Code, %2 = Snapshot Id', Locked = true;
    begin
        // CUSTOMIZATION begin
        exit(StrSubstNo(DataCaptionLbl, Rec.Code, Rec."Snapshot Id"))
        // CUSTOMIZATION end
    end;
}

Extend Integration Queue