Skip to main content

Implementation of a new, generic document class WIP

SQUEEZE → Core → IhreYour Verarbeitungprocessing

DieserThis Leitfadenguide istis bewusstdeliberately fokussiertfocused undand pipeline‑orientiert:pipeline-oriented: ErIt zeigt,shows wiehow Belegdatendocument ausdata SQUEEZE heruntergeladen,is downloaded from SQUEEZE, processed in Warteschlangenqueues, verarbeitetand undpersisted in in DEXPRO Core persistiertCore—and werdenwhere a undthird-party anextension welchercomes Stelleinto sich eine Drittanbieter‑Extension einklinkt.play.

Begriff:Term: In diesemthis Leitfadenguide, meintSQUEEZE „SQUEEZE‑App“app dierefers Business‑Central‑Erweiterung,to diethe mitBusiness derCentral extension that is connected to the SQUEEZE API verbundenand istcontrols undimports den Import nachto DEXPRO Core steuert.Core.

Annahmen:Assumptions:

  • Drittanbieter‑EntwicklerThird-party arbeitendevelopers typischerweisetypically mit work with veröffentlichtenpublished Symbolenicons, nichtnot mitwith demthe gesamtenentire Quellcode.source code.
  • DieThe SQUEEZE‑AppSQUEEZE übernimmt app handles Herunterladendownloading + Importwarteschlangeimport queue + Erstellungcreation desof Core‑Belegsthe sowiecore diedocument rudimentäreas Erstellungwell desas SQUEEZE‑Belegsthe unterrudimentary Berücksichtigungcreation derof Feldzuordnungthe SQUEEZE document, taking field mapping into account, sobaldas diesoon Einrichtungas abgeschlossensetup ist.is complete.
  • IhreYour Extensionextension übernimmttakes dieover Fachlogik,the nachdembusiness daslogic Core‑Dokumentonce existiert:the Quell‑Datensätzecore erstellendocument bzw.exists: erweitern,create validieren,or extend source records, validate them, generate “Processed JSON“JSON,” erzeugenand undoptionally optionalcreate einyour eigenesown Zielobjekttarget oderobject einenor eigenen Beleg erstellen.document.

1) DerThe Ende‑zu‑Ende‑Ablaufend-to-end process SQUEEZE → Core

SobaldOnce Dokumentklassethe unddocument Einrichtungclass konfiguriertand sind,setup läuftare dieconfigured, Importpipelinethe derSQUEEZE SQUEEZE‑Appapp's typischerweiseimport sopipeline ab:typically runs as follows:

  1. DXP Document Class erweitern extend  undand Ihrebind Implementierungyour binden:implementation: DXP ISource Document.
  2. Configure settings for this Dokumentenklassen‑EinrichtungDocument class‑Setup für diese Klasse konfigurieren..
    • BeimWhen Validierenvalidating von DXP SQZ Document Class ID holt, diethe SQUEEZE‑AppSQUEEZE automatischapp dieautomatically benötigtenretrieves Einrichtungswertethe ausrequired setup values from SQUEEZE (z. B. e.g., DXP SQZ Export Interface ID und  and DXP SQZ Line Table ID) undand fülltfills sie.them in.
  3. DerThe JobSQUEEZE derapp SQUEEZE‑Appjob ruft calls DXP SQZ API Mgt.DownloadDocumentData() auf.. AuchCan also be called via "Belege“Download herunterladen" aufrufbardocuments”.
    • DabeiNew werdenentries neueare Einträgecreated in in the DXP SQZ Importimport Queue angelegtqueue (Dokument‑document ID + Zielmandant)target client).
  4. DieThe SQUEEZE‑AppSQUEEZE ruft app calls DXP SQZ Import Queue Mgt.TransferImportQueueEntries() auf..
    • DabeiThe wirdorchestration diecode Orchestrierungs‑Codeunit unit DXP Sqz Create Document für dieis Einträgeexecuted for the entries in derthe Importwarteschlangeimport ausgeführt.queue.
  5. DXP SQZ API Mgt.CreateCoreAndSQUEEZEDocument(DocClass, DocumentId) lädt dasloads vollständigethe complete JSON.
    • Es wird DXP Document Mgt.AddDocument(DocClass, DocumentId, RawJson, …) aufgerufen. is called up.
    • Ergebnis:Result: Ein A DXP DocumentDatensatzRecord existiert.exists. Status =  ImportedJSON Raw ist gefüllt.is filled.
  6. DieThe SQUEEZE‑AppSQUEEZE ruftapp Ihrecalls Implementierung your implementation ISourceDocument.CreateSource(Document) auf..
    • AbYour hierimplementation beginntbegins Ihre Implementierung.here.

NachAfter Schrittstep 66, habenyou Sie:will have:

  • EinA Core‑Container‑DokumentDocument (DXP Document).
  • EinA SQUEEZE‑DokumentSQUEEZE aufdocument Seitein derthe SQUEEZE‑App.SQUEEZE app.
  • IhreYour Source‑Datensätzesource solltenrecords existieren,should sobald exist once CreateSource erfolgreich abgeschlossenhas ist.completed successfully.

2) WasWhat Sieyou implementierenimplement (Interfaces)

Quell‑Vertrag,Source alsocontract, Squeezei.e., Seite: squeeze page: DXP ISource Document

DasYou implementierenimplement Sie,this um:to:

  • IhreCreate editierbarenyour Source‑Datensätzeeditable aus source data sets from DXP Document.JSON Raw zu erstellen
  • Source‑DatensätzeValidate zusource validierendata records
  • Generate “Processed JSON“JSON” zuand erzeugentransfer undit anto Core‑Processingcore zu übergebenprocessing

Ziel‑Vertrag,Target alsocontract, Zielbeleg: i.e., target document: DXP IDocument Processing

DasYou implementierenimplement Sie,this wennif Core ausis demto create/update its own target data set (your own table/document) from the “Processed JSON“ einen eigenen Ziel‑Datensatz (Ihre eigene Tabelle / Ihr eigenes Dokument) erstellen/aktualisieren soll.JSON.”


3) Schritt 1 — Dokumentklasse definieren und Quell‑Implementierung zuweisen

Erstellen Sie eine Enum‑Extension und binden Sie Ihre Source‑Implementierung:

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) Schritt 2 — Dokumentenklassen‑Einrichtung konfigurieren (damit die Importwarteschlange gefüllt wird)

Konfigurieren Sie in der Dokumentenklassen‑Einrichtung für Ihre neue Dokumentklasse die SQUEEZE‑spezifischen Felder.

Wichtig:

  • Das Validieren von DXP SQZ Document Class ID triggert das automatische Laden der erforderlichen Konfiguration aus SQUEEZE (z. B. DXP SQZ Export Interface ID und DXP SQZ Line Table ID).
  • Falls der Abruf fehlschlägt, werden diese API‑abgeleiteten Felder wieder geleert.

Ergebnis: Die SQUEEZE‑App kann DownloadDocumentData() ausführen und Einträge in DXP SQZ Import Queue für Ihre Klasse anlegen.


5) Schritt 3 — Feldzuordnung sicherstellen (heruntergeladene Zuordnung + Ihre Standardwerte)

Die SQUEEZE‑App kann den Feldkatalog des angeschlossenen Squeeze Mandanten herunterladen und in Core‑Mapping‑Tabellen persistieren (pro Dokumentklasse).

Ihre Rolle als Dokumentklassen‑Implementierer:

  • Standard‑Feldzuordnung „Squeeze Field Name → AL Field No.“ via InitFieldMapping(...) bereitstellen.
  • Alternativ Felder über die Zuordnungs‑Pages mappen (Benutzerdefinierte Feldzuordnung).

5.1 InitFieldMapping implementieren (eigenständiges Beispiel)

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‑Schalter beim Zuweisen von Feldern: App‑Feld validieren

Wenn die SQUEEZE‑App oder Ihre Quell‑Erstelllogik JSON‑Werte in „App-/Quellfelder“ schreibt, können Sie steuern, ob der OnValidate‑Trigger ausgeführt wird.

In DXP Custom Field Mapping:

  • Validate App Field = App‑Feld während des Assignments validieren.
  • Validate (Ziel) = Validierung beim Transfer in das Ziel‑Feld ausführen.

Nutzen Sie das z. B. wenn Erweiterungsfelder Business‑Logik in OnValidate haben oder wenn Sie bewusst trigger‑frei (performanter) zuweisen wollen.


6) Schritt 4 — Source‑Datensätze in CreateSource erstellen

CreateSource(Document) wird von der SQUEEZE‑App unmittelbar nach DXP Document Mgt.AddDocument(...) aufgerufen, sobald der Core‑Container‑Datensatz existiert.

Minimale Verantwortlichkeiten:

  1. DXP Document.JSON Raw lesen.
  2. SQUEEZE‑Source‑Header/Lines erstellen (DXP SQZ Document Header / DXP SQZ Document Line).
  3. Core‑Dokument mit dem SQUEEZE‑Source‑Header via UpdateDocumentAfterTransfer verknüpfen.

Optional (empfohlen, wenn Sie Gleichwertigkeit der Funktionen zu den Standard‑SQUEEZE‑Dokumentklassen möchten): 4) Anhänge herunterladen, wenn DXP Download Attachments aktiv ist. 5) Automatische Validierung ausführen, wenn für das Dokument aktiviert.

6.1 Beispiel: SQUEEZE‑Header + Lines mit den generischen Helpern erstellen

Was die Helper machen (damit Sie es nicht doppelt implementieren):

  • SqzDocumentMgt.CreateSQUEEZEDocHeader(Document, DocHeader, RawJson)

    • Erstellt genau einen Datensatz in DXP SQZ Document Header für das Core‑Dokument (DXP Document).
    • Setzt Identifikationsfelder wie Core Document No. und die SQUEEZE‑API Document ID.
    • Weist Header‑Felder aus JSON anhand der konfigurierten Zuordnungen zu:
      • DXP Field Mapping (Feldzuordnung)
      • DXP Custom Field Mapping (Benutzerdefinierte Feldzuordnung)
    • Respektiert DXP Custom Field Mapping.Validate App Field und entscheidet damit, ob beim Zuweisen der OnValidate‑Trigger ausgeführt wird.
    • Führt das Integration‑Event OnBeforeModifySQUEEZEDocumentHeader(...) als Extension‑Hook aus.
    • Für die eingebauten Standard‑SQUEEZE‑Klassen wird zusätzlich Standard‑Post‑Processing ausgeführt (z. B. alternative IBAN/USt‑ID‑Ermittlung, Lieferantenaktualisierung, Standard‑Buchungsdatum, Duplikatsprüfung).
  • SqzDocumentMgt.CreateSQUEEZEDocLine(DocHeader, RawJson)

    • Erstellt die DXP SQZ Document Line‑Datensätze basierend auf den JSON‑Rows.
    • Weist Line‑Felder nach dem gleichen Mapping‑Prinzip zu (Standard + Custom; optional mit Validierungstriggern).
    • Befüllt Core Document No. auf den Lines.
    • Für Standard‑SQUEEZE‑Klassen wird zusätzlich Standard‑Line‑Post‑Processing angewendet (z. B. Übertragung erkannter Werte).
    • Persistiert line‑bezogene Hilfsdaten (z. B. Koordinaten/Metadaten, die UI und Matching‑Logik nutzen).
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) Schritt 5 — Validierung + Übergabe „Processed JSON“

7.1 Validierung: IsSourceDataPlausible

Nutzen Sie das Core‑Plausibility‑Framework, damit Fehler konsistent angezeigt werden:

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 „Processed JSON“ bauen und an Core übergeben: CreateProcessedJsonFromSource

„Processed JSON“ wird von Core in DXP Document.JSON Processed gespeichert und an Ihre Zielverarbeitung übergeben.

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) Schritt 6 — Eigenes Ziel‑Dokument erstellen

Wenn Core Ihren eigenen Ziel‑Datensatz erstellen soll, erweitern Sie DXP Target Document Process und implementieren Sie 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: Die Übertragung von Metadaten sowie benutzerdefinierten/zusätzlichen Feldern ist im obigen Beispiel bereits enthalten und basiert auf den Core‑Zuordnungstabellen.


9) Fehlerbehebung (schnelle Prüfungen)

  • 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).