Skip to main content

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 OnBeforeDoPlausibilityChecksOnAfterDoHeaderPlausibilityChecksOnAfterDoLinePlausibilityChecks 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 OnBeforeDoHeaderPlausibilityChecksOnBeforeDoLinePlausibilityChecksOnAfterDoHeaderPlausibilityChecks 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 MessageConfirm 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.
  • 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)