# Extension Entwicklung

In diesem Kapitel werden wichtige Integration Events und Beispiele aufgeführt, die bei der Entwicklung einer Extension für Breeze Interface helfen.  
  
Wichtig:  
Anpassungen dürfen nur durch entsprechend geschulte Berater/Entwickler durchgeführt werden. Diese befinden sich außerdem immer außerhalb des Standard-Supports durch DEXPRO.

# Leitfaden zur Implementierung einer individuellen Belegerstellung

## Überblick

Diese Dokumentation bietet eine Anleitung zur Implementierung benutzerdefinierter Dokumentenerstellungsprozesse unter Verwendung des Integration Event `OnDocumentCreation` im DEXPRO Core-Framework. Während die Standardimplementierung Einkaufsbelege (Tablelle 38,39) erstellt, zeigt dieser Leitfaden, wie Sie Ihre eigene Dokumentenerstellungslogik mithilfe der bereitgestellten JSON-Daten implementieren können.

### Voraussetzungen

Folgende Einstellung ist vor der Validierung eines Belegs in der [Dokumentenklassen Einrichtung](https://docs.squeeze.one/books/squeeze-for-dynamics-365-bc-de-de/page/dokumentenklassen-einrichtung "Dokumentenklassen Einrichtung") vorzunehmen:

- **Nächster Prozessschritt:** Breeze Interface
- **Zielvorlage:** Keine

[![image-1737634153644.png](https://docs.squeeze.one/uploads/images/gallery/2025-01/scaled-1680-/image-1737634153644.png)](https://docs.squeeze.one/uploads/images/gallery/2025-01/image-1737634153644.png)

Sie haben einen Beleg mit der App [DEXPRO Squeeze](https://docs.squeeze.one/books/dexpro-microsoft-dynamics-365-business-central-apps/chapter/dexpro-squeeze "DEXPRO Squeeze") validiert und in den nächsten Prozessschritt [Breeze Interface](https://docs.squeeze.one/books/dexpro-microsoft-dynamics-365-business-central-apps/chapter/dexpro-breeze-interface "DEXPRO Breeze Interface") übertragen? Dann sehen Sie diesen jetzt im [Breeze Interface](https://docs.squeeze.one/books/dexpro-microsoft-dynamics-365-business-central-apps/chapter/dexpro-breeze-interface "DEXPRO Breeze Interface") in einer Wartestellung (*WaitingForRetrieval*). An diesem Punkt besteht die Möglichkeit, den validierten Beleg in einen Genehmigungsworkflow zu überführen, um diesen nach erfolgter Genehmigung zurückzumelden und in den Prozess der Zielbelegerstellung zu übergeben - weitere Information zur Breeze Interface API finden sie [hier](https://docs.squeeze.one/books/breeze-interface-for-dynamics-365-bc-de-de/page/breeze-interface-api "Breeze Interface API").

[![image-1737637141572.png](https://docs.squeeze.one/uploads/images/gallery/2025-01/scaled-1680-/image-1737637141572.png)](https://docs.squeeze.one/uploads/images/gallery/2025-01/image-1737637141572.png)

Sobald Sie den Status des Breeze Belegs in "*Processed*" geändert haben, wird dieser an den [DEXPRO Core](https://docs.squeeze.one/books/dexpro-microsoft-dynamics-365-business-central-apps/chapter/dexpro-core "DEXPRO Core") zur weiteren Verarbeitung gemeldet - dies ist der [Integrationspunkt](#bkmrk-integrationspunkt), an dem Sie ansetzen müssen.

### <a id="bkmrk--1"></a>Integrationspunkt

Der zentrale Integrationspunkt ist das `OnDocumentCreation`-Ereignis in *Codeunit 70954599 “DXP Doc. Creation Def. Impl.”* in der App *DEXPRO Core*. Dieses Ereignis wird während der Dokumentenverarbeitung ausgelöst und ermöglicht die Implementierung einer benutzerdefinierten Dokumentenerstellungslogik.

### <a id="bkmrk--2"></a>Ereignis-Signatur

```PASCAL
[IntegrationEvent(false, false)]
local procedure OnDocumentCreation(JObject: JsonObject; var CreatedDocumentRecordId: RecordId)

```

### <a id="bkmrk--3"></a>Parameter

- `JObject`: Enthält die vollständigen JSON-Daten mit den Dokumentinformationen
- `CreatedDocumentRecordId`: Muss mit der RecordId des erstellten Dokuments gesetzt werden

## <a id="bkmrk--4"></a>Implementierungsleitfaden

### <a id="bkmrk--5"></a>Schritt 1: Subscriber-Codeunit erstellen

Zunächst erstellen Sie eine Codeunit, die das OnDocumentCreation-Ereignis abonniert:

```PASCAL
codeunit 50100 "Custom Document Creation"
{
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP Doc. Creation Def. Impl.", 'OnDocumentCreation', '', false, false)]
    local procedure OnDocumentCreation(JObject: JsonObject; var CreatedDocumentRecordId: RecordId)
    begin
        // Your implementation here
        CreateCustomDocument(JObject, CreatedDocumentRecordId);
    end;
}

```

### <a id="bkmrk--6"></a>Schritt 2: Dokumentenerstellungslogik implementieren

Hier ein Beispiel für die Implementierung der benutzerdefinierten Dokumentenerstellung:

```PASCAL
local procedure CreateCustomDocument(JObject: JsonObject; var CreatedDocumentRecordId: RecordId)
var
    CustomHeader: Record "Custom Document Header";
    CustomLine: Record "Custom Document Line";
    JsonHelper: Codeunit "DXP Json Helper";
    HeaderJObject: JsonObject;
    LinesJArray: JsonArray;
    LineJToken: JsonToken;
    LineNo: Integer;
begin
    // 1. Create Header
    CustomHeader.Init();
    CustomHeader."Document Type" := GetDocumentType(JObject);
    CustomHeader."Vendor No." := CopyStr(JsonHelper.ValAsTxt(JObject, 'vendorNo', true), 1, MaxStrLen(CustomHeader."Vendor No."));
    CustomHeader."Document Date" := JsonHelper.ValAsDate(JObject, 'docDate', true);
    CustomHeader."Posting Date" := JsonHelper.ValAsDate(JObject, 'postingDate', true);
    CustomHeader."Document Reference" := CopyStr(JsonHelper.ValAsTxt(JObject, 'docReference', true), 1, MaxStrLen(CustomHeader."Document Reference"));
    CustomHeader.Insert(true);

    // 2. Process Lines
    LinesJArray := JsonHelper.ReadJArrayFromObj(JObject, 'lines');
    LineNo := 10000;
    
    foreach LineJToken in LinesJArray do begin
        CustomLine.Init();
        CustomLine."Document No." := CustomHeader."No.";
        CustomLine."Line No." := LineNo;
        CustomLine."Item No." := CopyStr(JsonHelper.ValAsTxt(LineJToken.AsObject(), 'no', true), 1, MaxStrLen(CustomLine."Item No."));
        CustomLine.Quantity := JsonHelper.ValAsDec(LineJToken.AsObject(), 'qty', true);
        CustomLine."Unit Price" := JsonHelper.ValAsDec(LineJToken.AsObject(), 'unitPrice', true);
        CustomLine.Insert(true);
        
        LineNo += 10000;
    end;

    CreatedDocumentRecordId := CustomHeader.RecordId;
end;

```

## <a id="bkmrk--7"></a>JSON-Struktur

Die JSON-Eingabe folgt dieser Struktur:

```JSON
{
   "type":"Invoice",
   "vendorNo":"K00170",
   "iban":"DE58520503530052599766",
   "vatRegNo":"DE540026784",
   "barcode":"123456789",
   "docDate":"2023-07-13",
   "serviceDate":"2023-07-13",
   "postingDate":"2025-01-23",
   "postingDesc":"Die ist eine Buchungsbeschreibung.",
   "docReference":"R308154",
   "orderNo":"B23106029",
   "netAmount":7894.71,
   "netAmount2":0.0,
   "netAmount3":0.0,
   "taxRate":19.0,
   "taxRate2":0.0,
   "taxRate3":0.0,
   "taxAmount":1499.99,
   "taxAmount2":0.0,
   "taxAmount3":0.0,
   "totalAmount":9394.7,
   "currency":"EUR",
   "assignedTo":"BERND.FEDDERSEN",
   "note":"Die ist eine Bemerkung!",
   "dimensions":{
      "ABTEILUNG":"PROD",
      "EINKÄUFER":"BF",
      "KOSTENTRÄGER":"IT"
   },
   "dimensionSetID":27,
   "customFields":{
      "docClass":"DXP Invoice / Credit Memo",
      "namesAndValues":[
         {
            "name":"Customer_No",
            "value":"01121212"
         },
         {
            "name":"Custom_Date",
            "value":"2025-01-26"
         }
      ]
   },
   "orderMatchDifference":"false",
   "lines":[
      {
         "orderNo":"B23106029",
         "orderLineNo":10000,
         "receiptNo":"ELIEF107004",
         "receiptLineNo":10000,
         "vendorItemNo":"",
         "type":"Item",
         "no":"90002",
         "description":"JogiTek G 1337 Gaming-Headset",
         "qty":17.0,
         "uom":"STÜCK",
         "unitPrice":99.99,
         "lineDisc":0.0,
         "netAmount":1699.83,
         "totalAmount":2022.8,
         "taxRate":19.0,
         "vatBusPostingGroup":"INLAND",
         "vatProdPostingGroup":"MWST.19",
         "dimensions":{
            "ABTEILUNG":"PROD",
            "BEREICH":"30",
            "EINKÄUFER":"BF",
            "KOSTENTRÄGER":"IT",
            "VERKAUFSKAMPAGNE":"WINTER"
         },
         "dimensionSetID":53,
         "genProdPostingGroup":"HANDEL",
         "genBusPostingGroup":"INLAND",
         "deferralCode":"",
         "quantityDifference":"false",
         "unitPriceDifference":"false",
         "discountDifference":"false",
         "receiptDateDifference":"false",
         "customFields":{
            "docClass":"DXP Invoice / Credit Memo",
            "namesAndValues":[
               {
                  "name":"Custom_Field_1",
                  "value":"Text in Zeile 10000"
               },
               {
                  "name":"Custom_Field_2",
                  "value":"2025-01-31"
               }
            ]
         }
      },
      {
         "orderNo":"B23106029",
         "orderLineNo":30000,
         "receiptNo":"ELIEF107004",
         "receiptLineNo":30000,
         "vendorItemNo":"",
         "type":"Item",
         "no":"90005",
         "description":"Sumsing Galaxy 23",
         "qty":12.0,
         "uom":"STÜCK",
         "unitPrice":349.99,
         "lineDisc":0.0,
         "netAmount":4199.88,
         "totalAmount":4997.86,
         "taxRate":19.0,
         "vatBusPostingGroup":"INLAND",
         "vatProdPostingGroup":"MWST.19",
         "dimensions":{
            "ABTEILUNG":"PROD",
            "BEREICH":"50",
            "EINKÄUFER":"BF",
            "KOSTENTRÄGER":"IT",
            "VERKAUFSKAMPAGNE":"WINTER"
         },
         "dimensionSetID":55,
         "genProdPostingGroup":"HANDEL",
         "genBusPostingGroup":"INLAND",
         "deferralCode":"",
         "quantityDifference":"false",
         "unitPriceDifference":"false",
         "discountDifference":"false",
         "receiptDateDifference":"false",
         "customFields":{
            "docClass":"DXP Invoice / Credit Memo",
            "namesAndValues":[
               {
                  "name":"Custom_Field_1",
                  "value":"Text in Zeile 20000"
               },
               {
                  "name":"Custom_Field_2",
                  "value":"2025-01-30"
               }
            ]
         }
      },
      {
         "orderNo":"B23106029",
         "orderLineNo":20000,
         "receiptNo":"ELIEF107004",
         "receiptLineNo":20000,
         "vendorItemNo":"",
         "type":"Item",
         "no":"90000",
         "description":"Y-Phone Ultra Pro 23",
         "qty":5.0,
         "uom":"STÜCK",
         "unitPrice":399.0,
         "lineDisc":0.0,
         "netAmount":1995.0,
         "totalAmount":2374.05,
         "taxRate":19.0,
         "vatBusPostingGroup":"INLAND",
         "vatProdPostingGroup":"MWST.19",
         "dimensions":{
            "ABTEILUNG":"PROD",
            "BEREICH":"70",
            "EINKÄUFER":"BF",
            "KOSTENTRÄGER":"IT",
            "VERKÄUFER":"JH",
            "VERKAUFSKAMPAGNE":"WINTER"
         },
         "dimensionSetID":58,
         "genProdPostingGroup":"HANDEL",
         "genBusPostingGroup":"INLAND",
         "deferralCode":"",
         "quantityDifference":"false",
         "unitPriceDifference":"false",
         "discountDifference":"false",
         "receiptDateDifference":"false",
         "customFields":{
            "docClass":"DXP Invoice / Credit Memo",
            "namesAndValues":[
               {
                  "name":"Custom_Field_1",
                  "value":"Text in Zeile 30000"
               },
               {
                  "name":"Custom_Field_2",
                  "value":"2025-01-29"
               }
            ]
         }
      }
   ]
}
```

## <a id="bkmrk--8"></a>Best practice

1. **Fehlerbehandlung**: Implementieren Sie eine ordnungsgemäße Fehlerbehandlung für JSON-Parsing und Datenbankoperationen:

```PASCAL
local procedure CreateCustomDocument(JObject: JsonObject; var CreatedDocumentRecordId: RecordId)
var
    CustomHeader: Record "Custom Document Header";
begin
    if not DoesJsonHaveRequiredFields(JObject) then
        Error('Required fields are missing in the JSON payload');
        
    if not TryCreateCustomHeader(JObject, CustomHeader) then
        Error('Failed to create document header');
        
    // ... rest of the implementation
end;

```

2. **Validierung**: Implementieren Sie eine ordnungsgemäße Validierung vor der Dokumentenerstellung:

```PASCAL
local procedure ValidateDocument(JObject: JsonObject): Boolean
var
    Vendor: Record Vendor;
    VendorNo: Code[20];
begin
    VendorNo := CopyStr(JsonHelper.ValAsTxt(JObject, 'vendorNo', true), 1, MaxStrLen(VendorNo));
    if not Vendor.Get(VendorNo) then
        Error('Vendor %1 does not exist', VendorNo);
    // Add more validation as needed
    exit(true);
end;

```

## <a id="bkmrk--9"></a>Häufige Szenarien

### <a id="bkmrk--10"></a>Szenario 1: Verschiedene Dokumenttypen erstellen

```PASCAL
local procedure GetDocumentType(JObject: JsonObject): Enum "Custom Document Type"
var
    DocType: Text;
begin
    DocType := JsonHelper.ValAsTxt(JObject, 'type', true);
    case DocType of
        'Invoice':
            exit("Custom Document Type"::Invoice);
        'CreditMemo':
            exit("Custom Document Type"::"Credit Memo");
        else
            Error('Unknown document type: %1', DocType);
    end;
end;

```

### <a id="bkmrk--11"></a>Szenario 2: Benutzerdefinierte Felder verarbeiten

```PASCAL
local procedure ProcessCustomFields(JObject: JsonObject; var CustomDoc: Record "Custom Document Header")
var
    CustomFieldsObj: JsonObject;
    CustomFieldsArr: JsonArray;
    FieldToken: JsonToken;
begin
    if not JsonHelper.TokenExists(JObject, 'customFields') then
        exit;
        
    CustomFieldsObj := JsonHelper.ReadJObjectFromObj(JObject, 'customFields');
    CustomFieldsArr := JsonHelper.ReadJArrayFromObj(CustomFieldsObj, 'namesAndValues');
    
    foreach FieldToken in CustomFieldsArr do
        ProcessCustomField(FieldToken.AsObject(), CustomDoc);
end;

```

## <a id="bkmrk--12"></a>Fehlerbehebung

1. **RecordId ist leer**: Stellen Sie sicher, dass Sie den CreatedDocumentRecordId-Parameter setzen:

```PASCAL
CreatedDocumentRecordId := CustomHeader.RecordId;

```

2. **JSON-Parsing-Fehler**: Verwenden Sie die JsonHelper-Funktionen für sicheres Parsing:

```PASCAL
if not JsonHelper.TokenExists(JObject, 'vendorNo') then
    Error('Vendor number is missing in JSON');

```

3. **Datenvalidierung**: Implementieren Sie eine ordnungsgemäße Datenvalidierung:

```PASCAL
if JsonHelper.ValAsDec(LineJToken.AsObject(), 'qty', true) <= 0 then
    Error('Quantity must be greater than 0');

```

# Eigene Zielvorlage entwickeln

Diese Seite richtet sich an Entwickler und Partner, die Breeze Interface um eine **eigene Zielvorlage** (Target Template) erweitern wollen. Sie beschreibt am durchgehenden Beispiel „Rechnung mit Bestellbezug“, wie ein Beleg statt der voreingestellten Zielvorlage eine eigene erhält und welche Verarbeitung beim Setzen des Status **Processed** ausgeführt wird.

<p class="callout info">Das Beispiel: Eine Rechnung kommt über Squeeze herein und wird wie gewohnt validiert. Ist im Belegkopf eine Bestellnummer eingetragen, soll *nicht* wie im Standard eine Einkaufsrechnung erstellt werden. Stattdessen soll die im Kopf hinterlegte Bestellung gebucht werden.</p>

## Welcher Weg ist der richtige?

Für eine eigene Belegerstellung gibt es zwei Wege. Sie schließen einander aus – wählen Sie vor Beginn den passenden:

<table id="bkmrk-eigene-zielvorlage-%28"> <thead> <tr><th></th><th>Eigene Zielvorlage (diese Seite)</th><th>Ereignis `OnDocumentCreation`</th></tr> </thead> <tbody> <tr><td>Einrichtung Zielvorlage</td><td>Ihre eigene Zielvorlage</td><td>**Keine**</td></tr> <tr><td>Plausibilitätsprüfung durch Breeze</td><td>ja, mit den Schaltern der Zielvorlagen-Einrichtung</td><td>nein</td></tr> <tr><td>Mehrere Belegarten parallel</td><td>ja, eine Zielvorlage je Fall</td><td>nur eine Implementierung für alle Belege</td></tr> <tr><td>Geeignet für</td><td>Standard-Einkaufsbelege abweichend behandeln – etwa eine Bestellung buchen statt eine Rechnung anzulegen</td><td>Belege in vollständig eigene Tabellen schreiben</td></tr> </tbody></table>

Wollen Sie in eigene Tabellen schreiben und benötigen die Prüfungen von Breeze nicht, folgen Sie stattdessen der Seite **Leitfaden zur Implementierung einer individuellen Belegerstellung**. Für das hier beschriebene Beispiel ist dieser Weg nicht geeignet: Er setzt die Zielvorlage **Keine** voraus und umgeht damit die Plausibilitätsprüfung, die eine Rechnung mit Bestellbezug gerade braucht.

## Der Standardablauf

Ein Beleg durchläuft von Squeeze bis zum Zielbeleg in Business Central diese Stationen:

1. Squeeze übergibt den Beleg an Core. Core legt einen Datensatz in der Tabelle `DXP Document` an.
2. Core ermittelt über die **Dokumentenklasse** (`DXP Document Class`) den nächsten Prozessschritt. Steht dieser auf **Breeze Interface**, wird ein Breeze-Beleg (`DXP BRZ IF Document`) erzeugt.
3. Beim Anlegen erhält der Breeze-Beleg seine **Zielvorlage** aus der Einrichtung der Dokumentenklasse – Feld **Zielvorlage** auf der Seite **Dokumentenklassen-Einrichtung**.
4. Der Beleg wird im externen Workflow bearbeitet und kommt mit dem Status **Processed** zurück.
5. Breeze Interface löst daraufhin die zur Zielvorlage hinterlegte Implementierung aus. Diese prüft den Beleg auf Plausibilität und übergibt ihn an Core, das den Zielbeleg erzeugt.

Technisch ist die Zielvorlage ein Enum, das ein Interface implementiert:

- `DXP Breeze IF Target Template` – das Enum der Zielvorlagen, `Extensible = true`.
- `DXP BRZIF IDocument Processing` – das Interface, das jede Zielvorlage implementiert. Es besitzt genau eine Methode:   
    `procedure ProcessDocument(var BREEZEDoc: Record "DXP BRZ IF Document"; JObject: JsonObject)`

Im Auslieferungszustand sind diese Zielvorlagen enthalten:

<table id="bkmrk-wertzielvorlageimple"> <thead> <tr><th>Wert</th><th>Zielvorlage</th><th>Implementierung</th></tr> </thead> <tbody> <tr><td>0</td><td>Keine (None)</td><td>`DXP BRZ Default Processing`</td></tr> <tr><td>1</td><td>Einkaufsbeleg (Purchase Document)</td><td>`DXP BRZ IF PInv/Crdt Memo Proc`</td></tr> <tr><td>2</td><td>Einkaufsbestellung (Purchase Order)</td><td>`DXP BRZ IF Purch. Order Proc.`</td></tr> <tr><td>3</td><td>Auftragsbestätigung (Order Confirmation)</td><td>`DXP BRZ IF Order Conf. Proc.`</td></tr> <tr><td>4</td><td>Lieferschein (Delivery Note)</td><td>`DXP BRZ IF Del. Note Proc.`</td></tr> </tbody></table>

{add screenshot of Dokumentenklassen-Einrichtung here}

## Voraussetzungen

- Eine eigene Extension mit Abhängigkeit auf **DEXPRO Breeze Interface** (App-Id `7c431886-108e-44c3-9328-30e2b93edfa6`) und – über `propagateDependencies` mitgeliefert – auf **DEXPRO Core**.
- Ein eigener Objekt-ID-Bereich. Verwenden Sie **nicht** den Bereich von Breeze Interface (70954950–70954969) oder Core (70954575–70954624).
- Ein eigener Objektnamen-Affix, den Ihre `AppSourceCop.json` vorschreibt.

<p class="callout warning">Verwenden Sie für Ihre Objekte niemals das Affix `DXP`. Es ist für die DEXPRO-Apps reserviert. In den Codebeispielen dieser Seite steht `XYZ` stellvertretend für Ihr eigenes Affix.</p>

## Schritt 1 – Zielvorlage als Enum-Erweiterung anlegen

Das Enum `DXP Breeze IF Target Template` ist erweiterbar. Legen Sie einen neuen Wert an und verweisen Sie mit `Implementation` auf Ihre eigene Codeunit:

```
enumextension 50100 "XYZ Target Template Ext." extends "DXP Breeze IF Target Template"
{
    value(50100; "XYZ Post Purchase Order")
    {
        Caption = 'Bestellung buchen';
        Implementation = "DXP BRZIF IDocument Processing" = "XYZ Post Purch. Order Proc.";
    }
}
```

<p class="callout warning">Der Enum-Wert wird auf dem Breeze-Beleg und auf dem Core-Beleg gespeichert. Ändern Sie die Nummer nach dem ersten Produktiveinsatz nicht mehr – bereits gespeicherte Belege würden sonst auf eine andere Zielvorlage zeigen.</p>

## Schritt 2 – Die Standardzielvorlage überschreiben

Die Zielvorlage wird beim Anlegen des Breeze-Belegs aus der Dokumentenklassen-Einrichtung gelesen. Um sie fallabhängig zu übersteuern, abonnieren Sie das Ereignis `OnAfterFillDocumentInfo` der Codeunit `DXP BRZ IF Document Mgt.`. Es wird gerufen, während der Breeze-Beleg aus dem JSON gefüllt wird – also bevor er eingefügt ist:

```
codeunit 50100 "XYZ Breeze Doc. Subscribers"
{
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP BRZ IF Document Mgt.", 'OnAfterFillDocumentInfo', '', false, false)]
    local procedure SetTargetTemplateOnOrderReference(var BrzIfDoc: Record "DXP BRZ IF Document"; JsonData: JsonObject)
    var
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
        JsonHelper: Codeunit "DXP Json Helper";
        OrderNo: Code[20];
    begin
        // Nur Belege umleiten, die im Standard zur Einkaufsrechnung fuehren.
        if BrzIfDoc."Target Template" <> BrzIfDoc."Target Template"::"Purchase Document" then
            exit;

        OrderNo := CopyStr(JsonHelper.ValAsTxt(JsonData, CoreTokenMgt.GetOrderNoTok(), false), 1, MaxStrLen(OrderNo));
        if OrderNo = '' then
            exit;

        BrzIfDoc."Target Template" := BrzIfDoc."Target Template"::"XYZ Post Purchase Order";
    end;
}
```

Die Bestellnummer steht im Belegkopf-JSON unter dem Token `orderNo`. Lesen Sie sie ausschließlich über `DXP Core Token Mgt.` aus – die Token-Namen sind dort zentral gepflegt.

<p class="callout info">Das zweite Argument von `ValAsTxt` ist `EnsureSuccess`. Übergeben Sie hier `false`: Die Bestellnummer ist ein optionales Feld, und bei `true` würde ein fehlendes Token einen Laufzeitfehler auslösen.</p>

### Die Zielvorlage im Core-Beleg nachziehen

Core führt im Feld **Breeze Interface Zielvorlage** der Tabelle `DXP Document` eine Kopie der Zielvorlage mit. Setzt Ihr Abonnent die Zielvorlage um, aktualisieren Sie dieses Feld mit – sonst zeigt der Core-Beleg weiter die alte Vorlage an. Ihre eigene Verarbeitung aus Schritt 3 erledigt das (siehe `CoreDoc.Validate("DXP Breeze IF Target Template", ...)` im Beispiel unten).

## Schritt 3 – Die Verarbeitung implementieren

Wird der Breeze-Beleg auf **Processed** gesetzt, ruft Breeze Interface die zur Zielvorlage hinterlegte Implementierung auf:

```
IDocumentProcessing := Rec."Target Template";
IDocumentProcessing.ProcessDocument(Rec, JsonHelper.JObjectFromBlob(Rec.RecordId, Rec.FieldNo(JSON)));
```

Ihre Codeunit implementiert dafür `DXP BRZIF IDocument Processing`. Sie ist verantwortlich für:

- **Prüfen** des Belegs – im Fehlerfall den Breeze-Beleg auf Status **Error** setzen und die Meldungen in das JSON schreiben.
- **Übergeben** an Core über `DXP Document Mgt.UpdateDocument`, wenn der Beleg gültig ist.
- **Löschen** des Breeze-Belegs nach erfolgreicher Übergabe. Der Core-Beleg bleibt als Nachweis bestehen.

```
codeunit 50101 "XYZ Post Purch. Order Proc." implements "DXP BRZIF IDocument Processing"
{
    procedure ProcessDocument(var BREEZEDoc: Record "DXP BRZ IF Document"; JObject: JsonObject)
    var
        CoreDoc: Record "DXP Document";
        CoreDocMgt: Codeunit "DXP Document Mgt.";
        ValidDoc: Boolean;
    begin
        ValidDoc := CheckDocument(JObject);

        if not ValidDoc then begin
            BREEZEDoc.Validate(Status, "DXP Breeze IF Status"::Error);
            BREEZEDoc.Modify(false);
            exit;
        end;

        CoreDocMgt.UpdateDocument(
            BREEZEDoc."Core Document No.",
            "DXP Document Status"::Transferred,
            "DXP Target Document Process"::"XYZ Post Purchase Order",
            JObject);

        CoreDoc.Get(BREEZEDoc."Core Document No.");
        CoreDoc.Validate("DXP Breeze IF Target Template", BREEZEDoc."Target Template");
        CoreDoc.Modify(true);

        BREEZEDoc.Delete(true);
    end;
}
```

<p class="callout info">Als Vorlage für Plausibilitätsprüfungen dient die ausgelieferte Codeunit `DXP BRZ IF PInv/Crdt Memo Proc`. Nutzen Sie `DXP Plausiblity Check Mgt.` für die Prüfungen und `DXP BRZ IF Target Templ. Mgt.`, um die Einrichtung Ihrer Zielvorlage zu lesen – damit greifen die Schalter **Betragsprüfung deaktivieren** und **Buchungsdatum nicht prüfen** auch für Ihre Vorlage.</p>

## Schritt 4 – Den Zielbeleg in Core erzeugen

Die Zielvorlage in Breeze bestimmt *welche Prüfung* läuft. *Welcher Zielbeleg* entsteht, entscheidet ein zweites Enum in Core: `DXP Target Document Process`, ebenfalls `Extensible = true`, mit dem Interface `DXP IDocument Processing`.

<p class="callout warning">Die beiden Enums sind getrennt und müssen beide erweitert werden. Die Breeze-Zielvorlage wählt die Prüfung, der Core-Zielbelegprozess die Belegerstellung. Der Wert wird von Ihrer Verarbeitung aus Schritt 3 an `UpdateDocument` übergeben.</p>

```
enumextension 50101 "XYZ Target Doc. Process Ext." extends "DXP Target Document Process"
{
    value(50100; "XYZ Post Purchase Order")
    {
        Caption = 'Bestellung buchen';
        Implementation = "DXP IDocument Processing" = "XYZ Post P. Order Creation";
    }
}
```

Das Interface `DXP IDocument Processing` hat eine Methode, die die `RecordId` des erzeugten Belegs zurückgibt. Core speichert sie im Feld **Verknüpfte Datensatz-ID** des Core-Belegs:

```
procedure ProcessStandardDocument(JObject: JsonObject): RecordId
```

Ihre Implementierung liest die Bestellnummer aus dem Kopf, holt die Bestellung und bucht sie:

```
codeunit 50102 "XYZ Post P. Order Creation" implements "DXP IDocument Processing"
{
    procedure ProcessStandardDocument(JObject: JsonObject): RecordId
    var
        PurchaseHeader: Record "Purchase Header";
        PurchInvHeader: Record "Purch. Inv. Header";
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
        JsonHelper: Codeunit "DXP Json Helper";
        TargetDocumentMgt: Codeunit "DXP Target Document Mgt.";
        PurchPost: Codeunit "Purch.-Post";
        DocRecRef: RecordRef;
        OrderNo: Code[20];
        VendorNo: Code[20];
    begin
        OrderNo := CopyStr(JsonHelper.ValAsTxt(JObject, CoreTokenMgt.GetOrderNoTok(), true), 1, MaxStrLen(OrderNo));
        VendorNo := CopyStr(JsonHelper.ValAsTxt(JObject, CoreTokenMgt.GetVendorNoTok(), true), 1, MaxStrLen(VendorNo));

        PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Order);
        PurchaseHeader.SetRange("No.", OrderNo);
        PurchaseHeader.SetRange("Buy-from Vendor No.", VendorNo);
        PurchaseHeader.FindFirst();

        // Rechnungsdaten aus dem JSON in die Bestellung uebernehmen
        // (Belegdatum, Buchungsdatum, Externe Belegnummer, zu berechnende Mengen)
        UpdatePurchaseHeaderFromJson(JObject, PurchaseHeader);

        PurchPost.SetSuppressCommit(true);
        PurchPost.Run(PurchaseHeader);

        DocRecRef.Get(PurchaseHeader.RecordId());
        TargetDocumentMgt.SetProcessedCompletely(DocRecRef);

        PurchInvHeader.SetRange("Order No.", OrderNo);
        if PurchInvHeader.FindLast() then
            exit(PurchInvHeader.RecordId());

        exit(PurchaseHeader.RecordId());
    end;
}
```

<p class="callout warning">Geben Sie niemals eine leere `RecordId` zurück. Core prüft den Rückgabewert; bleibt er leer, bricht die Verarbeitung mit einer Fehlermeldung ab.</p>

### Vollständig verarbeitet kennzeichnen

Core erweitert die Tabelle **Einkaufskopf** um das Feld **Vollständig verarbeitet**. Setzen Sie es über `DXP Target Document Mgt.SetProcessedCompletely`, sobald der Beleg fertig verarbeitet ist. Die ausgelieferten Implementierungen tun das ebenfalls; das Feld steuert die Anzeige und die nachgelagerte Verarbeitung.

### Wenn die Bestellung gebucht wird

Beim Buchen entsteht ein neuer Beleg – die gebuchte Einkaufsrechnung –, während die Bestellung je nach Restmenge gelöscht wird. Verweisen Sie deshalb im Rückgabewert auf den *gebuchten* Beleg, wie im Beispiel oben. Zeigt **Verknüpfte Datensatz-ID** auf eine gelöschte Bestellung, läuft der Absprung vom Core-Beleg ins Leere.

## Die Einrichtung der Zielvorlage

Zu jeder Zielvorlage gehört ein Datensatz in der Tabelle `DXP BRZ IF Target Templ. Setup`, sichtbar auf der Seite **Zielvorlagen-Einrichtung**. Er wird beim ersten Zugriff automatisch angelegt. Diese Schalter stehen zur Verfügung:

- **Betragsprüfung deaktivieren** – unterdrückt den Abgleich von Kopf- und Zeilenbeträgen.
- **Buchungsdatum nicht prüfen** – unterdrückt die Prüfung des Buchungsdatums.
- **Gesperrten Kreditoren (Zahlung) ignorieren** – lässt Belege gesperrter Kreditoren zu.
- **Nicht freigeben** – unterdrückt die automatische Freigabe des Zielbelegs.

Sollen für Ihre Zielvorlage andere Vorgabewerte gelten als die leeren Standardwerte, setzen Sie sie beim Anlegen. Die Codeunit `DXP BRZ IF Target Templ. Mgt.` tut das für die ausgelieferten Vorlagen; für eigene Vorlagen abonnieren Sie den `OnInsert`-Trigger der Tabelle.

{add screenshot of Zielvorlagen-Einrichtung here}

## Checkliste

<table id="bkmrk-schrittobjektzweck-1"> <thead> <tr><th>Schritt</th><th>Objekt</th><th>Zweck</th></tr> </thead> <tbody> <tr><td>1</td><td>`enumextension` auf `DXP Breeze IF Target Template`</td><td>Die eigene Zielvorlage bekannt machen</td></tr> <tr><td>2</td><td>Abonnent auf `OnAfterFillDocumentInfo`</td><td>Die Standardzielvorlage fallabhängig überschreiben</td></tr> <tr><td>3</td><td>`codeunit` implements `DXP BRZIF IDocument Processing`</td><td>Prüfen und an Core übergeben</td></tr> <tr><td>4</td><td>`enumextension` auf `DXP Target Document Process`</td><td>Den eigenen Zielbelegprozess bekannt machen</td></tr> <tr><td>5</td><td>`codeunit` implements `DXP IDocument Processing`</td><td>Den Zielbeleg erzeugen – hier: die Bestellung buchen</td></tr> <tr><td>6</td><td>**Dokumentenklassen-Einrichtung**</td><td>Prüfen, dass der nächste Prozessschritt auf **Breeze Interface** steht</td></tr> </tbody></table>

## Fehlersuche

<table id="bkmrk-beobachtungursache-d"> <thead> <tr><th>Beobachtung</th><th>Ursache</th></tr> </thead> <tbody> <tr><td>Der Beleg behält die alte Zielvorlage.</td><td>Der Abonnent aus Schritt 2 greift nicht. Prüfen Sie, ob die Dokumentenklasse tatsächlich auf die Zielvorlage **Einkaufsbeleg** zeigt und ob das Token `orderNo` im Kopf-JSON gefüllt ist.</td></tr> <tr><td>Beim Setzen auf **Processed** läuft die Standardverarbeitung.</td><td>Der `Implementation`-Verweis im Enum fehlt. Ohne ihn greift die `DefaultImplementation` des Enums, also `DXP BRZ Default Processing`.</td></tr> <tr><td>Meldung *Document creation failed. RecordId is empty.*</td><td>Ihre `ProcessStandardDocument`-Implementierung hat keine `RecordId` zurückgegeben.</td></tr> <tr><td>Der Absprung vom Core-Beleg öffnet nichts.</td><td>**Verknüpfte Datensatz-ID** zeigt auf einen gelöschten Beleg – geben Sie den gebuchten Beleg zurück, nicht die Bestellung.</td></tr> <tr><td>Der Beleg steht auf **Error**, ohne dass eine Meldung erscheint.</td><td>Ihre Verarbeitung setzt den Status, schreibt aber keine Prüfmeldungen in das JSON. Nutzen Sie `DXP Document Transfer Mgt.AddErrorsToJson`.</td></tr> </tbody></table>

## Verwandte Themen

- **Zielvorlagen-Einrichtung** – die Schalter je Zielvorlage
- **Dokumentenklassen-Einrichtung** – Zuordnung von Dokumentenklasse, nächstem Prozessschritt und Zielvorlage
- **Breeze Belege** – die Belegliste und ihre Status
- **Leitfaden zur Implementierung einer individuellen Belegerstellung** – der alternative Weg über `OnDocumentCreation` für eigene Belegtabellen
- **Breeze Interface API** – Rückmeldung des Belegs aus dem externen Workflow

# Eigene Zielvorlage entwickeln

Diese Seite richtet sich an Entwickler und Partner, die Breeze Interface um eine **eigene Zielvorlage** (Target Template) erweitern wollen. Sie beschreibt am durchgehenden Beispiel „Rechnung mit Bestellbezug“, wie ein Beleg statt der voreingestellten Zielvorlage eine eigene erhält und welche Verarbeitung beim Setzen des Status **Processed** ausgeführt wird.

<p class="callout info">Das Beispiel: Eine Rechnung kommt über Squeeze herein und wird wie gewohnt validiert. Ist im Belegkopf eine Bestellnummer eingetragen, soll *nicht* wie im Standard eine Einkaufsrechnung erstellt werden. Stattdessen soll die im Kopf hinterlegte Bestellung gebucht werden.</p>

## Welcher Weg ist der richtige?

Für eine eigene Belegerstellung gibt es zwei Wege. Sie schließen einander aus – wählen Sie vor Beginn den passenden:

<table id="bkmrk-eigene-zielvorlage-%28"><thead><tr><th> </th><th>Eigene Zielvorlage (diese Seite)</th><th>Ereignis `OnDocumentCreation`</th></tr></thead><tbody><tr><td>Einrichtung Zielvorlage</td><td>Ihre eigene Zielvorlage</td><td>**Keine**</td></tr><tr><td>Plausibilitätsprüfung durch Breeze</td><td>ja, mit den Schaltern der Zielvorlagen-Einrichtung</td><td>nein</td></tr><tr><td>Mehrere Belegarten parallel</td><td>ja, eine Zielvorlage je Fall</td><td>nur eine Implementierung für alle Belege</td></tr><tr><td>Geeignet für</td><td>Standard-Einkaufsbelege abweichend behandeln – etwa eine Bestellung buchen statt eine Rechnung anzulegen</td><td>Belege in vollständig eigene Tabellen schreiben</td></tr></tbody></table>

Wollen Sie in eigene Tabellen schreiben und benötigen die Prüfungen von Breeze nicht, folgen Sie stattdessen der Seite **Leitfaden zur Implementierung einer individuellen Belegerstellung**. Für das hier beschriebene Beispiel ist dieser Weg nicht geeignet: Er setzt die Zielvorlage **Keine** voraus und umgeht damit die Plausibilitätsprüfung, die eine Rechnung mit Bestellbezug gerade braucht.

## Der Standardablauf

Ein Beleg durchläuft von Squeeze bis zum Zielbeleg in Business Central diese Stationen:

1. Squeeze übergibt den Beleg an Core. Core legt einen Datensatz in der Tabelle `DXP Document` an.
2. Core ermittelt über die **Dokumentenklasse** (`DXP Document Class`) den nächsten Prozessschritt. Steht dieser auf **Breeze Interface**, wird ein Breeze-Beleg (`DXP BRZ IF Document`) erzeugt.
3. Beim Anlegen erhält der Breeze-Beleg seine **Zielvorlage** aus der Einrichtung der Dokumentenklasse – Feld **Zielvorlage** auf der Seite **Dokumentenklassen-Einrichtung**.
4. Der Beleg wird im externen Workflow bearbeitet und kommt mit dem Status **Processed** zurück.
5. Breeze Interface löst daraufhin die zur Zielvorlage hinterlegte Implementierung aus. Diese prüft den Beleg auf Plausibilität und übergibt ihn an Core, das den Zielbeleg erzeugt.

Technisch ist die Zielvorlage ein Enum, das ein Interface implementiert:

- `DXP Breeze IF Target Template` – das Enum der Zielvorlagen, `Extensible = true`.
- `DXP BRZIF IDocument Processing` – das Interface, das jede Zielvorlage implementiert. Es besitzt genau eine Methode:   
    `procedure ProcessDocument(var BREEZEDoc: Record "DXP BRZ IF Document"; JObject: JsonObject)`

Im Auslieferungszustand sind diese Zielvorlagen enthalten:

<table id="bkmrk-wertzielvorlageimple"><thead><tr><th>Wert</th><th>Zielvorlage</th><th>Implementierung</th></tr></thead><tbody><tr><td>0</td><td>Keine (None)</td><td>`DXP BRZ Default Processing`</td></tr><tr><td>1</td><td>Einkaufsbeleg (Purchase Document)</td><td>`DXP BRZ IF PInv/Crdt Memo Proc`</td></tr><tr><td>2</td><td>Einkaufsbestellung (Purchase Order)</td><td>`DXP BRZ IF Purch. Order Proc.`</td></tr><tr><td>3</td><td>Auftragsbestätigung (Order Confirmation)</td><td>`DXP BRZ IF Order Conf. Proc.`</td></tr><tr><td>4</td><td>Lieferschein (Delivery Note)</td><td>`DXP BRZ IF Del. Note Proc.`</td></tr></tbody></table>

{add screenshot of Dokumentenklassen-Einrichtung here}

## Voraussetzungen

- Eine eigene Extension mit Abhängigkeit auf **DEXPRO Breeze Interface** (App-Id `7c431886-108e-44c3-9328-30e2b93edfa6`) und – über `propagateDependencies` mitgeliefert – auf **DEXPRO Core**.
- Ein eigener Objekt-ID-Bereich. Verwenden Sie **nicht** den Bereich von Breeze Interface (70954950–70954969) oder Core (70954575–70954624).
- Ein eigener Objektnamen-Affix, den Ihre `AppSourceCop.json` vorschreibt.

<p class="callout warning">Verwenden Sie für Ihre Objekte niemals das Affix `DXP`. Es ist für die DEXPRO-Apps reserviert. In den Codebeispielen dieser Seite steht `XYZ` stellvertretend für Ihr eigenes Affix.</p>

## Schritt 1 – Zielvorlage als Enum-Erweiterung anlegen

Das Enum `DXP Breeze IF Target Template` ist erweiterbar. Legen Sie einen neuen Wert an und verweisen Sie mit `Implementation` auf Ihre eigene Codeunit:

```
enumextension 50100 "XYZ Target Template Ext." extends "DXP Breeze IF Target Template"
{
    value(50100; "XYZ Post Purchase Order")
    {
        Caption = 'Bestellung buchen';
        Implementation = "DXP BRZIF IDocument Processing" = "XYZ Post Purch. Order Proc.";
    }
}
```

<p class="callout warning">Der Enum-Wert wird auf dem Breeze-Beleg und auf dem Core-Beleg gespeichert. Ändern Sie die Nummer nach dem ersten Produktiveinsatz nicht mehr – bereits gespeicherte Belege würden sonst auf eine andere Zielvorlage zeigen.</p>

## Schritt 2 – Die Standardzielvorlage überschreiben

Die Zielvorlage wird beim Anlegen des Breeze-Belegs aus der Dokumentenklassen-Einrichtung gelesen. Um sie fallabhängig zu übersteuern, abonnieren Sie das Ereignis `OnAfterFillDocumentInfo` der Codeunit `DXP BRZ IF Document Mgt.`. Es wird gerufen, während der Breeze-Beleg aus dem JSON gefüllt wird – also bevor er eingefügt ist:

```
codeunit 50100 "XYZ Breeze Doc. Subscribers"
{
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP BRZ IF Document Mgt.", 'OnAfterFillDocumentInfo', '', false, false)]
    local procedure SetTargetTemplateOnOrderReference(var BrzIfDoc: Record "DXP BRZ IF Document"; JsonData: JsonObject)
    var
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
        JsonHelper: Codeunit "DXP Json Helper";
        OrderNo: Code[20];
    begin
        // Nur Belege umleiten, die im Standard zur Einkaufsrechnung fuehren.
        if BrzIfDoc."Target Template" <> BrzIfDoc."Target Template"::"Purchase Document" then
            exit;

        OrderNo := CopyStr(JsonHelper.ValAsTxt(JsonData, CoreTokenMgt.GetOrderNoTok(), false), 1, MaxStrLen(OrderNo));
        if OrderNo = '' then
            exit;

        BrzIfDoc."Target Template" := BrzIfDoc."Target Template"::"XYZ Post Purchase Order";
    end;
}
```

Die Bestellnummer steht im Belegkopf-JSON unter dem Token `orderNo`. Lesen Sie sie ausschließlich über `DXP Core Token Mgt.` aus – die Token-Namen sind dort zentral gepflegt.

<p class="callout info">Das zweite Argument von `ValAsTxt` ist `EnsureSuccess`. Übergeben Sie hier `false`: Die Bestellnummer ist ein optionales Feld, und bei `true` würde ein fehlendes Token einen Laufzeitfehler auslösen.</p>

### Die Zielvorlage im Core-Beleg nachziehen

Core führt im Feld **Breeze Interface Zielvorlage** der Tabelle `DXP Document` eine Kopie der Zielvorlage mit. Setzt Ihr Abonnent die Zielvorlage um, aktualisieren Sie dieses Feld mit – sonst zeigt der Core-Beleg weiter die alte Vorlage an. Ihre eigene Verarbeitung aus Schritt 3 erledigt das (siehe `CoreDoc.Validate("DXP Breeze IF Target Template", ...)` im Beispiel unten).

## Schritt 3 – Die Verarbeitung implementieren

Wird der Breeze-Beleg auf **Processed** gesetzt, ruft Breeze Interface die zur Zielvorlage hinterlegte Implementierung auf:

```
IDocumentProcessing := Rec."Target Template";
IDocumentProcessing.ProcessDocument(Rec, JsonHelper.JObjectFromBlob(Rec.RecordId, Rec.FieldNo(JSON)));
```

Ihre Codeunit implementiert dafür `DXP BRZIF IDocument Processing`. Sie ist verantwortlich für:

- **Prüfen** des Belegs – im Fehlerfall den Breeze-Beleg auf Status **Error** setzen und die Meldungen in das JSON schreiben.
- **Übergeben** an Core über `DXP Document Mgt.UpdateDocument`, wenn der Beleg gültig ist.
- **Löschen** des Breeze-Belegs nach erfolgreicher Übergabe. Der Core-Beleg bleibt als Nachweis bestehen.

```
codeunit 50101 "XYZ Post Purch. Order Proc." implements "DXP BRZIF IDocument Processing"
{
    procedure ProcessDocument(var BREEZEDoc: Record "DXP BRZ IF Document"; JObject: JsonObject)
    var
        CoreDoc: Record "DXP Document";
        CoreDocMgt: Codeunit "DXP Document Mgt.";
        ValidDoc: Boolean;
    begin
        ValidDoc := CheckDocument(JObject);

        if not ValidDoc then begin
            BREEZEDoc.Validate(Status, "DXP Breeze IF Status"::Error);
            BREEZEDoc.Modify(false);
            exit;
        end;

        CoreDocMgt.UpdateDocument(
            BREEZEDoc."Core Document No.",
            "DXP Document Status"::Transferred,
            "DXP Target Document Process"::"XYZ Post Purchase Order",
            JObject);

        CoreDoc.Get(BREEZEDoc."Core Document No.");
        CoreDoc.Validate("DXP Breeze IF Target Template", BREEZEDoc."Target Template");
        CoreDoc.Modify(true);

        BREEZEDoc.Delete(true);
    end;
}
```

<p class="callout info">Als Vorlage für Plausibilitätsprüfungen dient die ausgelieferte Codeunit `DXP BRZ IF PInv/Crdt Memo Proc`. Nutzen Sie `DXP Plausiblity Check Mgt.` für die Prüfungen und `DXP BRZ IF Target Templ. Mgt.`, um die Einrichtung Ihrer Zielvorlage zu lesen – damit greifen die Schalter **Betragsprüfung deaktivieren** und **Buchungsdatum nicht prüfen** auch für Ihre Vorlage.</p>

## Schritt 4 – Den Zielbeleg in Core erzeugen

Die Zielvorlage in Breeze bestimmt *welche Prüfung* läuft. *Welcher Zielbeleg* entsteht, entscheidet ein zweites Enum in Core: `DXP Target Document Process`, ebenfalls `Extensible = true`, mit dem Interface `DXP IDocument Processing`.

<p class="callout warning">Die beiden Enums sind getrennt und müssen beide erweitert werden. Die Breeze-Zielvorlage wählt die Prüfung, der Core-Zielbelegprozess die Belegerstellung. Der Wert wird von Ihrer Verarbeitung aus Schritt 3 an `UpdateDocument` übergeben.</p>

```
enumextension 50101 "XYZ Target Doc. Process Ext." extends "DXP Target Document Process"
{
    value(50100; "XYZ Post Purchase Order")
    {
        Caption = 'Bestellung buchen';
        Implementation = "DXP IDocument Processing" = "XYZ Post P. Order Creation";
    }
}
```

Das Interface `DXP IDocument Processing` hat eine Methode, die die `RecordId` des erzeugten Belegs zurückgibt. Core speichert sie im Feld **Verknüpfte Datensatz-ID** des Core-Belegs:

```
procedure ProcessStandardDocument(JObject: JsonObject): RecordId
```

Ihre Implementierung liest die Bestellnummer aus dem Kopf, holt die Bestellung und bucht sie:

```
codeunit 50102 "XYZ Post P. Order Creation" implements "DXP IDocument Processing"
{
    procedure ProcessStandardDocument(JObject: JsonObject): RecordId
    var
        PurchaseHeader: Record "Purchase Header";
        PurchInvHeader: Record "Purch. Inv. Header";
        CoreTokenMgt: Codeunit "DXP Core Token Mgt.";
        JsonHelper: Codeunit "DXP Json Helper";
        TargetDocumentMgt: Codeunit "DXP Target Document Mgt.";
        PurchPost: Codeunit "Purch.-Post";
        DocRecRef: RecordRef;
        OrderNo: Code[20];
        VendorNo: Code[20];
    begin
        OrderNo := CopyStr(JsonHelper.ValAsTxt(JObject, CoreTokenMgt.GetOrderNoTok(), true), 1, MaxStrLen(OrderNo));
        VendorNo := CopyStr(JsonHelper.ValAsTxt(JObject, CoreTokenMgt.GetVendorNoTok(), true), 1, MaxStrLen(VendorNo));

        PurchaseHeader.SetRange("Document Type", PurchaseHeader."Document Type"::Order);
        PurchaseHeader.SetRange("No.", OrderNo);
        PurchaseHeader.SetRange("Buy-from Vendor No.", VendorNo);
        PurchaseHeader.FindFirst();

        // Rechnungsdaten aus dem JSON in die Bestellung uebernehmen
        // (Belegdatum, Buchungsdatum, Externe Belegnummer, zu berechnende Mengen)
        UpdatePurchaseHeaderFromJson(JObject, PurchaseHeader);

        PurchPost.SetSuppressCommit(true);
        PurchPost.Run(PurchaseHeader);

        DocRecRef.Get(PurchaseHeader.RecordId());
        TargetDocumentMgt.SetProcessedCompletely(DocRecRef);

        PurchInvHeader.SetRange("Order No.", OrderNo);
        if PurchInvHeader.FindLast() then
            exit(PurchInvHeader.RecordId());

        exit(PurchaseHeader.RecordId());
    end;
}
```

<p class="callout warning">Geben Sie niemals eine leere `RecordId` zurück. Core prüft den Rückgabewert; bleibt er leer, bricht die Verarbeitung mit einer Fehlermeldung ab.</p>

### Vollständig verarbeitet kennzeichnen

Core erweitert die Tabelle **Einkaufskopf** um das Feld **Vollständig verarbeitet**. Setzen Sie es über `DXP Target Document Mgt.SetProcessedCompletely`, sobald der Beleg fertig verarbeitet ist. Die ausgelieferten Implementierungen tun das ebenfalls; das Feld steuert die Anzeige und die nachgelagerte Verarbeitung.

### Wenn die Bestellung gebucht wird

Beim Buchen entsteht ein neuer Beleg – die gebuchte Einkaufsrechnung –, während die Bestellung je nach Restmenge gelöscht wird. Verweisen Sie deshalb im Rückgabewert auf den *gebuchten* Beleg, wie im Beispiel oben. Zeigt **Verknüpfte Datensatz-ID** auf eine gelöschte Bestellung, läuft der Absprung vom Core-Beleg ins Leere.

## Die Einrichtung der Zielvorlage

Zu jeder Zielvorlage gehört ein Datensatz in der Tabelle `DXP BRZ IF Target Templ. Setup`, sichtbar auf der Seite **Zielvorlagen-Einrichtung**. Er wird beim ersten Zugriff automatisch angelegt. Diese Schalter stehen zur Verfügung:

- **Betragsprüfung deaktivieren** – unterdrückt den Abgleich von Kopf- und Zeilenbeträgen.
- **Buchungsdatum nicht prüfen** – unterdrückt die Prüfung des Buchungsdatums.
- **Gesperrten Kreditoren (Zahlung) ignorieren** – lässt Belege gesperrter Kreditoren zu.
- **Nicht freigeben** – unterdrückt die automatische Freigabe des Zielbelegs.

Sollen für Ihre Zielvorlage andere Vorgabewerte gelten als die leeren Standardwerte, setzen Sie sie beim Anlegen. Die Codeunit `DXP BRZ IF Target Templ. Mgt.` tut das für die ausgelieferten Vorlagen; für eigene Vorlagen abonnieren Sie den `OnInsert`-Trigger der Tabelle.

{add screenshot of Zielvorlagen-Einrichtung here}

## Checkliste

<table id="bkmrk-schrittobjektzweck-1"><thead><tr><th>Schritt</th><th>Objekt</th><th>Zweck</th></tr></thead><tbody><tr><td>1</td><td>`enumextension` auf `DXP Breeze IF Target Template`</td><td>Die eigene Zielvorlage bekannt machen</td></tr><tr><td>2</td><td>Abonnent auf `OnAfterFillDocumentInfo`</td><td>Die Standardzielvorlage fallabhängig überschreiben</td></tr><tr><td>3</td><td>`codeunit` implements `DXP BRZIF IDocument Processing`</td><td>Prüfen und an Core übergeben</td></tr><tr><td>4</td><td>`enumextension` auf `DXP Target Document Process`</td><td>Den eigenen Zielbelegprozess bekannt machen</td></tr><tr><td>5</td><td>`codeunit` implements `DXP IDocument Processing`</td><td>Den Zielbeleg erzeugen – hier: die Bestellung buchen</td></tr><tr><td>6</td><td>**Dokumentenklassen-Einrichtung**</td><td>Prüfen, dass der nächste Prozessschritt auf **Breeze Interface** steht</td></tr></tbody></table>

## Fehlersuche

<table id="bkmrk-beobachtungursache-d"><thead><tr><th>Beobachtung</th><th>Ursache</th></tr></thead><tbody><tr><td>Der Beleg behält die alte Zielvorlage.</td><td>Der Abonnent aus Schritt 2 greift nicht. Prüfen Sie, ob die Dokumentenklasse tatsächlich auf die Zielvorlage **Einkaufsbeleg** zeigt und ob das Token `orderNo` im Kopf-JSON gefüllt ist.</td></tr><tr><td>Beim Setzen auf **Processed** läuft die Standardverarbeitung.</td><td>Der `Implementation`-Verweis im Enum fehlt. Ohne ihn greift die `DefaultImplementation` des Enums, also `DXP BRZ Default Processing`.</td></tr><tr><td>Meldung *Document creation failed. RecordId is empty.*</td><td>Ihre `ProcessStandardDocument`-Implementierung hat keine `RecordId` zurückgegeben.</td></tr><tr><td>Der Absprung vom Core-Beleg öffnet nichts.</td><td>**Verknüpfte Datensatz-ID** zeigt auf einen gelöschten Beleg – geben Sie den gebuchten Beleg zurück, nicht die Bestellung.</td></tr><tr><td>Der Beleg steht auf **Error**, ohne dass eine Meldung erscheint.</td><td>Ihre Verarbeitung setzt den Status, schreibt aber keine Prüfmeldungen in das JSON. Nutzen Sie `DXP Document Transfer Mgt.AddErrorsToJson`.</td></tr></tbody></table>