Skip to main content

Implementation of a new, generic document class WIP

SQUEEZE → Core → Your processing

This guide is deliberately focused and pipeline-oriented: It shows how document data is downloaded from SQUEEZE, processed in queues, and persisted in DEXPRO Core—and where a third-party extension comes into play.

Term: In this guide, “SQUEEZE app” refers to the Business Central extension that is connected to the SQUEEZE API and controls imports to DEXPRO Core.

Assumptions:

  • Third-party developers typically work with published icons, not with the entire source code.
  • The SQUEEZE app handles downloading + import queue + creation of the core document as well as the rudimentary creation of the SQUEEZE document, taking field mapping into account, as soon as setup is complete.
  • Your extension takes over the business logic once the core document exists: create or extend source records, validate them, generate “Processed JSON,” and optionally create your own target object or document.

1) The end-to-end process SQUEEZE → Core

Once the document class and setup are configured, the SQUEEZE app's import pipeline typically runs as follows:

  1. DXP Document Class extend and bind your implementation: DXP ISource Document.
  2. Configure settings for this Document class‑Setup.
    • When validating DXP SQZ Document Class ID, the SQUEEZE app automatically retrieves the required setup values from SQUEEZE (e.g., DXP SQZ Export Interface ID and DXP SQZ Line Table ID) and fills them in.
  3. The SQUEEZE app job calls DXP SQZ API Mgt.DownloadDocumentData(). Can also be called via “Download documents”.
    • New entries are created in the DXP SQZ import queue (document ID + target client).
  4. The SQUEEZE app calls DXP SQZ Import Queue Mgt.TransferImportQueueEntries().
    • The orchestration code unit DXP Sqz Create Document is executed for the entries in the import queue.
  5. DXP SQZ API Mgt.CreateCoreAndSQUEEZEDocument(DocClass, DocumentId) loads the complete JSON.
    • DXP Document Mgt.AddDocument(DocClass, DocumentId, RawJson, …) is called up.
    • Result: A DXP Document‑Record exists. Status = ImportedJSON Raw is filled.
  6. The SQUEEZE app calls your implementation ISourceDocument.CreateSource(Document).
    • Your implementation begins here.

After step 6, you will have:

  • A Core‑Container‑Document (DXP Document).
  • A SQUEEZE document in the SQUEEZE app.
  • Your source records should exist once CreateSource has completed successfully.

2) What you implement (Interfaces)

Source contract, i.e., squeeze page: DXP ISource Document

You implement this to:

  • Create your editable source data sets from DXP Document.JSON Raw
  • Validate source data records
  • Generate “Processed JSON” and transfer it to core processing

Target contract, i.e., target document: DXP IDocument Processing

You implement this if Core is to create/update its own target data set (your own table/document) from the “Processed JSON.”


3) SchrittStep 1 — DokumentklasseDefine definierendocument undclass Quell‑Implementierungand zuweisenassign source implementation

ErstellenCreate Siean eineenum Enum‑Extensionextension undand bindenbind Sieyour Ihresource Source‑Implementierung:implementation:

enumextension 50100 "MY Document Class Ext." extends "DXP Document Class"
{
    value(50100; "MY Generic Document")
    {
        Caption = 'My Generic Document';
        Implementation = "DXP ISource Document" = "MY Source Document Impl.";
    }
}

4) SchrittStep 2 — Dokumentenklassen‑EinrichtungConfigure konfigurierendocument class setup (damitso diethat Importwarteschlangethe gefülltimport wird)queue is filled)

KonfigurierenConfigure Siethe SQUEEZE-specific fields in der Dokumentenklassen‑Einrichtung fürthe Ihredocument neueclass Dokumentklassesetup diefor SQUEEZE‑spezifischenyour Felder.new document class.

Wichtig:Important:

  • DasValidating Validierenthe von DXP SQZ Document Class ID triggert dastriggers automatischethe Ladenautomatic derloading erforderlichenof Konfigurationthe ausrequired configuration from SQUEEZE (z. B. e.g., DXP SQZ Export Interface ID und  and DXP SQZ Line Table ID).
  • FallsIf derthe Abrufcall fehlschlägt,fails, werdenthese dieseAPI-derived API‑abgeleitetenfields Felderare wiedercleared geleert.again.

Ergebnis:Result: DieThe SQUEEZE‑AppSQUEEZE kann app can execute DownloadDocumentData() ausführen undand Einträgecreate in entries in the DXP SQZ Import Queue für Ihrefor Klasseyour anlegen.class.


5) SchrittStep 3 — FeldzuordnungEnsure sicherstellenfield mapping (heruntergeladenedownloaded Zuordnungmapping + Ihreyour Standardwerte)default values)

DieThe SQUEEZE‑AppSQUEEZE kannapp dencan Feldkatalogdownload desthe angeschlossenenfield catalog of the connected Squeeze Mandantenclient herunterladenand undpersist it in Core‑Mapping‑TabellenCore persistierenMapping tables (proper Dokumentklasse)document class).

IhreYour Rollerole alsas Dokumentklassen‑Implementierer:a document class implementer:

  • Standard‑FeldzuordnungProvide standard field mapping “Squeeze Field Name → AL Field No. via via InitFieldMapping(...) bereitstellen..
  • AlternativAlternatively, Feldermap überfields dievia Zuordnungs‑Pagesthe mappenassignment pages (Benutzerdefiniertecustom Feldzuordnung)field assignment).

5.1 Implement InitFieldMapping implementieren (eigenständigesindependent Beispiel)example)

codeunit 50101 "MY Source Document Impl." implements "DXP ISource Document"
{
    procedure InitFieldMapping(var HeaderMapping: Dictionary of [Text, Integer]; var LineMapping: Dictionary of [Text, Integer])
    var
        Header: Record "DXP SQZ Document Header";
        Line: Record "DXP SQZ Document Line";
    begin
        Clear(HeaderMapping);
        Clear(LineMapping);

        // Header fields
        HeaderMapping.Add('vendorNo', Header.FieldNo("Buy-from Vendor No."));
        HeaderMapping.Add('documentDate', Header.FieldNo("Document Date"));
        HeaderMapping.Add('postingDate', Header.FieldNo("Posting Date"));
        HeaderMapping.Add('reference', Header.FieldNo("Document Reference"));

        // Line fields
        LineMapping.Add('description', Line.FieldNo(Description));
        LineMapping.Add('quantity', Line.FieldNo(Quantity));
        LineMapping.Add('unitPrice', Line.FieldNo("Direct Unit Cost"));
    end;

    // other interface methods omitted here...
}

5.2 Validierungs‑SchalterValidation beimswitch Zuweisenwhen vonassigning Feldern:fields: App‑FeldValidate validierenapp field

WennWhen diethe SQUEEZE‑AppSQUEEZE oderapp Ihreor Quell‑Erstelllogikyour JSON‑Wertesource increation „App-/Quellfelder“logic schreibt,writes könnenJSON Sievalues steuern,to ob“app/source der fields,” you can control whether the OnValidate‑TriggerOnValidate trigger ausgeführt wird.is executed.

In DXP Custom Field Mapping:

  • Validate App Field  = App‑FeldValidate währendthe desapp Assignmentsfield validieren.during the assignment.
  • Validate  (Ziel)Target) = ValidierungPerform beimvalidation Transferwhen intransferring dasto Ziel‑Feldthe ausführen.target field.

NutzenUse Siethis, dasfor z. B.example, wennif Erweiterungsfelderextension Business‑Logikfields in have business logic in OnValidate haben oderor wennif Sieyou bewusstwant trigger‑freito assign deliberately trigger-free (performanter)higher zuweisen wollen.performance).


6) SchrittStep 4 — Source‑DatensätzeCreate in Source data sets in CreateSource erstellen

CreateSource(Document) wird vonis dercalled SQUEEZE‑Appby unmittelbarthe nach SQUEEZE app immediately after DXP Document Mgt.AddDocument(...) aufgerufen, sobaldas dersoon Core‑Container‑Datensatzas existiert.the core container data record exists.

MinimaleMinimum Verantwortlichkeiten:responsibilities:

  1. Read DXP Document.JSON Raw lesen..
  2. Create SQUEEZE‑Source‑Header/Lines erstellen (DXP SQZ Document Header / DXP SQZ Document Line).
  3. Connect Core‑Dokumentdocument mit demwith SQUEEZE‑Source‑Header via via UpdateDocumentAfterTransfer verknüpfen..

Optional (empfohlen,recommended wennif Sieyou Gleichwertigkeitwant derfunctionality Funktionenequivalent zuto denthe Standard‑SQUEEZE‑Dokumentklassenstandard möchten)SQUEEZE document classes): 4) AnhängeDownload herunterladen,attachments wenn if DXP Download Attachments aktiv ist.is active. 5) AutomatischePerform Validierungautomatic ausführen,validation wennif fürenabled dasfor Dokumentthe aktiviert.document.

6.1 Beispiel:Example: Create SQUEEZE‑Header + Lines mitwith dengeneric generischen Helpern erstellenhelpers

WasWhat diethe Helperhelpers machendo (damitso Sieyou esdon't nichthave doppeltto implementieren)implement it twice):

  • SqzDocumentMgt.CreateSQUEEZEDocHeader(Document, DocHeader, RawJson)

    • ErstelltCreates genauexactly einenone Datensatzdata in record in DXP SQZ Document Header für dasfor the Core‑Dokumentdocument (DXP Document).
    • SetztSets Identifikationsfelderidentification wie fields asCore Document No. und dieand the SQUEEZE‑API Document ID.
    • WeistAssigns Header‑Felderheader ausfields from JSON anhandbased deron konfiguriertenthe Zuordnungenconfigured zu:mappings:
      • DXP Field Mapping  (Feldzuordnung)field mapping)
      • DXP Custom Field Mapping  (BenutzerdefinierteCustom Feldzuordnung)field mapping)
    • Respektiert Respects DXP Custom Field Mapping.Validate App Field und entscheidetand damit,thus obdecides beimwhether Zuweisenthe der OnValidate‑TriggerOnValidate trigger ausgeführt wird.is executed when assigning.
    • FührtExecutes dasthe Integration‑Event integration event OnBeforeModifySQUEEZEDocumentHeader(...) als Extension‑Hookas aus.an extension hook.
    • FürStandard diepost-processing eingebautenis Standard‑SQUEEZE‑Klassenalso wirdperformed zusätzlichfor Standard‑Post‑Processingthe ausgeführtbuilt-in standard SQUEEZE classes (z. B.e.g., alternative IBAN/USt‑ID‑Ermittlung,VAT Lieferantenaktualisierung,ID Standard‑Buchungsdatum,determination, Duplikatsprüfung)supplier update, standard posting date, duplicate check).
  • SqzDocumentMgt.CreateSQUEEZEDocLine(DocHeader, RawJson)

    • ErstelltCreates die the DXP SQZ Document LineDatensätzedata basierendsets aufbased denon the JSON‑Rows.
    • WeistAssign Line‑Felderline nachfields demusing gleichenthe Mapping‑Prinzipsame zumapping principle (Standardstandard + Custom;custom; optionaloptionally mitwith Validierungstriggern)validation triggers).
    • Befüllt Fill the Core Document No. auf denin Lines.the lines.
    • FürFor Standard‑SQUEEZE‑Klassenstandard wirdSQUEEZE zusätzlichclasses, Standard‑Line‑Post‑Processingstandard angewendetline post-processing is also applied (z. B.e.g., Übertragungtransfer erkannterof Werte)recognized values).
    • PersistiertPersists line‑bezogeneline-related Hilfsdatenauxiliary data (z. B.e.g., Koordinaten/Metadaten,coordinates/metadata diethat use the UI undand Matching‑Logikmatching nutzen)logic).
procedure CreateSource(Document: Record "DXP Document"): Boolean
var
    DocClassSetup: Record "DXP Document Class Setup";
    AutoValidationMgt: Codeunit "DXP Automatic Validation Mgt.";
    JsonHelper: Codeunit "DXP Json Helper";
    DocMgt: Codeunit "DXP Document Mgt.";
    SqzDocumentMgt: Codeunit "DXP SQZ Document Mgt.";
    SqzApiMgt: Codeunit "DXP SQZ API Mgt.";
    RawJson: JsonObject;
    DocHeader: Record "DXP SQZ Document Header";
    AutomaticValidation: Boolean;
begin
    if (not Document."JSON Raw".HasValue()) or (Document.Status <> Document.Status::Imported) then
        exit(false);

    // 1) Unverarbeitetes JSON lesen
    RawJson := JsonHelper.JObjectFromBlob(Document.RecordId(), Document.FieldNo("JSON Raw"));

    // 2) SQUEEZE‑Source‑Dokument mit den generischen Hilfsfunktionen erstellen
    //    (Feldzuordnung + optionales Validierungs‑Trigger‑Verhalten wird im Helper behandelt)
    SqzDocumentMgt.CreateSQUEEZEDocHeader(Document, DocHeader, RawJson);
    SqzDocumentMgt.CreateSQUEEZEDocLine(DocHeader, RawJson);

    // 3) Core → SQUEEZE‑Source‑Header verknüpfen
    DocMgt.UpdateDocumentAfterTransfer(Document."No.", Document.Status::Transferred, DocHeader."API Document ID", DocHeader.RecordId());

    // 4) Optional: Anhänge herunterladen und speichern
    //    (gesteuert über die Dokumentenklassen‑Einrichtung)
    if DocClassSetup.Get(DocHeader."Document Class") then
        if DocClassSetup."DXP Download Attachments" then
            SqzApiMgt.DownloadAndSaveAttachments(DocHeader);

    // 5) Optional: Automatische Validierung
    //    Wenn aktiviert, führt die Validierung die Plausibilitätsprüfungen aus und erstellt das „Processed JSON“.
    AutomaticValidation := AutoValidationMgt.AutomaticValidationActivated(DocHeader."No.");
    if AutomaticValidation then
        SqzDocumentMgt.ValidateSQUEEZEDocument(DocHeader, AutomaticValidation);

    exit(true);
end;

7) SchrittStep 5 — ValidierungValidation + ÜbergabeHandover „Processed JSON“

7.1 Validierung: Validation: IsSourceDataPlausible

NutzenUse Siethe dasCore Core‑Plausibility‑Framework,Plausibility damitFramework Fehlerto konsistentensure angezeigtthat werden:errors are displayed consistently:

procedure IsSourceDataPlausible(Source: Variant; var TempPlausibilityCheckEntry: Record "DXP Plausibility Check Entry" temporary): Boolean
var
    PlausibilityCheck: Codeunit "DXP Plausiblity Check Mgt.";
    Header: Record "DXP SQZ Document Header";
begin
    if not Source.IsRecord then
        exit(false);

    Header := Source;
    TempPlausibilityCheckEntry.DeleteAll();

    PlausibilityCheck.FieldIsEmpty(Header, Header.FieldNo("Buy-from Vendor No."), 0, false, false);
    PlausibilityCheck.CheckPostingDate(Header."Posting Date", Header.FieldNo("Posting Date"));
    PlausibilityCheck.GetPlausibilityCheckEntries(TempPlausibilityCheckEntry);

    exit(TempPlausibilityCheckEntry.IsEmpty());
end;

7.2 Build „Processed JSON“ bauenand undpass anit Coreto übergeben: the core: CreateProcessedJsonFromSource

Core stores “Processed JSON“JSON” wirdin von Core in DXP Document.JSON Processed gespeichert undand antransfers Ihreit Zielverarbeitungto übergeben.your target processing.

procedure CreateProcessedJsonFromSource(Source: Variant)
var
    CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
    DocMgt: Codeunit "DXP Document Mgt.";
    JsonHelper: Codeunit "DXP Json Helper";
    DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
    Header: Record "DXP SQZ Document Header";
    Line: Record "DXP SQZ Document Line";
    HeaderJObj: JsonObject;
    LinesJArr: JsonArray;
    LineJObj: JsonObject;
begin
    Header := Source;

    HeaderJObj.Add(CoreTokenMgt.GetVendorNoTok(), Header."Buy-from Vendor No.");
    HeaderJObj.Add(CoreTokenMgt.GetDocDateTok(), Header."Document Date");
    HeaderJObj.Add(CoreTokenMgt.GetDocReferenceTok(), Header."Document Reference");

    // Benutzerdefinierte Felder (Erweiterungsfelder) aus den Source‑Tabellen hinzufügen
    HeaderJObj.Add(CoreTokenMgt.GetCustomFieldsTok(), JsonHelper.Rec2JsonFieldArray(Header, true, true, Header."Document Class", Enum::"DXP Field Type"::Header));

    Line.SetRange("Document No.", Header."No.");
    if Line.FindSet() then
        repeat
            Clear(LineJObj);
            LineJObj.Add(CoreTokenMgt.GetDescriptionTok(), Line.Description);
            LineJObj.Add(CoreTokenMgt.GetQtyTok(), Line.Quantity);
            LineJObj.Add(CoreTokenMgt.GetCustomFieldsTok(), JsonHelper.Rec2JsonFieldArray(Line, true, true, Header."Document Class", Enum::"DXP Field Type"::Line));
            LinesJArr.Add(LineJObj);
        until Line.Next() = 0;

    DocTransferMgt.AddDocLinesToHeaderJson(HeaderJObj, LinesJArr);

    // An Core‑Zielverarbeitung übergeben
    DocMgt.UpdateDocument(
        Header."Core Document No.",
        Enum::"DXP Document Status"::Transferred,
        Enum::"DXP Target Document Process"::"MY Create Custom Document",
        Enum::"DXP Next process step"::"Standard document",
        HeaderJObj);
end;

8) SchrittStep 6 — EigenesCreate Ziel‑Dokumentyour erstellenown target document

WennIf you want Core Ihrento eigenencreate Ziel‑Datensatzyour erstellenown soll,target erweiterndata Sie set, extend DXP Target Document Process und implementierenand Sie implement DXP IDocument Processing:

enumextension 50102 "MY Target Doc Process Ext." extends "DXP Target Document Process"
{
    value(50102; "MY Create Custom Document")
    {
        Caption = 'Create My Custom Document';
        Implementation = "DXP IDocument Processing" = "MY Custom Doc Creation";
    }
}

codeunit 50103 "MY Custom Doc Creation" implements "DXP IDocument Processing"
{
    procedure ProcessStandardDocument(JObject: JsonObject): RecordId
    var
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
        DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
        JsonHelper: Codeunit "DXP Json Helper";
        MyDoc: Record "MY Custom Document";
        TargetVariant: Variant;
    begin
        MyDoc.Init();
        MyDoc.Validate("Vendor No.", JsonHelper.ValAsTxt(JObject, CoreTokenMgt.GetVendorNoTok(), false));
        MyDoc.Validate("Document Date", JsonHelper.ValAsDate(JObject, CoreTokenMgt.GetDocDateTok(), false));
        MyDoc.Insert(true);

        // Überträgt Metadaten sowie benutzerdefinierte/zusätzliche Felder anhand der Core‑Zuordnungen in den Ziel‑Datensatz.
        TargetVariant := MyDoc;
        DocTransferMgt.ProcessAdditionalInformation(JObject, TargetVariant);
        MyDoc := TargetVariant;

        exit(MyDoc.RecordId());
    end;
}

Hinweis:Note: DieThe Übertragungtransfer vonof Metadatenmetadata sowieand benutzerdefinierten/zusätzlichenuser-defined/additional Feldernfields istis imalready obigenincluded Beispielin bereitsthe enthaltenabove undexample basiertand aufis denbased Core‑Zuordnungstabellen.on the core mapping tables.


9) FehlerbehebungTroubleshooting (schnellequick Prüfungen)checks)

  • Keine Einträge in DXP SQZ Import Queue → Dokumentenklassen‑Einrichtung für SQUEEZE ist unvollständig.
  • Core‑DXP Document existiert, aber kein Source‑Datensatz → Ihr CreateSource(Document) ist fehlgeschlagen oder gibt false zurück.
  • Source existiert, aber Ziel wird nicht erstellt → CreateProcessedJsonFromSource wird nicht aufgerufen oder DXP Target Document Process ist nicht konfiguriert.
  • Falsches Trigger‑Verhalten beim Zuweisen → DXP Custom Field Mapping.Validate App Field und Validate prüfen.
    • Validate steuert, ob die Validierung des Ziel‑Feldes (OnValidate) ausgeführt wird.

10) Was Core automatisch macht

Wenn Sie DXP Document Mgt.UpdateDocument(...) aufrufen:

  • Core speichert das „Processed JSON“ in DXP Document.JSON Processed.
  • Core setzt DXP Document.Status auf den übergebenen Status.
  • Core verknüpft/aktualisiert DXP Document.Linked-to Record Id mit dem Datensatz, den Ihre DXP IDocument Processing‑Implementierung zurückgibt.
  • Core überträgt Core‑Attachments auf den zurückgegebenen Datensatz (und hängt typischerweise das „Processed JSON“ als .json‑Attachment an).