How to Develop in Smart Processing (Developer Documentation)
Status: 01.08.2026 • Reading time: ~8 minutes
Smart Processing provides extension points where you can implement custom logic to start your own processes or adapt handling to customer requirements. This document explains the key development concept: work through the active session, and trigger custom codeunits in the matching process using the session data.
1. Core Concept: Work Through the Active Processing Session
Smart Processing runs an “active draft session” while a document is being processed. During that time, relevant state is maintained centrally (document context, template context, matched lines, deviations, and intermediate data used by the UI and processing pipeline).
As a developer, the recommended approach is:
- Read the current processing context from the session.
- Perform your logic using the provided context and references.
- Write results/state back into the session when the workflow needs it.
- Rely on the platform to keep UI and processing aligned through the session architecture.
This makes customizations stable and avoids inconsistent state between what users see and what your logic changed.
2. The Central Object: “SIM_DI Process Session SI”
The codeunit “SIM_DI Process Session SI” is the central entry point for accessing and manipulating the currently active Smart Processing session. It acts as the hub to obtain relevant runtime data (inbound document, process template, line buffers, deviation metadata) and to communicate results back to the pipeline (for example, which header was processed).
Public function overview (from the provided examples)
The following table lists the public functions that are actually used in your example code. If a function exists in multiple variants (overloads), parameters that may not be present in every variant are marked as optional.
| Function | What it does | Parameters (optional marked) | Returns |
|---|---|---|---|
InitSession |
Initializes the session with an inbound document and resolves the related process template. | InboundDocument |
none |
InitSession |
Initializes the session with an inbound document and an explicitly provided process template (and clears previous session data first). | InboundDocument, ProcessTemplate |
none |
GetInboundDocument |
Retrieves the inbound document stored in the current session. | var InboundDocument |
none |
GetProcessTemplate |
Retrieves the process template stored in the current session. | var ProcessTemplate |
none |
ClearProcessSession |
Clears the full session context including inbound document, process template, mapping keys, and process data. | - | none |
ClearProcessData |
Clears only processing data (temporary header/lines/remarks, mapped lookup records, processed header id) and clears matching data. | - | none |
SetProcessedHeaderRecordId |
Stores the record reference of the created/matched target document header in the session for downstream processing (e.g., completion/archiving). | RecordId |
none |
GetProcessedHeaderRecordId |
Returns the stored processed header record reference and clears it from the session afterwards. | - | RecordId |
SetDocumentHeaderVariableRef |
Stores a copy of the provided temporary header variable in the session (used as a reference-style session header state). | var TempDocumentHeader (temporary) |
none |
GetDocumentHeaderVariable |
Copies the session’s current temporary header data into the provided temporary record variable. | var TempDocumentHeader (temporary) |
none |
SetDocumentLineVariableRef |
Stores a copy of the provided temporary line variable in the session (used as a reference-style session line state). | var TempDocumentLine (temporary) |
none |
GetDocumentLineVariable |
Copies the session’s current temporary line data into the provided temporary record variable. | var TempDocumentLine (temporary) |
none |
SetRemarkVariableRef |
Stores a copy of the provided temporary remark variable in the session (used as a reference-style session remark state). | var DocumentRemark (temporary) |
none |
RemoveDocumentRemark |
Removes a remark from the session based on line number, field number, and validation area. | LineNo, FieldNo, FieldValidationArea |
none |
GetRemarks |
Copies all session remarks into the provided temporary remark record variable. | var DocumentRemark (temporary) |
none |
RemoveMappedLookupRecord |
Removes the mapped lookup record reference for a given template field reference. | TemplateFieldRecordId |
none |
GetMappedLookupRecord |
Retrieves the mapped lookup record reference for a given template field reference (if available). | TemplateFieldRecordId, var MappedRecordId |
Boolean |
GetDevitatingLinesJsonObject |
Returns the JSON object describing deviating lines and their mismatched fields (including matching setup name and mismatch details). | - | JsonObject |
GetExecuteCodeunitRefRecordIds |
Retrieves record references assigned for execution by a specific codeunit (typically matched lines to process). | ExecuteCodeunitNo, var RecordIds |
Boolean |
GetMatchedDocumentHeader |
Retrieves the matched document header record reference for a given matching setup name (if available). | MatchingSetupName, var MatchedDocumentHeaderRecordId |
Boolean |
3. Customizations in the Matching Process
A common extension scenario is to trigger custom codeunits during matching-especially when the user completes the draft and the target header record has been created.
A key detail of this mechanism is that the custom codeunit is executed with the header record of the matched document type (for example, a purchase header). This record becomes your stable anchor: you can derive context from it, create or import lines, update related records, and then hand the result back to the session so the platform can continue its workflow.
4. Example Custom Process Codeunits (Code Unchanged)
Example 1: Import matched receipt lines after header creation
codeunit 5673320 "SIM_DI Purch.-Get Receipts"
{
Description = 'This codeunit is used as a matching import codeunit to receive purchase receipt lines and create purchase invoice lines based on the matched document lines.';
TableNo = "Purchase Header"; // <-- This is the created header after completing the processing
Access = Internal;
var
GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Process Session SI";
GlobalCodeunitGetReceipts: Codeunit "Purch.-Get Receipt";
GlobalNoPurchaseReceiptLinesFoundLbl: Label 'There are no purchase receipt lines that can be processed. Please check the purchase receipt lines and check if they already have been invoiced.';
trigger OnRun()
var
LocalRecordPurchRcptLine: Record "Purch. Rcpt. Line";
LocalMatchedLineRecordId: RecordId;
LocalToExecuteRecordIds: List of [RecordId];
begin
// Receive the matched lines that need to be executed
GlobalCodeunitSIMDIProcessSessionSI.GetExecuteCodeunitRefRecordIds(Codeunit::"SIM_DI Purch.-Get Receipts", LocalToExecuteRecordIds);
// Filter the purchase receipt lines based on the incoming matched lines
foreach LocalMatchedLineRecordId in LocalToExecuteRecordIds do
if LocalRecordPurchRcptLine.Get(LocalMatchedLineRecordId) then
LocalRecordPurchRcptLine.Mark(true);
// Get the purchase receipt lines that have not been invoiced
LocalRecordPurchRcptLine.MarkedOnly(true);
LocalRecordPurchRcptLine.SetFilter("Qty. Rcd. Not Invoiced", '<>0');
// If no purchase receipt lines are found, throw an error
if LocalRecordPurchRcptLine.IsEmpty() then
Error(GlobalNoPurchaseReceiptLinesFoundLbl);
// Execute the process to get receipt lines
GlobalCodeunitGetReceipts.SetPurchHeader(Rec);
GlobalCodeunitGetReceipts.CreateInvLines(LocalRecordPurchRcptLine);
Commit();
end;
}
This example shows a typical matching-driven process: the session provides the list of “records to execute”, and your codeunit performs an import based on exactly those matched references.
Example 2: Update deviating fields when deviation is accepted
codeunit 5673350 "SIM_DI Update Deviating Fields"
{
Description = 'This codeunit can be used to update the linked document lines with the incoming values for the fields that have been deviating during the matching process and where deviation is accepted.';
Access = Public;
var
GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Process Session SI";
GlobalCodeunitSIMCOREEvaluate: Codeunit "SIM_CORE Evaluate";
GlobalCodeunitSIMCOREJSON: Codeunit "SIM_CORE JSON";
trigger OnRun()
var
TempLocalRecordSIMDITempDocumentLine: Record "SIM_DI Temp. Document Line" temporary;
LocalRecordSIMDIProcessTemplate: Record "SIM_DI Process Template";
LocalRecordSIMDIInboundDocument: Record "SIM_DI Inbound Document";
LocalCodeunitSIMDILogManagement: Codeunit "SIM_DI Log Management";
LocalDocumentHeaderRecordId: RecordId;
LocalRecordId: RecordId;
LocalRecordRef: RecordRef;
LocalFieldRef: FieldRef;
LocalRecordIdText: Text;
LocalDevitatingLinesJsonObject: JsonObject;
LocalLineMatchingValidationFieldsJsonObject: JsonObject;
LocalJsonToken: JsonToken;
LocalFieldNoInteger: Integer;
LocalFieldNoText: Text;
LocalCellIndexInteger: Integer;
LocalMatchingSetupNameText: Text;
LocalOldValueText: Text;
LocalNewValueText: Text;
LocalValueVariant: Variant;
LocalDevitatingFieldUpdateLbl: Label 'The line %1 has been updated.\The field "%2" has been changed from value "%3" to value "%4".', Comment = '%1 = Line No., %2 = Field Name, %3 = Old Value, %4 = New Value';
begin
/// Receive the data from the process session
LocalDevitatingLinesJsonObject := GlobalCodeunitSIMDIProcessSessionSI.GetDevitatingLinesJsonObject();
GlobalCodeunitSIMDIProcessSessionSI.GetDocumentLineVariable(TempLocalRecordSIMDITempDocumentLine);
GlobalCodeunitSIMDIProcessSessionSI.GetInboundDocument(LocalRecordSIMDIInboundDocument);
GlobalCodeunitSIMDIProcessSessionSI.GetProcessTemplate(LocalRecordSIMDIProcessTemplate);
// Itterate over the
foreach LocalRecordIdText in LocalDevitatingLinesJsonObject.keys() do begin
if not Evaluate(LocalRecordId, LocalRecordIdText) then continue;
if not LocalRecordRef.Get(LocalRecordId) then continue;
// Get the current line record
LocalDevitatingLinesJsonObject.Get(LocalRecordIdText, LocalJsonToken);
// Get the matching setup name
LocalMatchingSetupNameText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'MatchingSetupName');
// Get the miss matched fields as a json object
if not LocalJsonToken.AsObject().Get('MissMatchedFields', LocalJsonToken) then continue;
LocalLineMatchingValidationFieldsJsonObject := LocalJsonToken.AsObject();
// Itterate over the miss matched fields and update the linked document line with the incoming value if deviation is accepted
foreach LocalFieldNoText in LocalLineMatchingValidationFieldsJsonObject.keys() do begin
if not Evaluate(LocalFieldNoInteger, LocalFieldNoText) then continue;
LocalLineMatchingValidationFieldsJsonObject.Get(LocalFieldNoText, LocalJsonToken);
if not GlobalCodeunitSIMCOREJSON.GetJsonPathValueBoolean(LocalJsonToken.AsObject(), 'AcceptDeviation') then
continue;
if not Evaluate(LocalCellIndexInteger, GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'CellIndex')) then
continue;
LocalFieldRef := LocalRecordRef.Field(LocalFieldNoInteger);
LocalNewValueText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'IncomingValue');
LocalOldValueText := LocalFieldRef.Value;
// Update the field with the incoming value
GlobalCodeunitSIMCOREEvaluate.EvaluateVariable(
LocalNewValueText,
Format(LocalFieldRef.Type),
LocalValueVariant,
false
);
LocalFieldRef.Validate(LocalValueVariant);
LocalRecordRef.Modify();
// Add log entry
LocalCodeunitSIMDILogManagement.AddInformationInTheLog(
StrSubstNo(LocalDevitatingFieldUpdateLbl, Format(LocalRecordIdText), LocalFieldRef.Caption, LocalOldValueText, LocalNewValueText),
'SIM_DI Update Deviating Fields',
LocalRecordSIMDIInboundDocument."Entry No."
);
end;
// Remember the document header record id to archive the document later
GlobalCodeunitSIMDIProcessSessionSI.GetMatchedDocumentHeader(LocalMatchingSetupNameText, LocalDocumentHeaderRecordId);
end;
// Set the matched document header record id to the session
GlobalCodeunitSIMDIProcessSessionSI.SetProcessedHeaderRecordId(LocalDocumentHeaderRecordId);
Commit();
end;
}
This example illustrates “session-driven deviation handling”: the session supplies a structured deviation dataset; your code applies accepted deviations, records what changed, and reports the processed header back into the session.
5. Custom Lookup Validation Codeunits
Custom lookup codeunits validate template fields against master data. Configure via Use Lookup Validation = Custom Codeunit in template field settings.
Contract: TableNo = "SIM_DI Lookup Codeunit"
Input Fields:
- Parameter – Operation type: 'Lookup' (user clicks lookup) or 'Validate' (automatic validation)
- Input Value – Value to validate or search term
- Templ. Field RecordId / Temp. Document Line RecordId – Context references
Output Fields:
- Lookup Return Value – Validated value to return
- Lookup Validation Success – true if found, false if failed
- Lookup Error Message – Error text when validation fails
- Lookup Table No. – Master data table used (only requiered for errors)
Implementation Pattern
Your codeunit must:
- Handle both operation modes via
case Rec.Parameter - Retrieve context from session using
GetProcessTemplate()andGetDocumentLineVariable() - Implement validation logic: exact match first, then search filter fallback
- Set all output fields and call
Rec.Modify() - Synchronize related fields (e.g., update Description when No. is validated) using
ChangeAdditionalField()pattern - Return clear error messages when validation fails
Key Points:
- For 'Lookup' mode: Open
Page.RunModal()and return selected value - For 'Validate' mode: Find matching record, set return value and error message
- Always update
Lookup Validation Success,Lookup Return Value, andLookup Error Message - Use separate RecordRef for pre-validation to avoid mutating page source
- For type-dependent validation: retrieve Type from document line, map to table/fields dynamically
Complete Example
The example below demonstrates all patterns including type resolution, bidirectional field sync, two-phase validation, and error handling:
codeunit 5673301 "SIM_DI LookUp No."
{
TableNo = "SIM_DI Lookup Codeunit";
Description = 'This codeunit is used to lookup the number of the item, G/L Account, resource, fixed asset, and allocation account.';
Access = Public;
var
GlobalRecordSIMDIProcessTemplate: Record "SIM_DI Process Template";
GlobalCodeunitSIMDISession: Codeunit "SIM_DI Process Session SI";
GlobalTypeNotFilledErrLbl: Label 'To validate this field, the field "Type" must be filled in.';
trigger OnRun()
var
LocalRecordSIMDITemplField: Record "SIM_DI Templ. Field";
LocalRecordRef: RecordRef;
LocalSalesLineType: Enum "Sales Line Type";
LocalNoFieldNo: Integer;
LocalDescFieldNo: Integer;
begin
GlobalCodeunitSIMDISession.GetProcessTemplate(GlobalRecordSIMDIProcessTemplate);
if not LocalRecordSIMDITemplField.Get(Rec."Templ. Field RecordId") then exit;
// Resolve the sales line type from the document line
if not this.ResolveSalesLineType(Rec, LocalSalesLineType) then exit;
// Get the table and field configuration for the resolved type
if not this.GetTypeConfiguration(LocalSalesLineType, LocalRecordRef, LocalNoFieldNo, LocalDescFieldNo) then begin
Rec."Lookup Validation Success" := false;
Rec."Lookup Error Message" := GlobalTypeNotFilledErrLbl;
Rec.Modify();
exit;
end;
case Rec.Parameter of
'Lookup':
if this.CreateLookupPage(Rec, LocalRecordRef, LocalNoFieldNo, LocalDescFieldNo) then begin
Rec."Lookup Validation Success" := true;
Rec."Lookup Return Value" := CopyStr(Format(LocalRecordRef.Field(LocalNoFieldNo).Value), 1, MaxStrLen(Rec."Lookup Return Value"));
Rec.Modify();
this.ChangeAdditionalField(
GlobalRecordSIMDIProcessTemplate."Template Code",
Rec."Temp. Document Line RecordId",
Format(LocalRecordRef.Field(LocalDescFieldNo).Value)
);
end;
'Validate':
this.ValidateNo(Rec, LocalRecordRef, LocalNoFieldNo, LocalDescFieldNo);
end;
end;
/// <summary>
/// Resolves the sales line type from the document line context.
/// </summary>
/// <param name="Rec">The lookup codeunit record containing the context.</param>
/// <param name="ParamSalesLineType">The resolved sales line type.</param>
/// <returns>True if the type was resolved successfully, otherwise false.</returns>
local procedure ResolveSalesLineType(var Rec: Record "SIM_DI Lookup Codeunit"; var ParamSalesLineType: Enum "Sales Line Type"): Boolean
var
TempLocalRecordSIMDITempDocumentLine: Record "SIM_DI Temp. Document Line" temporary;
LocalRecordSalesLine: Record "Sales Line";
LocalTypeText: Text;
LocalTypeNotExistErrLbl: Label 'The type "%1" does not exist. Please use a valid type.', Comment = '%1 = Type Text';
LocalInvalidRecordIdErrLbl: Label 'Received an invalid record id to lookup.';
begin
GlobalCodeunitSIMDISession.GetDocumentLineVariable(TempLocalRecordSIMDITempDocumentLine);
if not TempLocalRecordSIMDITempDocumentLine.Get(Rec."Temp. Document Line RecordId") then begin
Rec."Lookup Validation Success" := false;
Rec."Lookup Error Message" := LocalInvalidRecordIdErrLbl;
Rec.Modify();
exit(false);
end;
LocalTypeText := TempLocalRecordSIMDITempDocumentLine.GetCellValueViaFieldNo(
GlobalRecordSIMDIProcessTemplate."Template Code", LocalRecordSalesLine.FieldNo(Type));
if not Evaluate(ParamSalesLineType, LocalTypeText) then begin
Rec."Lookup Validation Success" := false;
Rec."Lookup Error Message" := StrSubstNo(LocalTypeNotExistErrLbl, LocalTypeText);
Rec.Modify();
exit(false);
end;
exit(true);
end;
/// <summary>
/// Returns the table reference and field numbers for the given sales line type.
/// </summary>
/// <param name="ParamSalesLineType">The sales line type to configure.</param>
/// <param name="ParamRecordRef">The record reference to open for the corresponding table.</param>
/// <param name="ParamNoFieldNo">The field number of the No. field.</param>
/// <param name="ParamDescFieldNo">The field number of the Description/Name field.</param>
/// <returns>True if the type is supported, otherwise false.</returns>
local procedure GetTypeConfiguration(
ParamSalesLineType: Enum "Sales Line Type";
var ParamRecordRef: RecordRef;
var ParamNoFieldNo: Integer;
var ParamDescFieldNo: Integer): Boolean
var
LocalRecordItem: Record "Item";
LocalRecordGLAccount: Record "G/L Account";
LocalRecordResource: Record "Resource";
LocalRecordFixedAsset: Record "Fixed Asset";
LocalRecordAllocationAccount: Record "Allocation Account";
begin
case ParamSalesLineType of
ParamSalesLineType::"Charge (Item)",
ParamSalesLineType::Item:
begin
ParamRecordRef.Open(Database::Item);
ParamNoFieldNo := LocalRecordItem.FieldNo("No.");
ParamDescFieldNo := LocalRecordItem.FieldNo(Description);
end;
ParamSalesLineType::"G/L Account":
begin
ParamRecordRef.Open(Database::"G/L Account");
ParamNoFieldNo := LocalRecordGLAccount.FieldNo("No.");
ParamDescFieldNo := LocalRecordGLAccount.FieldNo(Name);
end;
ParamSalesLineType::Resource:
begin
ParamRecordRef.Open(Database::Resource);
ParamNoFieldNo := LocalRecordResource.FieldNo("No.");
ParamDescFieldNo := LocalRecordResource.FieldNo(Name);
end;
ParamSalesLineType::"Fixed Asset":
begin
ParamRecordRef.Open(Database::"Fixed Asset");
ParamNoFieldNo := LocalRecordFixedAsset.FieldNo("No.");
ParamDescFieldNo := LocalRecordFixedAsset.FieldNo(Description);
end;
ParamSalesLineType::"Allocation Account":
begin
ParamRecordRef.Open(Database::"Allocation Account");
ParamNoFieldNo := LocalRecordAllocationAccount.FieldNo("No.");
ParamDescFieldNo := LocalRecordAllocationAccount.FieldNo(Name);
end;
else
exit(false);
end;
exit(true);
end;
/// <summary>
/// Validates the input value by matching against the No. field.
/// </summary>
/// <param name="Rec">The lookup codeunit record to validate and update.</param>
/// <param name="ParamRecordRef">The record reference to search in.</param>
/// <param name="ParamNoFieldNo">The field number of the No. field.</param>
/// <param name="ParamDescFieldNo">The field number of the Description/Name field.</param>
/// <returns>The RecordId of the found record, or an empty RecordId if not found.</returns>
local procedure ValidateNo(
var Rec: Record "SIM_DI Lookup Codeunit";
var ParamRecordRef: RecordRef;
ParamNoFieldNo: Integer;
ParamDescFieldNo: Integer): RecordId
var
LocalRemarkMessageLbl: Label 'The %2 "%1" could not be located.', Comment = '%1 = Field Value, %2 = Table';
begin
// Try exact match on No. field
if StrLen(Rec."Input Value") <= ParamRecordRef.Field(ParamNoFieldNo).Length then begin
ParamRecordRef.Field(ParamNoFieldNo).SetRange(Rec."Input Value");
Rec."Lookup Validation Success" := ParamRecordRef.FindFirst();
end;
// Try search filter on No. field
if not Rec."Lookup Validation Success" then begin
ParamRecordRef.Reset();
ParamRecordRef.Field(ParamNoFieldNo).SetRange(Rec."Input Value");
Rec."Lookup Validation Success" := ParamRecordRef.FindFirst();
end;
if Rec."Lookup Validation Success" then begin
Rec."Lookup Return Value" := CopyStr(Format(ParamRecordRef.Field(ParamNoFieldNo).Value), 1, MaxStrLen(Rec."Lookup Return Value"));
this.ChangeAdditionalField(
GlobalRecordSIMDIProcessTemplate."Template Code",
Rec."Temp. Document Line RecordId",
Format(ParamRecordRef.Field(ParamDescFieldNo).Value)
);
end else
Rec."Lookup Error Message" := StrSubstNo(LocalRemarkMessageLbl, Rec."Input Value", ParamRecordRef.Caption());
Rec."Lookup Table No." := ParamRecordRef.Number;
Rec.Modify();
if Rec."Lookup Validation Success" then
exit(ParamRecordRef.RecordId);
end;
/// <summary>
/// Creates a lookup page to display records and allow the user to select one.
/// Pre-selects a record by validating the input value against the No. field.
/// </summary>
/// <param name="Rec">The lookup codeunit record.</param>
/// <param name="ParamRecordRef">The record reference for the lookup page.</param>
/// <param name="ParamNoFieldNo">The field number of the No. field.</param>
/// <param name="ParamDescFieldNo">The field number of the Description/Name field.</param>
/// <returns>True if the user selects a record, otherwise false.</returns>
local procedure CreateLookupPage(
var Rec: Record "SIM_DI Lookup Codeunit";
var ParamRecordRef: RecordRef;
ParamNoFieldNo: Integer;
ParamDescFieldNo: Integer): Boolean
var
LocalValidationRecordRef: RecordRef;
LocalRecordId: RecordId;
LocalVariant: Variant;
begin
// Use a separate RecordRef for validation to keep the original clean for the page
LocalValidationRecordRef.Open(ParamRecordRef.Number);
LocalRecordId := this.ValidateNo(Rec, LocalValidationRecordRef, ParamNoFieldNo, ParamDescFieldNo);
if ParamRecordRef.Get(LocalRecordId) then;
LocalVariant := ParamRecordRef;
exit(Page.RunModal(0, LocalVariant) = Action::LookupOK);
end;
/// <summary>
/// Changes the value of an additional field on the document line based on the lookup result.
/// This is used to set the description field after looking up the number, ensuring both fields are populated.
/// </summary>
/// <param name="ParamTemplateCode">The template code of the document.</param>
/// <param name="ParamTempDocumentLineRecordId">The record ID of the temp document line to update.</param>
/// <param name="ParamFieldValueText">The value to set in the additional field.</param>
local procedure ChangeAdditionalField(
ParamTemplateCode: Code[20];
ParamTempDocumentLineRecordId: RecordId;
ParamFieldValueText: Text)
var
TempLocalRecordSIMDITempDocumentLine: Record "SIM_DI Temp. Document Line" temporary;
LocalRecordSIMDITemplField: Record "SIM_DI Templ. Field";
begin
GlobalCodeunitSIMDISession.GetDocumentLineVariable(TempLocalRecordSIMDITempDocumentLine);
if not TempLocalRecordSIMDITempDocumentLine.Get(ParamTempDocumentLineRecordId) then exit;
if not LocalRecordSIMDITemplField.GetViaFieldName(ParamTemplateCode, Enum::"SIM_DI Document Type"::Line, 'Description') then exit;
if LocalRecordSIMDITemplField."Use Lookup Validation" = LocalRecordSIMDITemplField."Use Lookup Validation"::No then exit;
TempLocalRecordSIMDITempDocumentLine.SetCellValue(
TempLocalRecordSIMDITempDocumentLine.GetCellIndex(LocalRecordSIMDITemplField),
CopyStr(ParamFieldValueText, 1, 250)
);
GlobalCodeunitSIMDISession.SetDocumentLines(TempLocalRecordSIMDITempDocumentLine);
end;
}
Additional Customization Points
There are more places where custom codeunits can be integrated, but the guiding principle remains constant: use the session to retrieve the active processing context and to write back workflow-relevant results. This keeps your extensions consistent with the Smart Processing flow and prevents UI/process drift.