Skip to main content

Extending Excel Importer

We designed Excel Importer to be extensible so that our customers could handle new scenarios or create additional import types. This section provides information on how to extend Excel Importer, including the events that are available. Partners can use this information to extend Excel Importer.

Important

To extend Excel Importer, you need to have a Premium plan.

Need help or additional events?

If you need some guidance extending Excel Importer or you want to request an additional event or helper to assist with your extension, please get in touch with us. Remember to tell us what outcome you want to achieve - you never know; we might want to add this feature to Excel Importer and save you the trouble.

Automating Files Imports

The app now includes an API that allows you to automate the process of importing files using the Excel Importer. You can read more about this here.

Adding a new Import Type

Example: Adding a new Import Type (Basic Example)

This example uses the Standard Cost Worksheet import type as an example, which does not have any special processing.

  • Extend the enum "ImportType_EI_TSL" with your custom import type
enumextension 50000 "ImportType" extends ImportType_EI_TSL
{
value(50000; "Standard Cost Worksheet")
{
Caption = 'Standard Cost Worksheet';
}
}

  • Create a codeunit similar to the one below:
codeunit 50000 "StdCostWorksheetMgt"
{
internal procedure ImportStandardCostWorksheet();
var
ExcelImportManagement: Codeunit "Excel Import Management_EI_TSL";
begin
ExcelImportManagement.Import(Enum::ImportType_EI_TSL::"Standard Cost Worksheet", Database::"Standard Cost Worksheet", false);
end;
}
  • Create a page extension to add the Import action to your page and call your function
pageextension 50000 "StandardCostWrksheet" extends "Standard Cost Worksheet"
{
actions
{
addfirst("F&unctions")
{
action("ImportFromExcel")
{
ApplicationArea = All;
Caption = 'Import';
Ellipsis = true; Image = ImportExcel;
Promoted = true;
PromotedCategory = Process;
PromotedIsBig = true;
ToolTip = 'Allows you to import standard costs from Excel or text in a customisable layout.';

trigger OnAction()
var
StandardCostWrksheetImport: Codeunit StdCostWrksheetMgt;
begin
StandardCostWrksheetImport.ImportStandardCostWorksheet();
end;
}
}
}
}

Adding New Import Types or Changing Existing Imports

This section references events that are available to extend Excel Importer. It is not a complete list of the available events but includes events that get used frequently. You can use these events when you have more complex processing that must get handled. You can use these events when you create new import types or if you want to change the way existing import types work.

Object - EventPurpose
table "Exl. Mapping Template_EI_TSL"Excel Mapping Template
OnGetCustomTableIDSpecifies the table associated with the import type.
OnInsertCustomTemplateToBufferyou can optionally subscribe to this event if you want to specify additional details about a custom import type
OnCheckIfFieldFromCustomEntityCanBeEditedUse this event if you want to protect certain fields from being updated by the import. Using this event will cause fields to be filtered out of lookups so they cannot be selected.
OnBeforeGetRelatedFieldsAndSettingsForCustomEntityUse this event to specify the available settings as well as any related tables that get updated by the import (e.g. Header/Line). Refer to the example below to see how to use this.
OnBeforeGetRelatedFieldsAndSettingsUse this event to add additional settings to existing templates or if you want to implement different logic to handle related fields and settings for a template.
OnBeforeGetCommaSeparatedDimensionFieldIDTextUse this event associate global/shortcut dimension fields with the dimension code.
codeunit "SettingsHelper_EI_TSL"Settings Helper
HandleCustomSettingTypeThis event allows you to specify settings values for a custom setting type on an existing template. You can use the approach above to specify the allowed values.
OnCustomLookupSettingValueUse this event to specify the available setting values for the setting type in relation to a custom template. This is different to the HandleCustomSettingType event in that it only fires for a custom template. Here is an example on how to use this.

The example code comes from the sales and purchase document import (it has been changed slightly as build in imports do not use these events).

    [EventSubscriber(ObjectType::Table, Database::"Exl. Mapping Template_EI_TSL", OnBeforeGetRelatedFieldsAndSettingsForCustomEntity, '', false, false)]
local procedure OnBeforeGetRelatedFieldsAndSettingsForCustomEntity(var ExcelImportManagement: Codeunit "Excel Import Management_EI_TSL"; var RelatedTableList: List of [Integer]; var RelatedFieldFilterList: List of [Text]; ImportType: Enum ImportType_EI_TSL)
begin
AddRelatedFieldsAndSettings(ExcelImportManagement, ImportType, RelatedTableList, RelatedFieldFilterList);
end;

/// <summary>
/// Adds the related tables and settings that are applicable for the import
/// </summary>
internal procedure AddRelatedFieldsAndSettings(var ExcelImportManagement: Codeunit "Excel Import Management_EI_TSL"; ImportType: Enum ImportType_EI_TSL; var RelatedTableList: List of [Integer]; var RelatedFieldFilterList: List of [Text]; var RelatedReferenceNo: Code[50]);
var
ItemTrackingMgt: Codeunit ItemTrackingMgt_EI_TSL;
NegativeDocumentTotalsTxt: Label 'Specify how to handle negative document totals - this does not apply to quotes and blanket orders', MaxLength = 100;
ReleaseDocsTxt: Label 'Release the documents or send them for approval after importing.', MaxLength = 100;
Prop_DocNoRuleTextLbl: Label 'Use the imported Document No. (if present) as the Posted Document No.', MaxLength = 100;
Prop_ReplaceDocNoTextLbl: Label 'Replace with the imported Document No. from the Number Series.', MaxLength = 100;
begin
// Add the setting types available for this import and provide some basic info including the default value and what the setting does
ExcelImportManagement.AddSettingToPropertyBuffer(SettingType::"Document No. as Posting No.", SettingValue::No, Prop_DocNoRuleTextLbl);
ExcelImportManagement.AddSettingToPropertyBuffer(SettingType::"Replace Document No.", SettingValue::No, Prop_ReplaceDocNoTextLbl);
ExcelImportManagement.AddSettingToPropertyBuffer(SettingType::"Negative Document Totals", SettingValue::"Do not Validate", NegativeDocumentTotalsTxt);
ExcelImportManagement.AddSettingToPropertyBuffer(SettingType::"Release Documents", SettingValue::No, ReleaseDocsTxt);

// tables
if ImportType = ImportType::Sales then
RelatedTableList.Add(Database::"Sales Header")
else
RelatedTableList.Add(Database::"Purchase Header");
RelatedFieldFilterList.Add(''); // you can optionally include a filter string if you only want to allow certain fields.
ItemTrackingMgt.AddTrackingSpecFields(ImportType, ExcelImportManagement, false, RelatedTableList, RelatedFieldFilterList);
end;

Example - Specifying Allowed Settings Values for a Setting Type on an existing template

This example shows you how to specify allowed values for a custom setting type on an existing template (e.g. Sales Document).

    [EventSubscriber(ObjectType::Codeunit, Codeunit::SettingsHelper_EI_TSL, OnHandleCustomSettingType, '', false, false)]
local procedure OnHandleCustomSettingType(ImportType: Enum ImportType_EI_TSL; SettingType: Enum ImportSettingType_EI_TSL; var SettingsText: Text; var IsHandled: Boolean)
begin
SettingsText := GetSettingValuesAllowedForType(ImportType, SettingType);
IsHandled := true;
end;

/// <summary>
/// Creates a comma separated list of allowed setting values for the setting type.
/// </summary>
internal procedure GetSettingValuesAllowedForType(ImportType: Enum ImportType_EI_TSL; SettingType: Enum ImportSettingType_EI_TSL) SettingsText: Text
begin
case SettingType of
SettingType::"Post Documents Automatically":
begin
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::No);
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::Yes);
end;
end;
end;

Example - Specifying Allowed Settings Values for a Setting Type on a custom template

This example shows you how to specify allowed values for a custom setting type on a custom template you have created.

    [EventSubscriber(ObjectType::Codeunit, Codeunit::SettingsHelper_EI_TSL, OnCustomLookupSettingValue, '', false, false)]
local procedure OnCustomLookupSettingValue(ImportType: Enum ImportType_EI_TSL; SettingType: Enum ImportSettingType_EI_TSL; var SettingsText: Text)
begin
SettingsText := GetSettingValuesAllowedForType(ImportType, SettingType);
end;

/// <summary>
/// Creates a comma separated list of allowed setting values for the setting type.
/// </summary>
internal procedure GetSettingValuesAllowedForType(ImportType: Enum ImportType_EI_TSL; SettingType: Enum ImportSettingType_EI_TSL) SettingsText: Text
begin
case SettingType of
SettingType::"Replace Document No.", SettingType::"Document No. as Posting No.",
SettingType::"Release Documents":
begin
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::No);
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::Yes);
end;
SettingType::"Negative Document Totals":
begin
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::"Do not Validate");
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::"Skip during Import");
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::"Cancel Import");
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::"Order/Invoice to Credit");
SettingsHelper.AddToSettingsText(SettingsText, SettingValue::"Order/Invoice to Return/Credit");
end;
else
SettingsHelper.SettingTypeNotValidForImportTypeError(ImportType, SettingType);
end;
end;

Example - Adding a text setting

It is possible to add a setting that is not an enum but a text value. Below is the example from the General Journal import. The Amount by Dimension setting will hold a dimension value.

    internal procedure AddGeneralJournalRelatedFieldsAndSettings(var ExcelImportManagement: Codeunit "Excel Import Management_EI_TSL");
var
Prop_AmtByDimDescLbl: Label 'Specify this if there are multiple amount columns, each representing a different dimension.', MaxLength = 100;
Prop_ExcludeZeroDescLbl: Label 'Skip lines where the amount is zero', MaxLength = 100;
begin
ExcelImportManagement.AddSettingToPropertyBuffer(SettingType::"Exclude Zero Amounts", SettingValue::No, Prop_ExcludeZeroDescLbl);
ExcelImportManagement.AddSettingToPropertyBuffer(SettingType::"Amount by Dimension", SettingValue::"Text Value in Constant", Prop_AmtByDimDescLbl);
end;
  • You can subscribe to OnBeforeValidateSettingValuesForSettingType to validate input while creating a template.
    internal procedure ValidateDimensionForAmountByDimension(SettingTypeParam: Enum ImportSettingType_EI_TSL; SelectedValue: Text)
var
Dimension: Record Dimension;
begin
if (SelectedValue = '') or (SettingTypeParam <> SettingTypeParam::"Amount by Dimension") then
exit;
Dimension.Get(SelectedValue);
Dimension.TestField(Blocked, false);
end;
  • You can access the value of the setting at runtime using the GetConstantTextSettingFromStorage procedure.
        AmountDimensionCode := CopyStr(SettingsHelper.GetConstantTextSettingFromStorage(SettingType::"Amount by Dimension", '', false, false), 1, MaxStrLen(AmountDimensionCode));
if AmountDimensionCode = '' then
exit;

Example - Handling Global/Shortcut Dimensions

You use this event so that the Excel Importer will update the Global/Shortcut Dimension fields as expected.

    [EventSubscriber(ObjectType::Table, Database::"Exl. Mapping Template_EI_TSL", 'OnBeforeGetCommaSeparatedDimensionFieldIDText', '', false, false)]
local procedure OnBeforeGetCommaSeparatedDimensionFieldIDText(ImportType: Enum ImportType_EI_TSL; var CommaSeparatedFieldIDText: Text; var IsHandled: Boolean);
var
ExlAccDimMapLine: Record ExlAccDimMapLine_EI_TSL;
begin
if ImportType <> ImportType::"Account/Dimension Mapping" then
exit;
CommaSeparatedFieldIDText := Format(ExlAccDimMapLine.FieldNo("Shortcut Dimension 1 Code")) + ',' + Format(ExlAccDimMapLine.FieldNo("Shortcut Dimension 2 Code"));
IsHandled := true;
end;
note

The events are shown in the order in which they fire.

OnBeforeImportExcelData

Use this event to perform custom logic after the Excel File is loaded but before the processing starts

OnBeforeCheckIfConcatenationIsRequired

This event allows you to skip concatenation in certain scenarios. For example, the General Journal Dimensioned Amount feature, when enabled on a template, disables concatenation for the Amount field.

OnAfterCopyExcelBufferToExlImpBuffer

This event is raised after the data from the current row is transferred into a temporary record, before any processing is done and before the app checks criteria for skipping the row. You can use this event if you want to perform special processing using a footer record. The event includes all buffers so you need to use the record type to determine which before to use. The LastImportedRecordRef will contain the values imported from a previous row as it has not been initialised as this stage.

OnBeforeCheckImportedValuesBeforeUpdate

Use this event if you want to do your validation before importing data. You will use this if you want to suppress some of the standard validation added by Excel Importer and add your own.

OnAfterCheckImportedValuesBeforeUpdate

Use this event to add additional validation before importing data.

OnBeforeExcludeExcelBufferRowFromImport

Use this event if you want to exclude an Excel row from the import. At this point Excel Importer has not transferred any values to fields

OnBeforeFindExistingRecord

This event fires before Excel Importer checks if there is an existing record. This is commonly used to manipulate the imported data - for example replacing an item reference with the actual item number. The StagingRecordRef parameter contains values that are mapped to fields.

OnBeforeSkipImportOfRecord

Use this event if you want to skip the import based on values on the line. The StagingRecordRef parameter contains values that are mapped to fields. This is before Excel Import has tried to find an existing record.

OnFindExistingRecord

This event is fired if Excel Importer finds an existing record with the Record ID as the record being imported.

OnInsertImportedData

This event fires before a record is inserted. At this stage no values will be transferred to the NewRecordRef unless the record exists already. You can use StagingRecordRef to get the mapped field values. You can also insert the record if it needs to exist before updating other field values.

OnBeforeApplyImportedData

This event fires before the import values are copied to the record.

OnAfterAssignFieldValue

This event gets fired after a value gets assigned to a field. You can use this event to perform special processing after updating a specific field during import.

OnBeforeModifyOrInsertImportedData

This event fires before the record is insert or modified. The dimension set is also not applied that this point. You can use this event to handle the insert or modify yourself or do some processing immediately before the insert/modify.

OnAfterApplyAndSaveData

This event fires after the dimension set is applied and the record has been insert/modified. You can use this event to handle processing that needs to happen after the record is updated.

OnPostImportData

This event fires after all records have been imported, but before the transaction has been committed. Use this event to handle post import processing that is directly connected to the import (e.g. releasing orders).

Sales and Purchase Document Events

EventPurpose
Sales Documents
OnBeforeInsertSalesHeaderThis event allows you to directly update any fields that need to be updated before the sales header is inserted.
OnAfterInsertNewSalesHeaderBeforeModifyAllows you to implement custom logic directly after all fields are transferred to a sales header before it gets modified.
OnAfterGetOrCreateSalesHeader_BeforeInsertLineAllows you to implement custom logic after the sales header is created before the line is inserted.
OnAfterInsertSalesLineBeforeUpdateFieldsAllows you to implement custom logic after the sales line is inserted with the initial values but before the line gets updated with the rest of the imported values.
Purchase Documents
OnBeforeInsertPurchaseHeaderThis event allows you to directly update any fields that need to be updated before the purchase header is inserted.
OnAfterInsertNewPurchaseHeaderBeforeModifyAllows you to implement custom logic directly after all fields are transferred to a purchase header before being modified.
OnAfterGetOrCreatePurchaseHeader_BeforeInsertLineAllows you to implement custom logic after the purchase header is created but before the line gets inserted.
OnAfterInsertPurchaseLineBeforeUpdateFieldsAllows you to implement custom logic after the purchase line is inserted with the initial values but before the line gets updated with the rest of the imported values.
CommonThese can be used for purchases and sales documents.
OnBeforeAssignDocumentNoUse this event to change how the document number gets assigned. If you assign a value to the NewDocNo parameter, the app will get that sales header.
OnAfterFieldCannotBeEditedThe app has built-in rules to prevent certain fields from being updated directly. Use this event to restrict more fields. Fields that are restricted do not show in lookups
OnBeforeFieldCannotBeEditedSimilar to the previous event, however, this event allows you to override the built-in rules
OnAfterImportSalesOrPurchaseLineAllows you to implement custom logic directly after all fields are transferred to a sales/purchase line and the line has been inserted.
OnPostImportSalesPurchaseDocsBeforeDataReleaseThis event fires after all the documents have been imported before the documents get released. This event allows you to process the imported documents before they get released or sent for approval. This event will fire even if the template is not configured to release the documents. The TempRecordRef parameter contains a record for every sales or purchase header created during the import.

Physical Inventory Journal Events

EventPurpose
OnClearPhysicalQuantityOnJournalBeforeUpdatePhysQtyYou can use this event to handle specific logic required when resetting the physical quantity on the Physical Inventory Journal before importing the recording.

Helper Functions

FunctionPurpose
Excel Import Management
ProcessRelatedTableFieldsProcesses fields from a related table. The InputSeqFrom and InputSeqTo parameters allow you to specify a range of fields to process. If you specify zero for both, it does not apply a filter. If you specify a value for only one it is either a minimum or maximum. Refer to the example below.

Example - ProcessRelatedTableFields

In this example, we show you how you can use the ProcessRelatedTableFields function to process fields from the purchase header table, which is a related table on the purchase document import.

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Sales/Purch. Doc. Imp._EI_TSL", OnBeforeInsertPurchaseHeader, '', false, false)]
local procedure "OnBeforeInsertPurchaseHeader"(var PurchaseHeader: Record "Purchase Header"; var ExlImpFieldBuffer: Record "Exl. Imp Field Buffer_EI_TSL")
begin
UpdatePurchaseHeaderFieldsBeforeInsert(PurchaseHeader, ExlImpFieldBuffer);
end;

local procedure UpdatePurchaseHeaderFieldsBeforeInsert(var PurchaseHeader: Record "Purchase Header"; var ExlImpFieldBuffer: Record "Exl. Imp Field Buffer_EI_TSL")
var
RecordRef: RecordRef;
ExcelImportManagement: Codeunit "Excel Import Management_EI_TSL";
FromProcressingOrder: Integer;
ToProcressingOrder: Integer;
begin
// logic to determine which fields to apply before insert
//FromProcressingOrder :=
//ToProcressingOrder :=

RecordRef.GetTable(PurchaseHeader);
ExcelImportManagement.ProcessRelatedTableFields(RecordRef, ExlImpFieldBuffer, FromProcressingOrder, ToProcressingOrder);
RecordRef.SetTable(PurchaseHeader);
end;

Adding a New Import Type

Adding a new import type is very straightforward.

  • Extend the "ImportType_EI_TSL" Enum to add your Import Type
  • Subscribe to the OnGetCustomTableID

Custom Values

Custom values get used to map values required for processing when these values do not relate to a specific field.

ObjectEventDescription
Table CustomValue_EI_TSLOnAfterRefreshCustomValueActions Use this event to publish a new custom action. When you subscribe to this you can use the AddActionToNameValueBuffer function described below
Table CustomValue_EI_TSLOnAfterCheckValueTypeSelectedForProcessingAction
Table CustomValue_EI_TSLOnAfterGetDefaultValueType Allows you to specify the default value type for your custom processing action.
Table CustomValue_EI_TSLOnBeforeCopyAccountDimensionValuesToSalesLine You can use this event to change how the information gets copied from the account dimension mapping. You can only make changes to the NewSalesLine parameter.
Table CustomValue_EI_TSLOnAfterGetDefaultRoundingPrecision Allows you to specify the rounding precision on the custom value. Only use this if the default rounding precision will only work for you.
Table CustomValue_EI_TSLOnBeforeCreateDefaultCustomValues You can use this event if you want to create default custom values.
Table CustomValue_EI_TSLOnAfterGetDefaultRoundingPrecision You can use this event if you want to update a default custom value before it gets inserted.
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnBeforeAddNewSalesUsingValueAsAmount Allows you to add custom logic to the AddNewSalesPurchaseLineUsingValueAsAmount processing action for sales lines before the processing action gets executed.
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnBeforeAddNewPurchaseLineUsingValueAsAmountAs above, but applies to purchase documents
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnAfterAddNewSalesUsingValueAsAmountBeforeInsertNewSalesLineAllows you to add custom logic to the AddNewSalesPurchaseLineUsingValueAsAmount processing action for sales lines after the processing action gets executed.
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnAfterAddNewPurchaseLineUsingValueAsAmountBeforeInsertNewPurchaseLineAs above, but applies to purchase documents.
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnCustomSalesPurchaseValueProcessActionAllows you to implement your own custom processing action.
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnAfterSales_InitQuantitiesOnCopyLineForCustomValuethis event fires when the new sales line is copied from the existing purchase line.
Codeunit "Sales/Purch. Doc. Imp._EI_TSL"OnAfterPurch_InitQuantitiesOnCopyLineForCustomValuethis event fires when the new purchase line is copied from the existing purchase line.

Helpers for Custom Values

ObjectFunction
Table CustomValue_EI_TSLAddActionToNameValueBuffer
Table CustomValue_EI_TSLGetActionText Used to retrieve the caption or extended description for the given action. You can use this if you want to display a message to the user and provide a user friendly reference to the action.
Table CustomValue_EI_TSLCopyAccountDimensionValuesToSalesLine Use this function if you want your custom processing action to copy values from the account dimension mapping

Example: Adding a new Processing Action

Publishing the Processing Action

The code snippet below shows you how to add a new processing action that you can select in the custom values list. The example adds a processing action that you can use on a sales import template.

var
ProcessingActionIDLbl: Label 'ProcessingActionCode_TSL', Locked = true, MaxLength = 250;
ProcessingActionCaptionTxt: Label 'Add a new sales line or purchase line if the value is not zero', MaxLength = 250;
ExtendedDescriptionTxt: Label 'Specify details about what this action does and how to use it.', MaxLength = 2048;

[EventSubscriber(ObjectType::Table, Database::CustomValue_EI_TSL, 'OnAfterRefreshCustomValueActions', '', false, false)]
local procedure OnAfterRefreshCustomValueActions(ImportType: Enum ImportType_EI_TSL; var TempNameValueBuffer: Record "Name/Value Buffer");
begin
case ImportType of
ImportType::Sales:
AddSalesProcessingActions(TempNameValueBuffer);
end;

end;

local procedure AddSalesProcessingActions(var TempNameValueBuffer: Record "Name/Value Buffer")
var
CustomValue: Record CustomValue_EI_TSL;
begin
CustomValue.AddActionToNameValueBuffer(
TempNameValueBuffer, ProcessingActionIDLbl, ProcessingActionCaptionTxt,
ExtendedDescriptionTxt);
end;

Implementing the Processing Action

Here is an example of how you can implement the processing logic on the sales import template.

    var
ProcessingActionIDLbl: Label 'ProcessingActionCode_TSL', Locked = true, MaxLength = 250;
ProcessingActionCaptionTxt: Label 'Add a new sales line or purchase line if the value is not zero', MaxLength = 250;
ExtendedDescriptionTxt: Label 'Specify details about what this action does and how to use it.', MaxLength = 2048;

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Excel Import Management_EI_TSL", 'OnAfterApplyandSaveData', '', false, false)]
local procedure OnAfterApplyandSaveData(var RecRef: RecordRef; var ValuesImported: Record "Exl. Imp Field Buffer_EI_TSL"; var TableID: Integer; var PropertyBuf2: Record "Name/Value Buffer"; var RowNo: Integer; var FirstRowNo: Integer; var TmpDimSetEntry: Record "Dimension Set Entry"; ImportTypeAsEnum: Enum ImportType_EI_TSL);
begin
if ImportTypeAsEnum = ImportTypeAsEnum::Sales then
SalesOnAfterApplyandSaveData(RecRef, ValuesImported);
end;

local procedure SalesOnAfterApplyandSaveData(var RecordRef: RecordRef; var ExlImpFieldBuffer: Record "Exl. Imp Field Buffer_EI_TSL");
var
SalesLine: Record "Sales Line";
begin
RecordRef.SetTable(SalesLine);
ProcessSalesLineCustomValueActions(SalesLine, ExlImpFieldBuffer);
end;

local procedure ProcessSalesLineCustomValueActions(ImportedSalesLine: Record "Sales Line"; var ExlImpFieldBuffer: Record "Exl. Imp Field Buffer_EI_TSL")
var
TempCustValueExlImpFieldBuffer: Record "Exl. Imp Field Buffer_EI_TSL" temporary;
CustomValue: Record CustomValue_EI_TSL;
begin
TempCustValueExlImpFieldBuffer.FilterOnCustomValuesUsingImportedFields(ExlImpFieldBuffer);
if not TempCustValueExlImpFieldBuffer.FindSet() then
exit;
repeat
case CustomValue."Processing Action" of
ProcessingActionIDLbl:
HandleMyNewProcessingAction(ImportedSalesLine, TempCustValueExlImpFieldBuffer, CustomValue);
end;
until TempCustValueExlImpFieldBuffer.Next() = 0;
end;

local procedure HandleMyNewProcessingAction(ImportedSalesLine: Record "Sales Line"; ExlImpFieldBuffer: Record "Exl. Imp Field Buffer_EI_TSL"; var CustomValue: Record CustomValue_EI_TSL)
var
NewSalesLine: Record "Sales Line";
ExcelImportManagement: Codeunit "Excel Import Management_EI_TSL";
RecordRef: RecordRef;
FieldRef: FieldRef;
TotalLineAmountExcl: Decimal;
begin
if ExlImpFieldBuffer."Cell Value as Text" = '' then
exit;
// convert the text to an amount
RecordRef.Open(Database::"Sales Line");
// the next 4 lines get the decimal value. It uses the functions in Excel Importer because there are various transformations that can
// be done using the Excel Mapping. It is recommended you use this method instead of handling it yourself
FieldRef := RecordRef.Field(NewSalesLine.FieldNo("Unit Price")); // this can be any decimal field as we only want to get the decimal value
ExlImpFieldBuffer."Validate Field Method" := ExlImpFieldBuffer."Validate Field Method"::Never; // important - we just want the value
ExcelImportManagement.EvaluateFieldRef(FieldRef, ExlImpFieldBuffer);
TotalLineAmountExcl := FieldRef.Value();
if TotalLineAmountExcl = 0 then
exit;
NewSalesLine := ImportedSalesLine;
// do something like add a new line or make changes to the line that was imported
end;