Hoe te Ontwikkelen in Slimme Verwerking (Ontwikkelaarsdocumentatie)
Status: 01.08.2026 • Leestijd: ~8 minuten
Slimme Verwerking biedt uitbreidingspunten waar je aangepaste logica kunt implementeren om je eigen processen te starten of de afhandeling aan te passen aan klantvereisten. Dit document legt het belangrijkste ontwikkelingsconcept uit: werk door de actieve sessie en trigger aangepaste codeunits in het bijbehorende proces met behulp van de sessiegegevens.
1. Kernconcept: Werk Door de Actieve Verwerkingssessie
Slimme Verwerking draait een “actieve conceptsessie” terwijl een document wordt verwerkt. Gedurende die tijd wordt de relevante status centraal onderhouden (documentcontext, sjablooncontext, gematchte regels, afwijkingen en tussenliggende gegevens die door de UI en verwerkingspipeline worden gebruikt).
Als ontwikkelaar is de aanbevolen aanpak:
- Lees de huidige verwerkingscontext uit de sessie.
- Voer je logica uit met behulp van de verstrekte context en referenties.
- Schrijf resultaten/status terug in de sessie wanneer de workflow dit nodig heeft.
- Vertrouw op het platform om de UI en verwerking in overeenstemming te houden via de sessiearchitectuur.
Dit maakt aanpassingen stabiel en voorkomt inconsistente status tussen wat gebruikers zien en wat je logica heeft veranderd.
2. Het Centrale Object: “SIM_DI Verwerkingssessie SI”
De codeunit “SIM_DI Verwerkingssessie SI” is het centrale toegangspunt voor het verkrijgen en manipuleren van de momenteel actieve Slimme Verwerkingssessie. Het fungeert als de hub om relevante runtime-gegevens te verkrijgen (inbound document, proces-sjabloon, regelbuffers, afwijkingsmetadata) en om resultaten terug te communiceren naar de pipeline (bijvoorbeeld, welke header is verwerkt).
Overzicht van openbare functies (uit de verstrekte voorbeelden)
De volgende tabel geeft de openbare functies weer die daadwerkelijk in je voorbeeldcode worden gebruikt. Als een functie in meerdere varianten (overloads) bestaat, zijn parameters die mogelijk niet in elke variant aanwezig zijn gemarkeerd als optioneel.
“SIM_DI Verwerkingssessie SI” - Tabel van Openbare Functies
| Functie | Wat het doet | Parameters (optioneel gemarkeerd) | Retourneert |
|---|---|---|---|
InitSession |
Initialiseert de sessie met een inbound document en lost het bijbehorende proces-sjabloon op. | InboundDocument |
geen |
InitSession |
Initialiseert de sessie met een inbound document en een expliciet verstrekt proces-sjabloon (en wist eerst de vorige sessiegegevens). | InboundDocument, ProcessTemplate |
geen |
GetInboundDocument |
Haalt het inbound document op dat in de huidige sessie is opgeslagen. | var InboundDocument |
geen |
GetProcessTemplate |
Haalt het proces-sjabloon op dat in de huidige sessie is opgeslagen. | var ProcessTemplate |
geen |
ClearProcessSession |
Wis de volledige sessiecontext, inclusief inbound document, proces-sjabloon, mapping-sleutels en procesgegevens. | - | geen |
ClearProcessData |
Wis alleen verwerkingsgegevens (tijdelijke header/regels/opmerkingen, gemapte lookup-records, verwerkte header-id) en wist bijpassende gegevens. | - | geen |
SetProcessedHeaderRecordId |
Slaat de recordreferentie van de gemaakte/gematchte doel documentheader op in de sessie voor downstream verwerking (bijv. voltooiing/archivering). | RecordId |
geen |
GetProcessedHeaderRecordId |
Retourneert de opgeslagen verwerkte header recordreferentie en wist deze daarna uit de sessie. | - | RecordId |
SetDocumentHeaderVariableRef |
Slaat een kopie van de verstrekte tijdelijke headervariabele op in de sessie (gebruikt als een referentiestijl sessie headerstatus). | var TempDocumentHeader (tijdelijk) |
geen |
GetDocumentHeaderVariable |
Kopieert de huidige tijdelijke headergegevens van de sessie naar de verstrekte tijdelijke recordvariabele. | var TempDocumentHeader (tijdelijk) |
geen |
SetDocumentLineVariableRef |
Slaat een kopie van de verstrekte tijdelijke regelvariabele op in de sessie (gebruikt als een referentiestijl sessie regelstatus). | var TempDocumentLine (tijdelijk) |
geen |
GetDocumentLineVariable |
Kopieert de huidige tijdelijke regeldgegevens van de sessie naar de verstrekte tijdelijke recordvariabele. | var TempDocumentLine (tijdelijk) |
geen |
SetRemarkVariableRef |
Slaat een kopie van de verstrekte tijdelijke opmerkingvariabele op in de sessie (gebruikt als een referentiestijl sessie opmerkingstatus). | var DocumentRemark (tijdelijk) |
geen |
RemoveDocumentRemark |
Verwijdert een opmerking uit de sessie op basis van regelnummer, veldnummer en validatiegebied. | LineNo, FieldNo, FieldValidationArea |
geen |
GetRemarks |
Kopieert alle sessieopmerkingen naar de verstrekte tijdelijke opmerkingrecordvariabele. | var DocumentRemark (tijdelijk) |
geen |
RemoveMappedLookupRecord |
Verwijdert de gemapte lookup-recordreferentie voor een gegeven sjabloonveldreferentie. | TemplateFieldRecordId |
geen |
GetMappedLookupRecord |
Haalt de gemapte lookup-recordreferentie op voor een gegeven sjabloonveldreferentie (indien beschikbaar). | TemplateFieldRecordId, var MappedRecordId |
Boolean |
GetDevitatingLinesJsonObject |
Retourneert het JSON-object dat afwijkende regels en hun niet-overeenkomende velden beschrijft (inclusief naam van de matching setup en mismatchdetails). | - | JsonObject |
GetExecuteCodeunitRefRecordIds |
Haalt recordreferenties op die zijn toegewezen voor uitvoering door een specifieke codeunit (typisch gematchte regels om te verwerken). | ExecuteCodeunitNo, var RecordIds |
Boolean |
GetMatchedDocumentHeader |
Haalt de gematchte documentheader recordreferentie op voor een gegeven naam van de matching setup (indien beschikbaar). | MatchingSetupName, var MatchedDocumentHeaderRecordId |
Boolean |
Opmerking: Dit zijn alle openbare functies die uit je voorbeelden kunnen worden bevestigd. Als je de volledige codeunit-bron verstrekt, zal ik deze tabel uitbreiden zodat deze elke openbare functie bevat.
3. Aanpassingen in het Matchingproces
Een veelvoorkomend uitbreidingsscenario is het triggeren van aangepaste codeunits tijdens het matchen, vooral wanneer de gebruiker het concept heeft voltooid en de doel headerrecord is aangemaakt.
Een belangrijk detail van dit mechanisme is dat de aangepaste codeunit wordt uitgevoerd met de headerrecord van het gematchte documenttype (bijvoorbeeld, een aankoopheader). Deze record wordt je stabiele anker: je kunt context hieruit afleiden, regels maken of importeren, gerelateerde records bijwerken en vervolgens het resultaat teruggeven aan de sessie zodat het platform zijn workflow kan voortzetten.
4. Voorbeeld van Aangepaste Procescodeunits (Code Ongewijzigd)
Voorbeeld 1: Importeer gematchte ontvangstregels na headercreatie
codeunit 5673320 "SIM_DI Aankoop.-Ontvangsten Krijgen"
{
Description = 'Deze codeunit wordt gebruikt als een matching import codeunit om aankoopontvangstregels te ontvangen en aankoopfactuurregels te creëren op basis van de gematchte documentregels.';
TableNo = "Aankoop Header"; // <-- Dit is de aangemaakte header na het voltooien van de verwerking
Access = Internal;
var
GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Verwerkingssessie SI";
GlobalCodeunitGetReceipts: Codeunit "Aankoop.-Ontvangst Krijgen";
GlobalNoPurchaseReceiptLinesFoundLbl: Label 'Er zijn geen aankoopontvangstregels die kunnen worden verwerkt. Controleer de aankoopontvangstregels en kijk of ze al zijn gefactureerd.';
trigger OnRun()
var
LocalRecordPurchRcptLine: Record "Aankoop. Ontvangst. Regel";
LocalMatchedLineRecordId: RecordId;
LocalToExecuteRecordIds: List of [RecordId];
begin
// Ontvang de gematchte regels die moeten worden uitgevoerd
GlobalCodeunitSIMDIProcessSessionSI.GetExecuteCodeunitRefRecordIds(Codeunit::"SIM_DI Aankoop.-Ontvangsten Krijgen", LocalToExecuteRecordIds);
// Filter de aankoopontvangstregels op basis van de binnenkomende gematchte regels
foreach LocalMatchedLineRecordId in LocalToExecuteRecordIds do
if LocalRecordPurchRcptLine.Get(LocalMatchedLineRecordId) then
LocalRecordPurchRcptLine.Mark(true);
// Verkrijg de aankoopontvangstregels die nog niet zijn gefactureerd
LocalRecordPurchRcptLine.MarkedOnly(true);
LocalRecordPurchRcptLine.SetFilter("Qty. Rcd. Niet Gefactureerd", '<>0');
// Als er geen aankoopontvangstregels worden gevonden, gooi een fout
if LocalRecordPurchRcptLine.IsEmpty() then
Error(GlobalNoPurchaseReceiptLinesFoundLbl);
// Voer het proces uit om ontvangstregels te krijgen
GlobalCodeunitGetReceipts.SetPurchHeader(Rec);
GlobalCodeunitGetReceipts.CreateInvLines(LocalRecordPurchRcptLine);
Commit();
end;
}
Dit voorbeeld toont een typisch matching-gedreven proces: de sessie biedt de lijst van “records om uit te voeren”, en je codeunit voert een import uit op basis van precies die gematchte referenties.
Voorbeeld 2: Update afwijkende velden wanneer afwijking is geaccepteerd
codeunit 5673350 "SIM_DI Update Afwijkende Velden"
{
Description = 'Deze codeunit kan worden gebruikt om de gekoppelde documentregels bij te werken met de binnenkomende waarden voor de velden die tijdens het matchingproces afwijkend zijn geweest en waar afwijking is geaccepteerd.';
Access = Public;
var
GlobalCodeunitSIMDIProcessSessionSI: Codeunit "SIM_DI Verwerkingssessie SI";
GlobalCodeunitSIMCOREEvaluate: Codeunit "SIM_CORE Evalueren";
GlobalCodeunitSIMCOREJSON: Codeunit "SIM_CORE JSON";
trigger OnRun()
var
TempLocalRecordSIMDITempDocumentLine: Record "SIM_DI Temp. Document Regel" tijdelijk;
LocalRecordSIMDIProcessTemplate: Record "SIM_DI Proces Sjabloon";
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 'De regel %1 is bijgewerkt.\Het veld "%2" is veranderd van waarde "%3" naar waarde "%4".', Comment = '%1 = Regel Nr., %2 = Veldnaam, %3 = Oude Waarde, %4 = Nieuwe Waarde';
begin
/// Ontvang de gegevens van de proces sessie
LocalDevitatingLinesJsonObject := GlobalCodeunitSIMDIProcessSessionSI.GetDevitatingLinesJsonObject();
GlobalCodeunitSIMDIProcessSessionSI.GetDocumentLineVariable(TempLocalRecordSIMDITempDocumentLine);
GlobalCodeunitSIMDIProcessSessionSI.GetInboundDocument(LocalRecordSIMDIInboundDocument);
GlobalCodeunitSIMDIProcessSessionSI.GetProcessTemplate(LocalRecordSIMDIProcessTemplate);
// Itereer over de
foreach LocalRecordIdText in LocalDevitatingLinesJsonObject.keys() do begin
if not Evaluate(LocalRecordId, LocalRecordIdText) then continue;
if not LocalRecordRef.Get(LocalRecordId) then continue;
// Verkrijg de huidige regelrecord
LocalDevitatingLinesJsonObject.Get(LocalRecordIdText, LocalJsonToken);
// Verkrijg de naam van de matching setup
LocalMatchingSetupNameText := GlobalCodeunitSIMCOREJSON.GetJsonPathValueText(LocalJsonToken.AsObject(), 'MatchingSetupName');
// Verkrijg de niet-overeenkomende velden als een json-object
if not LocalJsonToken.AsObject().Get('MissMatchedFields', LocalJsonToken) then continue;
LocalLineMatchingValidationFieldsJsonObject := LocalJsonToken.AsObject();
// Itereer over de niet-overeenkomende velden en werk de gekoppelde documentregel bij met de binnenkomende waarde als afwijking is geaccepteerd
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;
// Werk het veld bij met de binnenkomende waarde
GlobalCodeunitSIMCOREEvaluate.EvaluateVariable(
LocalNewValueText,
Format(LocalFieldRef.Type),
LocalValueVariant,
false
);
LocalFieldRef.Validate(LocalValueVariant);
LocalRecordRef.Modify();
// Voeg logboekvermelding toe
LocalCodeunitSIMDILogManagement.AddInformationInTheLog(
StrSubstNo(LocalDevitatingFieldUpdateLbl, Format(LocalRecordIdText), LocalFieldRef.Caption, LocalOldValueText, LocalNewValueText),
'SIM_DI Update Afwijkende Velden',
LocalRecordSIMDIInboundDocument."Entry Nr."
);
end;
// Onthoud de documentheaderrecord-id om het document later te archiveren
GlobalCodeunitSIMDIProcessSessionSI.GetMatchedDocumentHeader(LocalMatchingSetupNameText, LocalDocumentHeaderRecordId);
end;
// Stel de gematchte documentheaderrecord-id in op de sessie
GlobalCodeunitSIMDIProcessSessionSI.SetProcessedHeaderRecordId(LocalDocumentHeaderRecordId);
Commit();
end;
}
Dit voorbeeld illustreert “sessie-gedreven afwijkingsafhandeling”: de sessie levert een gestructureerde afwijkingsdataset; je code past geaccepteerde afwijkingen toe, registreert wat is veranderd en rapporteert de verwerkte header terug in de sessie.
5. Aanvullende Aanpassingspunten
Er zijn meer plaatsen waar aangepaste codeunits kunnen worden geïntegreerd, maar het leidende principe blijft constant: gebruik de sessie om de actieve verwerkingscontext op te halen en om workflow-relevante resultaten terug te schrijven. Dit houdt je extensies consistent met de Slimme Verwerkingsflow en voorkomt UI/procesafwijkingen.