Skip to main content

Erstellung benutzerdefinierter Dokumente (Individuelle Verarbeitung)

Inhaltsverzeichnis

  1. Überblick
  2. Verstehen des Dokumentenablaufs
  3. JSON-Datenstruktur
  4. Schnellstart: Einfache benutzerdefinierte Verarbeitung

Überblick

Dieses Handbuch erklärt, wie Sie benutzerdefinierte Business Central-Dokumente aus JSON-Daten erstellen, die von DEXPRO Core bereitgestellt werden. Das System empfängt Dokumente mit dem Status "Custom Processing" (Individuelle Verarbeitung), die Drittanbieter-Entwickler in jeden BC-Dokumententyp umwandeln können (Bestellungen, Verkaufsaufträge, Fibu-Buchblätter, Serviceaufträge usw.).

Was Sie lernen werden

  • Wie Sie Dokumente abfangen, die für die individuelle Verarbeitung markiert sind
  • Die JSON-Struktur mit Dokumentenkopf, Zeilen, Metadaten und benutzerdefinierten Feldern
  • Wie Sie Ihr benutzerdefiniertes Dokument erstellen

Verstehen des Dokumentenablaufs

Kernworkflow

x
 
1
┌─────────────────────────────────────────────────────────────────┐
2
│ 1. Dokumentenimport                                             │
3
│    JSON-Rohdaten → DXP Document (Status: Imported)              │
4
└────────────────────────┬────────────────────────────────────────┘
5
6
7
┌─────────────────────────────────────────────────────────────────┐
8
│ 2. Erstellung des Quelldokuments                                │
9
│    ISourceDocument.CreateSource() → Ihre Quelltabellen          │
10
│    (z.B. SQZ Document Header/Lines)  │
11
└────────────────────────┬────────────────────────────────────────┘
12
13
14
┌─────────────────────────────────────────────────────────────────┐
15
│ 3. Validierung & Plausibilitätsprüfungen                        │
16
│    ISourceDocument.IsSourceDataPlausible()                      │
17
│    → Validiert Datenqualität, prüft auf Fehler                  │
18
└────────────────────────┬────────────────────────────────────────┘
19
20
21
┌─────────────────────────────────────────────────────────────────┐
22
│ 4. Verarbeitetes JSON erstellen                                 │
23
│    ISourceDocument.CreateProcessedJsonFromSource()              │
24
│    → Erstellt JSON-Struktur für Zieldokument                    │
25
└────────────────────────┬────────────────────────────────────────┘
26
27
28
┌─────────────────────────────────────────────────────────────────┐
29
│ 5. Core-Dokument mit "Custom Processing" Status aktualisieren   │
30
│    UpdateDocument() → Setzt Status auf "Custom Processing"      │
31
│    → Speichert JSON Processed in DXP Document                   │
32
└────────────────────────┬────────────────────────────────────────┘
33
34
35
┌─────────────────────────────────────────────────────────────────┐
36
│ 6. Ihre benutzerdefinierte Verarbeitung (HIER SETZEN SIE AN!)   │
37
│    Ereignisse abonnieren oder Interface implementieren          │
38
│    → JSON Processed aus DXP Document lesen                      │
39
│    → Ihr BC-Zieldokument erstellen                              │
40
└────────────────────────┬────────────────────────────────────────┘
41
42
43
┌─────────────────────────────────────────────────────────────────┐
44
│ 7. Finale Statusaktualisierung                                  │
45
│    Dokumentstatus → Transferred oder Finished                   │
46
│    Linked-to Record Id → Ihr erstelltes BC-Dokument             │
47
└─────────────────────────────────────────────────────────────────┘
48

Wichtige Statuswerte

StatusBeschreibung
ImportedJSON-Rohdaten empfangen, noch nicht verarbeitet
TransferredQuelldokument erstellt, bereit zur Verarbeitung
Custom ProcessingIhr Zielstatus - Dokument bereit für benutzerdefinierte Verarbeitung
ClosedZieldokument erfolgreich verbucht oder ggfs. bezahlt
DeletedVerarbeitung abgebrochen, Dokument gelöscht

JSON-Datenstruktur

Überblick

Das "JSON Processed" Blob in der DXP Document-Tabelle enthält ein strukturiertes JSON-Objekt mit allen Informationen, die zum Erstellen Ihres Zieldokuments benötigt werden.

JSON-Struktur (Auszug)

xxxxxxxxxx
 
1
{
2
  // ═══════════════════════════════════════════════════════════
3
  // KOPFBEREICH - Dokumentenebene Informationen
4
  // ═══════════════════════════════════════════════════════════
5
  
6
  "Type": "Invoice",                    // Dokumenttyp: Invoice, Credit Memo, Order, usw.
7
  "VendorNo": "VENDOR001",              // Kreditoren-/Kundennummer
8
  "DocumentDate": "2025-10-15",         // Belegdatum
9
  "PostingDate": "2025-10-16",          // Buchungsdatum
10
  "DocumentReference": "INV-2025-001",  // Externe Belegnummer
11
  "OrderNo": "PO-12345",                // Referenz zur Bestellung (falls vorhanden)
12
  "PostingDescription": "Invoice Q4",   // Buchungsbeschreibung
13
  "NetAmount": 1000.00,                 // Nettobetrag (ohne MwSt.)
14
  "TotalAmount": 1190.00,               // Bruttobetrag (inkl. MwSt.)
15
  "TaxAmount": 190.00,                  // Gesamter Steuerbetrag
16
  "Currency": "EUR",                    // Währungscode
17
  
18
  // ───────────────────────────────────────────────────────────
19
  // DIMENSIONEN - Kopfebene Dimensionen als Schlüssel-Wert-Paare
20
  // ───────────────────────────────────────────────────────────
21
  
22
  "Dimensions": {
23
    "DEPARTMENT": "SALES",
24
    "PROJECT": "PROJ001",
25
    "COSTCENTER": "CC-100"
26
  },
27
  
28
  // ───────────────────────────────────────────────────────────
29
  // BENUTZERDEFINIERTE FELDER - Zusätzliche Kopffelder (siehe unten)
30
  // ───────────────────────────────────────────────────────────
31
  
32
  "CustomFields": [
33
    {
34
      "Id": 50100,
35
      "Name": "CustomerNo",
36
      "Value": "CUST001",
37
      "Caption": "Customer Number"
38
    },
39
    {
40
      "Id": 50101,
41
      "Name": "DeliveryTerms",
42
      "Value": "EXW",
43
      "Caption": "Delivery Terms"
44
    }
45
  ],
46
  
47
  // ───────────────────────────────────────────────────────────
48
  // METADATEN - Systemgenerierte Feldzuordnungen
49
  // ───────────────────────────────────────────────────────────
50
  
51
  "Metadata": [
52
    {
53
      "DocumentClass": "DXP Invoice / Credit Memo",
54
      "FieldType": "Header",
55
      "FieldId": 101,
56
      "Value": "Additional Info"
57
    }
58
  ],
59
  
60
  // ═══════════════════════════════════════════════════════════
61
  // ZEILEN-BEREICH - Dokumentzeilen
62
  // ═══════════════════════════════════════════════════════════
63
  
64
  "Lines": [
65
    {
66
      // ─────────────────────────────────────────────────────────
67
      // Zeilen-Grundinformationen
68
      // ─────────────────────────────────────────────────────────
69
      
70
      "Type": "Item",                   // Item, G/L Account, Charge (Item), Fixed Asset
71
      "No": "ITEM001",                  // Artikel-/Kontonummer
72
      "Description": "Product A",       // Zeilenbeschreibung
73
      "VendorItemNo": "VEND-SKU-123",   // Kreditorenartikelnummer
74
      "Quantity": 10.0,                 // Menge
75
      "UnitOfMeasure": "PCS",          // Einheitencode
76
      "DirectUnitCost": 100.00,        // EK-Preis
77
      "LineDiscount": 5.0,             // Zeilenrabatt in Prozent
78
      
79
      // ─────────────────────────────────────────────────────────
80
      // Zeilen-Beträge & Steuern
81
      // ─────────────────────────────────────────────────────────
82
      
83
      "NetAmount": 950.00,             // Zeilennettobetrag
84
      "TotalAmount": 1130.50,          // Zeilenbruttobetrag
85
      "TaxRate": 19.0,                 // Steuersatz in Prozent
86
      "VATBusPostingGroup": "DOMESTIC",
87
      "VATProdPostingGroup": "STANDARD",
88
      "GenBusPostingGroup": "DOMESTIC",
89
      "GenProdPostingGroup": "RETAIL",
90
      
91
      // ─────────────────────────────────────────────────────────
92
      // Bestellreferenz (für Zuordnung)
93
      // ─────────────────────────────────────────────────────────
94
      
95
      "OrderNo": "PO-12345",           // Referenzierte Bestellnummer
96
      "OrderLineNo": 10000,            // Referenzierte Bestellzeilennummer
97
      "ReceiptNo": "RCP-001",          // Referenzierte Wareneingangsnummer
98
      "ReceiptLineNo": 10000,          // Referenzierte Wareneingangszeile
99
      
100
      // ─────────────────────────────────────────────────────────
101
      // Zeilen-Dimensionen
102
      // ─────────────────────────────────────────────────────────
103
      
104
      "Dimensions": {
105
        "DEPARTMENT": "PROD",
106
        "PROJECT": "PROJ001"
107
      },
108
      
109
      // ─────────────────────────────────────────────────────────
110
      // Zeilen-Benutzerdefinierte Felder
111
      // ─────────────────────────────────────────────────────────
112
      
113
      "CustomFields": [
114
        {
115
          "Id": 50200,
116
          "Name": "SerialNo",
117
          "Value": "SN-12345",
118
          "Caption": "Serial Number"
119
        }
120
      ],
121
      
122
      // ─────────────────────────────────────────────────────────
123
      // Zeilen-Metadaten
124
      // ─────────────────────────────────────────────────────────
125
      
126
      "Metadata": [
127
        {
128
          "DocumentClass": "DXP Invoice / Credit Memo",
129
          "FieldType": "Line",
130
          "FieldId": 201,
131
          "Value": "Line-specific metadata"
132
        }
133
      ]
134
    }
135
    // ... weitere Zeilen
136
  ]
137
}
138

Benutzerdefinierte Felder vs. Metadaten

Benutzerdefinierte Felder (Custom Fields):

  • Benutzerdefinierte Felder aus Ihrer App

  • Ggfs. zugeordnet über Custom Field Mapping

  • Können jedem Feld in der Squeeze-Validierung zugeordnet werden

  • Beispiel: Hinzufügen einer "Kundennr." zur Squeeze-Validierung

Metadaten:

  • Systemgenerierte Felder

  • Vom Squeeze-System extrahiert, aber keinem Feld in BC zugeordnet


Schnellstart: Einfache benutzerdefinierte Verarbeitung

Szenario

Sie möchten einen benutzerdefinierten Dokumenttyp (z.B. einen Warenausgang) aus Dokumenten erstellen, die mit dem Status "Custom Processing" markiert sind.

Schritt 1: Integration Event abonnieren

Erstellen Sie eine Codeunit, um Dokumente mit dem Status "Custom Processing" abzufangen:

xxxxxxxxxx
 
1
codeunit 50100 "My Custom Document Handler"
2
{
3
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Document Mgt.", 
4
        'OnAfterGetDocumentOnBeforeCheckStatusAndNextProcessStep', '', true, true)]
5
    local procedure OnAfterGetDocument(
6
        var Document: Record "DXP Document"; 
7
        NewStatus: Enum "DXP Document Status"; 
8
        NextStep: Enum "DXP Next process step"; 
9
        var ProcessedJSONObj: JsonObject; 
10
        var Handled: Boolean)
11
    begin
12
        // Nur Custom Processing Status behandeln
13
        if NewStatus <> NewStatus::"Custom Processing" then
14
            exit;
15
        
16
        // Als behandelt markieren, um Standard-Verarbeitung zu verhindern
17
        Handled := true;
18
        
19
        // Ihr benutzerdefiniertes Dokument erstellen
20
        CreateMyCustomDocument(Document, ProcessedJSONObj);
21
    end;
22
    
23
    local procedure CreateMyCustomDocument(
24
        var Document: Record "DXP Document"; 
25
        ProcessedJSON: JsonObject)
26
    var
27
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
28
        JsonHelper: Codeunit "DXP Json Helper";
29
        MyCustomHeader: Record "My Custom Document Header";
30
        MyCustomLine: Record "My Custom Document Line";
31
        LineJArray: JsonArray;
32
        LineJToken: JsonToken;
33
        LineJObj: JsonObject;
34
    begin
35
        // ═══════════════════════════════════════════════════════
36
        // 1. KOPF ERSTELLEN
37
        // ═══════════════════════════════════════════════════════
38
        
39
        MyCustomHeader.Init();
40
        MyCustomHeader."No." := '';  // Wird durch Nummernserie zugewiesen
41
        
42
        // Standard-Kopffelder lesen
43
        MyCustomHeader."Vendor No." := 
44
            JsonHelper.ValAsTxt(ProcessedJSON, CoreTokenMgt.GetVendorNoTok(), false);
45
        MyCustomHeader."Document Date" := 
46
            JsonHelper.ValAsDate(ProcessedJSON, CoreTokenMgt.GetDocDateTok(), false);
47
        MyCustomHeader."Document Reference" := 
48
            JsonHelper.ValAsTxt(ProcessedJSON, CoreTokenMgt.GetDocReferenceTok(), false);
49
        
50
        MyCustomHeader.Insert(true);
51
        
52
        // ═══════════════════════════════════════════════════════
53
        // 2. DIMENSIONEN VERARBEITEN (wenn Ihr Dokument diese unterstützt)
54
        // ═══════════════════════════════════════════════════════
55
        
56
        ProcessHeaderDimensions(ProcessedJSON, MyCustomHeader);
57
        
58
        // ═══════════════════════════════════════════════════════
59
        // 3. BENUTZERDEFINIERTE FELDER VERARBEITEN
60
        // ═══════════════════════════════════════════════════════
61
        
62
        ProcessCustomFields(ProcessedJSON, MyCustomHeader);
63
        
64
        // ═══════════════════════════════════════════════════════
65
        // 4. ZEILEN ERSTELLEN
66
        // ═══════════════════════════════════════════════════════
67
        
68
        LineJArray := JsonHelper.ReadJArrayFromObj(ProcessedJSON, CoreTokenMgt.GetLinesTok());
69
        
70
        foreach LineJToken in LineJArray do begin
71
            LineJObj := LineJToken.AsObject();
72
            
73
            MyCustomLine.Init();
74
            MyCustomLine."Document No." := MyCustomHeader."No.";
75
            MyCustomLine."Line No." := GetNextLineNo(MyCustomHeader."No.");
76
            
77
            // Zeilenfelder lesen
78
            MyCustomLine."Item No." := 
79
                JsonHelper.ValAsTxt(LineJObj, CoreTokenMgt.GetNoTok(), false);
80
            MyCustomLine.Description := 
81
                JsonHelper.ValAsTxt(LineJObj, CoreTokenMgt.GetDescriptionTok(), false);
82
            MyCustomLine.Quantity := 
83
                JsonHelper.ValAsDec(LineJObj, CoreTokenMgt.GetQtyTok(), false);
84
            MyCustomLine."Unit of Measure" := 
85
                JsonHelper.ValAsTxt(LineJObj, CoreTokenMgt.GetUoMTok(), false);
86
            
87
            MyCustomLine.Insert(true);
88
            
89
            // Zeilen-Dimensionen und benutzerdefinierte Felder verarbeiten, falls erforderlich
90
            ProcessLineDimensions(LineJObj, MyCustomLine);
91
            ProcessLineCustomFields(LineJObj, MyCustomLine);
92
        end;
93
        
94
        // ═══════════════════════════════════════════════════════
95
        // 5. CORE-DOKUMENTSTATUS AKTUALISIEREN
96
        // ═══════════════════════════════════════════════════════
97
        
98
        UpdateCoreDocument(Document, MyCustomHeader);
99
    end;
100
    
101
    local procedure ProcessHeaderDimensions(ProcessedJSON: JsonObject; var MyCustomHeader: Record "My Custom Document Header")
102
    var
103
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
104
        DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
105
        DimensionsJObj: JsonObject;
106
        DimSetID: Integer;
107
    begin
108
        // Dimensionen aus JSON lesen
109
        if ProcessedJSON.Contains(CoreTokenMgt.GetDimensionsTok()) then begin
110
            ProcessedJSON.Get(CoreTokenMgt.GetDimensionsTok(), DimensionsJObj);
111
            
112
            // In Dimensionssatz-ID konvertieren
113
            if DocTransferMgt.GetDimSetIdFromJsonObj(DimensionsJObj, DimSetID) then begin
114
                MyCustomHeader."Dimension Set ID" := DimSetID;
115
                MyCustomHeader.Modify(true);
116
            end;
117
        end;
118
    end;
119
    
120
    local procedure ProcessCustomFields(ProcessedJSON: JsonObject; var MyCustomHeader: Record "My Custom Document Header")
121
    var
122
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
123
        JsonHelper: Codeunit "DXP Json Helper";
124
        CustomFieldsJArray: JsonArray;
125
        CustomFieldJToken: JsonToken;
126
        CustomFieldJObj: JsonObject;
127
        FieldName: Text;
128
        FieldValue: Text;
129
    begin
130
        // Benutzerdefinierte Felder-Array lesen
131
        if not ProcessedJSON.Contains(CoreTokenMgt.GetCustomFieldsTok()) then
132
            exit;
133
            
134
        CustomFieldsJArray := JsonHelper.ReadJArrayFromObj(ProcessedJSON, CoreTokenMgt.GetCustomFieldsTok());
135
        
136
        foreach CustomFieldJToken in CustomFieldsJArray do begin
137
            CustomFieldJObj := CustomFieldJToken.AsObject();
138
            FieldName := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetNameTok(), false);
139
            FieldValue := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetValueTok(), false);
140
            
141
            // Zu Ihren benutzerdefinierten Feldern zuordnen
142
            case FieldName of
143
                'CustomerNo':
144
                    MyCustomHeader."Customer No." := CopyStr(FieldValue, 1, 20);
145
                'DeliveryTerms':
146
                    MyCustomHeader."Delivery Terms" := CopyStr(FieldValue, 1, 10);
147
                // Weitere Feldzuordnungen nach Bedarf hinzufügen
148
            end;
149
        end;
150
        
151
        MyCustomHeader.Modify(true);
152
    end;
153
    
154
    local procedure ProcessLineDimensions(LineJObj: JsonObject; var MyCustomLine: Record "My Custom Document Line")
155
    var
156
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
157
        DocTransferMgt: Codeunit "DXP Document Transfer Mgt.";
158
        DimensionsJObj: JsonObject;
159
        DimSetID: Integer;
160
    begin
161
        if LineJObj.Contains(CoreTokenMgt.GetDimensionsTok()) then begin
162
            LineJObj.Get(CoreTokenMgt.GetDimensionsTok(), DimensionsJObj);
163
            
164
            if DocTransferMgt.GetDimSetIdFromJsonObj(DimensionsJObj, DimSetID) then begin
165
                MyCustomLine."Dimension Set ID" := DimSetID;
166
                MyCustomLine.Modify(true);
167
            end;
168
        end;
169
    end;
170
    
171
    local procedure ProcessLineCustomFields(LineJObj: JsonObject; var MyCustomLine: Record "My Custom Document Line")
172
    var
173
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
174
        JsonHelper: Codeunit "DXP Json Helper";
175
        CustomFieldsJArray: JsonArray;
176
        CustomFieldJToken: JsonToken;
177
        CustomFieldJObj: JsonObject;
178
        FieldName: Text;
179
        FieldValue: Text;
180
    begin
181
        if not LineJObj.Contains(CoreTokenMgt.GetCustomFieldsTok()) then
182
            exit;
183
            
184
        CustomFieldsJArray := JsonHelper.ReadJArrayFromObj(LineJObj, CoreTokenMgt.GetCustomFieldsTok());
185
        
186
        foreach CustomFieldJToken in CustomFieldsJArray do begin
187
            CustomFieldJObj := CustomFieldJToken.AsObject();
188
            FieldName := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetNameTok(), false);
189
            FieldValue := JsonHelper.ValAsTxt(CustomFieldJObj, CoreTokenMgt.GetValueTok(), false);
190
            
191
            // Zu Ihren benutzerdefinierten Zeilenfeldern zuordnen
192
            case FieldName of
193
                'SerialNo':
194
                    MyCustomLine."Serial No." := CopyStr(FieldValue, 1, 50);
195
                // Weitere Feldzuordnungen hinzufügen
196
            end;
197
        end;
198
        
199
        MyCustomLine.Modify(true);
200
    end;
201
    
202
    local procedure UpdateCoreDocument(var Document: Record "DXP Document"; MyCustomHeader: Record "My Custom Document Header")
203
    var
204
        DocumentMgt: Codeunit "DXP Document Mgt.";
205
    begin
206
        // Core-Dokument aktualisieren, um es mit Ihrem erstellten Dokument zu verknüpfen
207
        Document.Status := Document.Status::Transferred;
208
        Document."Linked-to Record Id" := MyCustomHeader.RecordId;
209
        Document.Modify(true);
210
        
211
        // Optional: Anhänge von Core zu Ihrem Dokument übertragen
212
        TransferAttachments(Document, MyCustomHeader);
213
    end;
214
    
215
    local procedure TransferAttachments(Document: Record "DXP Document"; MyCustomHeader: Record "My Custom Document Header")
216
    var
217
        DocAttachment: Record "DXP Document Attachment";
218
        MyDocAttachment: Record "Document Attachment";
219
        InStr: InStream;
220
    begin
221
        DocAttachment.SetRange("Document No.", Document."No.");
222
        if DocAttachment.FindSet() then
223
            repeat
224
                MyDocAttachment.Init();
225
                MyDocAttachment.ID := 0;
226
                
227
                DocAttachment."File Content".CreateInStream(InStr);
228
                MyDocAttachment.SaveAttachmentFromStream(
229
                    InStr, 
230
                    MyCustomHeader.RecordId, 
231
                    DocAttachment."File Name");
232
            until DocAttachment.Next() = 0;
233
    end;
234
    
235
    local procedure GetNextLineNo(DocumentNo: Code[20]): Integer
236
    var
237
        MyCustomLine: Record "My Custom Document Line";
238
    begin
239
        MyCustomLine.SetRange("Document No.", DocumentNo);
240
        if MyCustomLine.FindLast() then
241
            exit(MyCustomLine."Line No." + 10000);
242
        exit(10000);
243
    end;
244
}
245

Wichtige Hilfs-Codeunits

CodeunitZweck
DXP Core Token Mgt.Stellt Token-Namen für JSON-Felder bereit (GetVendorNoTok(), GetDocDateTok(), usw.)
DXP Json HelperJSON-Parsing-Hilfsfunktionen (ValAsTxt(), ValAsDate(), ReadJArrayFromObj(), usw.)
DXP Document Transfer Mgt.Dimensionsverarbeitung, Metadatenübertragung, Behandlung benutzerdefinierter Felder
DXP Document Mgt.Kern-Dokumentenverwaltung (UpdateDocument(), UpdateDocumentStatus(), usw.)

Bei Fragen oder Unklarheiten wenden Sie sich bitte an die DEXPRO Solutions GmbH.