From dfd4c0bf1bd831416cf2c3429124d90d153c49b1 Mon Sep 17 00:00:00 2001 From: Volodymyr Date: Fri, 3 Jul 2026 14:44:57 +0200 Subject: [PATCH 1/2] Data Exchange Definition export performance improvement --- .../Bank/Payment/PaymentExportMgt.Codeunit.al | 101 ++++++++++++++++++ .../DataExchange/ExportMapping.Codeunit.al | 44 +++++++- 2 files changed, 141 insertions(+), 4 deletions(-) diff --git a/src/Layers/W1/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al b/src/Layers/W1/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al index 7829065803..53e651d929 100644 --- a/src/Layers/W1/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al +++ b/src/Layers/W1/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al @@ -249,6 +249,107 @@ codeunit 1210 "Payment Export Mgt" end; end; + /// + /// Processes column mapping for payment export data exchange. + /// + /// Data exchange record + /// Record reference containing source data + /// FlowField grouping buffer for aggregated fields + /// Line number in the data exchange + /// Data exchange line definition code + /// Table ID of the source record + /// Temporary record for data exchange fields + procedure ProcessColumnMapping(var DataExch: Record "Data Exch."; RecRef: RecordRef; var DataExchFlowFieldGrBuff: Record "Data Exch. FlowField Gr. Buff."; LineNo: Integer; DataExchLineDefCode: Code[20]; TableID: Integer; var TempDataExchField: Record "Data Exch. Field" temporary) + var + DataExchDef: Record "Data Exch. Def"; + DataExchColumnDef: Record "Data Exch. Column Def"; + DataExchFieldMapping: Record "Data Exch. Field Mapping"; + TransformationRule: Record "Transformation Rule"; + StringConversionManagement: Codeunit StringConversionManagement; + FieldRef: FieldRef; + ValueAsDestType: Variant; + ValueAsString: Text[250]; + begin + if not DataExchDef.Get(DataExch."Data Exch. Def Code") then + Error(FormatNotDefinedErr, DataExch."Data Exch. Def Code"); + + PrepopulateColumns(DataExchDef, DataExchLineDefCode, DataExch."Entry No.", LineNo, TempDataExchField); + + DataExchFieldMapping.SetRange("Data Exch. Def Code", DataExchDef.Code); + DataExchFieldMapping.SetRange("Data Exch. Line Def Code", DataExchLineDefCode); + DataExchFieldMapping.SetRange("Table ID", TableID); + DataExchFieldMapping.FindSet(); + + repeat + DataExchColumnDef.Get(DataExchDef.Code, DataExchLineDefCode, DataExchFieldMapping."Column No."); + + if DataExchFieldMapping."Use Default Value" then + ValueAsString := DataExchFieldMapping."Default Value" + else begin + FieldRef := RecRef.Field(DataExchFieldMapping."Field ID"); + if FieldRef.Class = FieldRef.Class::FlowField then + if DataExchFlowFieldGrBuff.Get(RecRef.RecordId, FieldRef.Number) then + FieldRef.Value := DataExchFlowFieldGrBuff.Value + else + FieldRef.CalcField(); + + CheckOptional(DataExchFieldMapping.Optional, FieldRef); + CastToDestinationType(ValueAsDestType, FieldRef.Value, DataExchColumnDef, DataExchFieldMapping.Multiplier); + ValueAsString := FormatToText(ValueAsDestType, DataExchDef, DataExchColumnDef); + + if TransformationRule.Get(DataExchFieldMapping."Transformation Rule") then + ValueAsString := CopyStr(TransformationRule.TransformText(ValueAsString), 1, 250); + + if DataExchColumnDef."Text Padding Required" and (DataExchColumnDef."Pad Character" <> '') and (not DataExchColumnDef."Blank Zero") then + ValueAsString := + StringConversionManagement.GetPaddedString( + ValueAsString, + DataExchColumnDef.Length, + DataExchColumnDef."Pad Character", + DataExchColumnDef.Justification); + end; + + OnProcessColumnMappingOnBeforeCheckLength(ValueAsString, DataExchFieldMapping, DataExchColumnDef); + CheckLength(ValueAsString, RecRef.Field(DataExchFieldMapping."Field ID"), DataExchDef, DataExchColumnDef); + + TempDataExchField.Get(DataExch."Entry No.", LineNo, DataExchFieldMapping."Column No."); + TempDataExchField.SetValueWithoutModifying(ValueAsString); + TempDataExchField.Modify(); + until DataExchFieldMapping.Next() = 0; + end; + + local procedure PrepopulateColumns(DataExchDef: Record "Data Exch. Def"; DataExchLineDefCode: Code[20]; DataExchEntryNo: Integer; DataExchLineNo: Integer; var TempDataExchField: Record "Data Exch. Field" temporary) + var + DataExchLineDef: Record "Data Exch. Line Def"; + DataExchColumnDef: Record "Data Exch. Column Def"; + ColumnIndex: Integer; + begin + if DataExchDef."File Type" in + [DataExchDef."File Type"::"Fixed Text", + DataExchDef."File Type"::Xml, + DataExchDef."File Type"::Json] + then begin + DataExchColumnDef.SetRange("Data Exch. Def Code", DataExchDef.Code); + DataExchColumnDef.SetRange("Data Exch. Line Def Code", DataExchLineDefCode); + if not DataExchColumnDef.FindSet() then + Error(DataExchLineDefNotFoundErr, DataExchDef.Name, DataExchLineDefCode); + repeat + TempDataExchField.InsertRec( + DataExchEntryNo, DataExchLineNo, DataExchColumnDef."Column No.", + PadStr(DataExchColumnDef.Constant, DataExchColumnDef.Length), DataExchLineDefCode) + until DataExchColumnDef.Next() = 0; + end else begin + if not DataExchLineDef.Get(DataExchDef.Code, DataExchLineDefCode) then + Error(DataExchLineDefNotFoundErr, DataExchDef.Name, DataExchLineDefCode); + for ColumnIndex := 1 to DataExchLineDef."Column Count" do + if DataExchColumnDef.Get(DataExchDef.Code, DataExchLineDef.Code, ColumnIndex) then + TempDataExchField.InsertRec( + DataExchEntryNo, DataExchLineNo, ColumnIndex, DataExchColumnDef.Constant, DataExchLineDefCode) + else + TempDataExchField.InsertRec(DataExchEntryNo, DataExchLineNo, ColumnIndex, '', DataExchLineDefCode); + end; + end; + local procedure CheckOptional(Optional: Boolean; FieldRef: FieldRef) var Value: Variant; diff --git a/src/Layers/W1/BaseApp/System/DataExchange/ExportMapping.Codeunit.al b/src/Layers/W1/BaseApp/System/DataExchange/ExportMapping.Codeunit.al index 7977e0e95b..b114f1c7d6 100644 --- a/src/Layers/W1/BaseApp/System/DataExchange/ExportMapping.Codeunit.al +++ b/src/Layers/W1/BaseApp/System/DataExchange/ExportMapping.Codeunit.al @@ -10,28 +10,64 @@ codeunit 1269 "Export Mapping" trigger OnRun() var + DataExchField: Record "Data Exch. Field"; DataExchMapping: Record "Data Exch. Mapping"; + TempDataExchField: Record "Data Exch. Field" temporary; TempDataExchFlowFieldGrBuff: Record "Data Exch. FlowField Gr. Buff." temporary; PaymentExportMgt: Codeunit "Payment Export Mgt"; SourceRecRef: RecordRef; Window: Dialog; LineNo: Integer; + RowCount: Integer; + Divider: Integer; begin FindMapping(DataExchMapping, Rec."Data Exch. Def Code", Rec."Data Exch. Line Def Code"); GetSourceRecRefBuffer(SourceRecRef, TempDataExchFlowFieldGrBuff, DataExchMapping, ReadTableFilters(Rec)); - Window.Open(ProgressMsg); + RowCount := SourceRecRef.Count(); + case true of + RowCount > 1000: + Divider := 200; + RowCount > 100: + Divider := 10; + else + Divider := 1; + end; + + Window.Open(MappingProgressMsg); repeat LineNo += 1; - Window.Update(1, LineNo); - PaymentExportMgt.ProcessColumnMapping(Rec, SourceRecRef, TempDataExchFlowFieldGrBuff, LineNo, Rec."Data Exch. Line Def Code", SourceRecRef.Number); + if LineNo mod Divider = 0 then + Window.Update(1, LineNo); + + PaymentExportMgt.ProcessColumnMapping(Rec, SourceRecRef, TempDataExchFlowFieldGrBuff, LineNo, Rec."Data Exch. Line Def Code", SourceRecRef.Number, TempDataExchField); until SourceRecRef.Next() = 0; + Window.Close(); + Window.Open(SavingProgressMsg); + TempDataExchField.Reset(); + if TempDataExchField.FindSet() then + repeat + if TempDataExchField."Line No." <> LineNo then begin + LineNo := TempDataExchField."Line No."; + if LineNo mod Divider = 0 then + Window.Update(1, LineNo); + end; + + DataExchField.Init(); + DataExchField.TransferFields(TempDataExchField); + if TempDataExchField."Value BLOB".HasValue() then begin + TempDataExchField.CalcFields("Value BLOB"); + DataExchField."Value BLOB" := TempDataExchField."Value BLOB"; + end; + DataExchField.Insert(); + until TempDataExchField.Next() = 0; Window.Close(); end; var #pragma warning disable AA0470 - ProgressMsg: Label 'Processing line no. #1######.'; + MappingProgressMsg: Label 'Mapping line no. #1######'; + SavingProgressMsg: Label 'Saving line no. #1######'; MappingNotFoundErr: Label 'No mapping was found for format definition %1 and line definition %2.'; RecordsNotFoundErr: Label 'No records were found for source table %1 using the filters: %2.'; #pragma warning restore AA0470 From 238ee27ed9756e832adb63ecdfc4b9c25add756c Mon Sep 17 00:00:00 2001 From: Volodymyr Date: Fri, 3 Jul 2026 15:17:45 +0200 Subject: [PATCH 2/2] Miapp --- .../Bank/Payment/PaymentExportMgt.Codeunit.al | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/Layers/RU/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al b/src/Layers/RU/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al index ce99de6179..3ae52c40a8 100644 --- a/src/Layers/RU/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al +++ b/src/Layers/RU/BaseApp/Bank/Payment/PaymentExportMgt.Codeunit.al @@ -260,6 +260,107 @@ codeunit 1210 "Payment Export Mgt" end; end; + /// + /// Processes column mapping for payment export data exchange. + /// + /// Data exchange record + /// Record reference containing source data + /// FlowField grouping buffer for aggregated fields + /// Line number in the data exchange + /// Data exchange line definition code + /// Table ID of the source record + /// Temporary record for data exchange fields + procedure ProcessColumnMapping(var DataExch: Record "Data Exch."; RecRef: RecordRef; var DataExchFlowFieldGrBuff: Record "Data Exch. FlowField Gr. Buff."; LineNo: Integer; DataExchLineDefCode: Code[20]; TableID: Integer; var TempDataExchField: Record "Data Exch. Field" temporary) + var + DataExchDef: Record "Data Exch. Def"; + DataExchColumnDef: Record "Data Exch. Column Def"; + DataExchFieldMapping: Record "Data Exch. Field Mapping"; + TransformationRule: Record "Transformation Rule"; + StringConversionManagement: Codeunit StringConversionManagement; + FieldRef: FieldRef; + ValueAsDestType: Variant; + ValueAsString: Text[250]; + begin + if not DataExchDef.Get(DataExch."Data Exch. Def Code") then + Error(FormatNotDefinedErr, DataExch."Data Exch. Def Code"); + + PrepopulateColumns(DataExchDef, DataExchLineDefCode, DataExch."Entry No.", LineNo, TempDataExchField); + + DataExchFieldMapping.SetRange("Data Exch. Def Code", DataExchDef.Code); + DataExchFieldMapping.SetRange("Data Exch. Line Def Code", DataExchLineDefCode); + DataExchFieldMapping.SetRange("Table ID", TableID); + DataExchFieldMapping.FindSet(); + + repeat + DataExchColumnDef.Get(DataExchDef.Code, DataExchLineDefCode, DataExchFieldMapping."Column No."); + + if DataExchFieldMapping."Use Default Value" then + ValueAsString := DataExchFieldMapping."Default Value" + else begin + FieldRef := RecRef.Field(DataExchFieldMapping."Field ID"); + if FieldRef.Class = FieldRef.Class::FlowField then + if DataExchFlowFieldGrBuff.Get(RecRef.RecordId, FieldRef.Number) then + FieldRef.Value := DataExchFlowFieldGrBuff.Value + else + FieldRef.CalcField(); + + CheckOptional(DataExchFieldMapping.Optional, FieldRef); + CastToDestinationType(ValueAsDestType, FieldRef.Value, DataExchColumnDef, DataExchFieldMapping.Multiplier); + ValueAsString := FormatToText(ValueAsDestType, DataExchDef, DataExchColumnDef); + + if TransformationRule.Get(DataExchFieldMapping."Transformation Rule") then + ValueAsString := CopyStr(TransformationRule.TransformText(ValueAsString), 1, 250); + + if DataExchColumnDef."Text Padding Required" and (DataExchColumnDef."Pad Character" <> '') and (not DataExchColumnDef."Blank Zero") then + ValueAsString := + StringConversionManagement.GetPaddedString( + ValueAsString, + DataExchColumnDef.Length, + DataExchColumnDef."Pad Character", + DataExchColumnDef.Justification); + end; + + OnProcessColumnMappingOnBeforeCheckLength(ValueAsString, DataExchFieldMapping, DataExchColumnDef); + CheckLength(ValueAsString, RecRef.Field(DataExchFieldMapping."Field ID"), DataExchDef, DataExchColumnDef); + + TempDataExchField.Get(DataExch."Entry No.", LineNo, DataExchFieldMapping."Column No."); + TempDataExchField.SetValueWithoutModifying(ValueAsString); + TempDataExchField.Modify(); + until DataExchFieldMapping.Next() = 0; + end; + + local procedure PrepopulateColumns(DataExchDef: Record "Data Exch. Def"; DataExchLineDefCode: Code[20]; DataExchEntryNo: Integer; DataExchLineNo: Integer; var TempDataExchField: Record "Data Exch. Field" temporary) + var + DataExchLineDef: Record "Data Exch. Line Def"; + DataExchColumnDef: Record "Data Exch. Column Def"; + ColumnIndex: Integer; + begin + if DataExchDef."File Type" in + [DataExchDef."File Type"::"Fixed Text", + DataExchDef."File Type"::Xml, + DataExchDef."File Type"::Json] + then begin + DataExchColumnDef.SetRange("Data Exch. Def Code", DataExchDef.Code); + DataExchColumnDef.SetRange("Data Exch. Line Def Code", DataExchLineDefCode); + if not DataExchColumnDef.FindSet() then + Error(DataExchLineDefNotFoundErr, DataExchDef.Name, DataExchLineDefCode); + repeat + TempDataExchField.InsertRec( + DataExchEntryNo, DataExchLineNo, DataExchColumnDef."Column No.", + PadStr(DataExchColumnDef.Constant, DataExchColumnDef.Length), DataExchLineDefCode) + until DataExchColumnDef.Next() = 0; + end else begin + if not DataExchLineDef.Get(DataExchDef.Code, DataExchLineDefCode) then + Error(DataExchLineDefNotFoundErr, DataExchDef.Name, DataExchLineDefCode); + for ColumnIndex := 1 to DataExchLineDef."Column Count" do + if DataExchColumnDef.Get(DataExchDef.Code, DataExchLineDef.Code, ColumnIndex) then + TempDataExchField.InsertRec( + DataExchEntryNo, DataExchLineNo, ColumnIndex, DataExchColumnDef.Constant, DataExchLineDefCode) + else + TempDataExchField.InsertRec(DataExchEntryNo, DataExchLineNo, ColumnIndex, '', DataExchLineDefCode); + end; + end; + local procedure CheckOptional(Optional: Boolean; FieldRef: FieldRef) var Value: Variant;