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:
DXP Document Classextend and bind your implementation:DXP ISource Document.- 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 IDandDXP SQZ Line Table ID) and fills them in.
- When validating
- 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).
- The SQUEEZE app calls
DXP SQZ Import Queue Mgt.TransferImportQueueEntries().- The orchestration code unit
DXP Sqz Create Documentis executed for the entries in the import queue.
- The orchestration code unit
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 =Imported,JSON Rawis filled.
- 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
CreateSourcehas 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) 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 IDtriggert das automatische Laden der erforderlichen Konfiguration aus SQUEEZE (z. B.DXP SQZ Export Interface IDundDXP 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:
DXP Document.JSON Rawlesen.- SQUEEZE‑Source‑Header/Lines erstellen (
DXP SQZ Document Header/DXP SQZ Document Line). - Core‑Dokument mit dem SQUEEZE‑Source‑Header via
UpdateDocumentAfterTransferverknü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 Headerfü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 Fieldund 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).
- Erstellt genau einen Datensatz in
-
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).
- Erstellt die
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 Documentexistiert, aber kein Source‑Datensatz → IhrCreateSource(Document)ist fehlgeschlagen oder gibtfalsezurück. - Source existiert, aber Ziel wird nicht erstellt →
CreateProcessedJsonFromSourcewird nicht aufgerufen oderDXP Target Document Processist nicht konfiguriert. - Falsches Trigger‑Verhalten beim Zuweisen →
DXP Custom Field Mapping.Validate App FieldundValidateprüfen.Validatesteuert, 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.Statusauf den übergebenen Status. - Core verknüpft/aktualisiert
DXP Document.Linked-to Record Idmit dem Datensatz, den IhreDXP 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).