Events when validating a SQUEEZE document (Validate action) Target audience This documentation is aimed at third-party developers who want to run their own logic when a user triggers the  Validate  action on the  DXP SQZ Document v2  page (page  70954659 ) – for example additional custom checks before validation, setting further values on the SQUEEZE document, or follow-up actions on the target document that was created. The events described here are available from  SQUEEZE for Dynamics 365 BC version 2.50 . Context: what happens when you choose Validate? The  Validate  action calls two routines of the document page in sequence: 1)  CheckPlausibility() Runs the  plausibility check  of the respective  document class  and updates the  plausibility entries  in the lower part of the page. This routine runs not only when you choose  Validate , but after almost every field change. It is therefore  not  a suitable hook for "once, on validation". To extend the check itself, use the already documented events  OnBeforeDoPlausibilityChecks ,  OnAfterDoHeaderPlausibilityChecks ,  OnAfterDoLinePlausibilityChecks  and  OnAfterDoPlausibilityChecks . 2)  FinishValidation() Stops with an error message as long as plausibility entries are still open, handles the duplicate check where applicable, and then calls the  ValidateSQUEEZEDocument  method of the  DXP SQZ Document Mgt.  codeunit ( 70954632 ). That is where the processed JSON is created, the Core document ( DXP Document ) is processed further, the target document is created and the SQUEEZE document is completed. Both events described here are raised in  DXP SQZ Document Mgt.ValidateSQUEEZEDocument .  They therefore apply uniformly to: the  Validate  action on  DXP SQZ Document v2  ( 70954659 ), the  Validate  action on  DXP SQZ Document (Generic)  ( 70954670 ) and the older document pages, the  automatic validation  (for example from the processing queue). There is deliberately no event directly on the action. If you want to distinguish between a manual click and automatic validation, evaluate the  AutomaticValidation  parameter. Event matrix (overview) Area Event Timing Control Typical use cases DXP SQZ Document Mgt. OnBeforeValidateSQUEEZEDocument After the plausibility and duplicate checks, before the processed JSON is created and the target document is generated var IsHandled: Boolean  cancels the validation;  var DocHeader  allows changes to the document Custom additional checks with cancellation, filling fields, starting an approval workflow, querying external systems DXP SQZ Document Mgt. OnAfterValidateSQUEEZEDocument After the Core document has been processed and the target document has been created, before the validation dialog Cancellation not possible Post-processing the target document, writing custom log tables, sending notifications, informing third-party systems Distinction from  OnAfterWriteProcessedJsonToBlob For logic that runs  after  validation, a Core event already exists. It is described on the page  Creating custom documents (custom processing) : [IntegrationEvent(false, false)] local procedure OnAfterWriteProcessedJsonToBlob(var Document: Record "DXP Document"; var ProcessedJSONObj: JsonObject) It is raised in the  DXP Document Mgt.  codeunit (Core) after the processed JSON has been written to the Core document – within the validation process, so it fires when  Validate  is chosen as well.   OnAfterWriteProcessedJsonToBlob  (Core) OnAfterValidateSQUEEZEDocument  (SQUEEZE) Raised in DXP Document Mgt. DXP SQZ Document Mgt. Applies to all  Core documents – including those from other DEXPRO source apps. You have to filter by document class yourself. SQUEEZE documents only Context DXP Document  and the processed JSON additionally the complete  DXP SQZ Document Header  with all recognised values, order matching and splitting information Manual vs. automatic cannot be distinguished can be distinguished via  AutomaticValidation Timing directly after the JSON is written, still inside the Core processing at the end of the validation, after the SQUEEZE document has been completed JSON modifiable yes ( var ProcessedJSONObj ) no Recommendation: You want to modify the  processed JSON  or hand a document over to  custom processing  →  OnAfterWriteProcessedJsonToBlob . You want to evaluate SQUEEZE-specific values or react to manual validation only →  OnAfterValidateSQUEEZEDocument . You want to intervene  before  the target document is created, or to cancel the validation →  OnBeforeValidateSQUEEZEDocument . There is no Core equivalent for this. OnBeforeValidateSQUEEZEDocument [IntegrationEvent(false, false)] local procedure OnBeforeValidateSQUEEZEDocument(var DocHeader: Record "DXP SQZ Document Header"; AutomaticValidation: Boolean; var IsHandled: Boolean) Parameter Description var DocHeader The SQUEEZE document to be validated. Changes to fields are written afterwards and flow into the target document. AutomaticValidation false  when  Validate  is chosen,  true  for automatic validation. var IsHandled Set to  true  to cancel the validation. The SQUEEZE document stays open, unchanged. The event is raised after: the document has been re-read and has neither the  Deleted  nor the  Rejected  status, the plausibility check succeeded, in the case of automatic validation, and before the processed JSON is created. At this point the target document does not exist yet. OnAfterValidateSQUEEZEDocument [IntegrationEvent(false, false)] local procedure OnAfterValidateSQUEEZEDocument(DocHeader: Record "DXP SQZ Document Header"; CoreDocument: Record "DXP Document"; AutomaticValidation: Boolean) Parameter Description DocHeader The validated SQUEEZE document. At this point its status is already  Deleted  – this is the regular final state of a validated document and  not  an error. CoreDocument The corresponding Core document ( DXP Document ), including  Status  and  Linked-to Record Id  of the target document that was created. AutomaticValidation false  when  Validate  is chosen,  true  for automatic validation. Use the Core document to determine whether the target document was actually created: CoreDocument.Status = CoreDocument.Status::Transferred  – the target document was created and  CoreDocument."Linked-to Record Id"  points to it. CoreDocument.Status = CoreDocument.Status::"Custom Processing"  – the document was handed over to  custom processing ; no standard target document exists. Important: custom checks do  not  belong in this event OnBeforeValidateSQUEEZEDocument  is the wrong place for checks that are meant to prevent a validation. An  Error  raised here only appears as a dialog  after  the user chose  Validate  – so the user learns about the problem at the very end of their work. Use one of the two approaches below instead. Both make the problem appear as a  plausibility entry  and disable the  Validate  action. Approach 1 (no development): plausibility rule group In the  document class setup , define rules under  Plausibility Rule Group . Every active and currently valid rule whose conditions  match  describes a problem and automatically creates a plausibility entry. Rules that reference the document lines are evaluated per line, so the entry points to the line concerned. For checks such as "Shortcut Dimension 1 Code must not be empty" this is the preferred approach – no code, no extension, maintainable by the user. Approach 2 (with development):  OnAfterDoPlausibilityChecks This event is published by all document classes with  var TempPlausibilityCheckEntry  and is therefore the reliable route. You insert your entry into the temporary record directly: codeunit 50100 "My SQZ Plausibility Checks" { [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnAfterDoPlausibilityChecks', '', false, false)] local procedure OnAfterChecks(DocHeader: Record "DXP SQZ Document Header"; var TempPlausibilityCheckEntry: Record "DXP Plausibility Check Entry" temporary) var CostCenterMissingLbl: Label 'Please enter a cost center.'; begin if DocHeader."Shortcut Dimension 1 Code" <> '' then exit; AddEntry(TempPlausibilityCheckEntry, CostCenterMissingLbl, DocHeader.RecordId(), 0); end; local procedure AddEntry(var TempPlausibilityCheckEntry: Record "DXP Plausibility Check Entry" temporary; MessageText: Text; LinkedToRecId: RecordId; LookupPageId: Integer) var NewEntryNo: Integer; begin NewEntryNo := 1; TempPlausibilityCheckEntry.Reset(); TempPlausibilityCheckEntry.SetCurrentKey("Entry No."); if TempPlausibilityCheckEntry.FindLast() then NewEntryNo := TempPlausibilityCheckEntry."Entry No." + 1; TempPlausibilityCheckEntry.Init(); TempPlausibilityCheckEntry."Entry No." := NewEntryNo; TempPlausibilityCheckEntry.Text := CopyStr(MessageText, 1, MaxStrLen(TempPlausibilityCheckEntry.Text)); TempPlausibilityCheckEntry."Linked to Record Id" := LinkedToRecId; TempPlausibilityCheckEntry."Lookup Page Id" := LookupPageId; if TempPlausibilityCheckEntry.Insert() then; end; } The publisher object depends on the  document class : Document class Codeunit Purchase invoice / credit memo DXP SQZ P. Inv/Crdt Memo Impl. Order confirmation DXP SQZ P. Order Conf. Impl. Generic document classes DXP SQZ Document Mgt. Set  Linked to Record Id  and  Lookup Page Id  (for lines:  Page::"DXP SQZ Document Subform" ) so that the plausibility entry becomes clickable and jumps to the record concerned. Alternative:  OnAfterDoHeaderPlausibilityChecks PlausibilityCheck.AddPlausibilityCheckEntry(...)  offers a more convenient API that saves you the manual insert into the temporary record: [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ P. Inv/Crdt Memo Impl.", 'OnAfterDoHeaderPlausibilityChecks', '', false, false)] local procedure OnAfterHeaderChecks(DocHeader: Record "DXP SQZ Document Header"; var PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.") var CostCenterMissingLbl: Label 'Please enter a cost center.'; begin if DocHeader."Shortcut Dimension 1 Code" = '' then PlausibilityCheck.AddPlausibilityCheckEntry(CostCenterMissingLbl, 0); end; OnAfterDoLinePlausibilityChecks  works the same way for line checks; the  AddPlausibilityCheckEntry(Text; LinkedToRecId; LookupPageId)  overload makes the entry clickable. Caution for the order confirmation document class:  in  DXP SQZ P. Order Conf. Impl. , the events  OnBeforeDoHeaderPlausibilityChecks ,  OnBeforeDoLinePlausibilityChecks ,  OnAfterDoHeaderPlausibilityChecks  and  OnAfterDoLinePlausibilityChecks  were originally published without  var  on the  PlausibilityCheck  parameter. A subscriber receives a copy there, so entries it adds are lost. For this document class, use the variants with the  V2  suffix from  version 2.50  onwards – for example  OnAfterDoHeaderPlausibilityChecksV2 . Their signature is identical to the events of the other document classes. The old events remain available but are marked as obsolete. Example 1: adding values before the handover to the target document [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnBeforeValidateSQUEEZEDocument', '', false, false)] local procedure OnBeforeValidateSetPostingDescription(var DocHeader: Record "DXP SQZ Document Header"; AutomaticValidation: Boolean; var IsHandled: Boolean) begin if DocHeader."Posting Description" = '' then DocHeader."Posting Description" := CopyStr(DocHeader."Document Reference", 1, MaxStrLen(DocHeader."Posting Description")); // No Modify required – the document is written afterwards. end; Modifying the target document: please use the Core events If you want to change the  target document  that was created, neither event on this page is the right place. Core provides events that hand you the target document directly – most of them even as a typed  Purchase Header , so you can skip the detour via  Linked-to Record Id  and a  RecordRef . These events are described on the page  Events after the creation of a Core document (DXP Document) : Target document Codeunit Event Purchase invoice / credit memo DXP P. Inv. CredMemo. Creation OnAfterProcessStandardDocument(JObject; DocRecRef) Purchase document, general DXP Document Transfer Mgt. OnAfterCreatePurchaseDoc(var JObject; PurchaseHeader) Purchase header DXP Document Transfer Mgt. OnAfterCreatePurchaseHeader(var JObject; PurchaseHeader) Purchase order DXP P. Order Creation OnAfterCreatePurchaseOrder(var JObject; var PurchaseHeader) Order confirmation DXP P. Order Confirmation OnAfterProcessStandardDocument(JObject; var PurchaseHeader) OnAfterValidateSQUEEZEDocument  is only the better choice if you additionally need values from the  DXP SQZ Document Header  – for example recognised values, order matching or splitting information that is not contained in the JSON of the Core document. Example 2: reacting to manual validation only [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP SQZ Document Mgt.", 'OnAfterValidateSQUEEZEDocument', '', false, false)] local procedure OnAfterValidateNotifyUser(DocHeader: Record "DXP SQZ Document Header"; CoreDocument: Record "DXP Document"; AutomaticValidation: Boolean) var ValidatedMsg: Label 'Document %1 has been forwarded.', Comment = '%1 = SQUEEZE document no.'; begin if AutomaticValidation then exit; if not GuiAllowed() then exit; Message(ValidatedMsg, DocHeader."No."); end; Notes and limitations No dialogs in automatic processing.  Always check  AutomaticValidation  and  GuiAllowed()  before  Message ,  Confirm  or  Page.RunModal . Otherwise the processing queue runs into an error. OnBeforeValidateSQUEEZEDocument  runs after the plausibility check.  Custom checks that are supposed to appear in the page's  plausibility entries  and to disable the  Validate  action belong in  OnAfterDoHeaderPlausibilityChecks  or  OnAfterDoLinePlausibilityChecks  instead. IsHandled := true  cancels completely.  No target document is created, the Core document stays unchanged and the SQUEEZE document keeps its status. The user does not get a message – issue one yourself if required. No event for deleted or rejected documents.  If the document has the  Deleted  or  Rejected  status, validation ends beforehand and neither event is raised. OnAfterValidateSQUEEZEDocument  runs after a  Commit .  An  Error  in a subscriber does not roll the validation back; it leaves a validated document plus an error message for the user. Related pages Creating custom documents (custom processing) Events after the creation of a SQUEEZE document (CreateSource) Events after the creation of a Core document (DXP Document) Rule-based next process step (routing documents into custom processing)