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;
}