> For the complete documentation index, see [llms.txt](https://docs.solutioo.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.solutioo.de/entwicklerdokumentationen-business-central-dhl-connector/dhl-connector-entwicklerdokumentation/integration-events.md).

# Integration Events

Der DHL Connector **25.23.0.0** veröffentlicht additive `IntegrationEvent`s für Packing, Empfänger, Label und Rate. Die drei bestehenden Events aus 25.12 bleiben inklusive Signatur und Timing unverändert. `OnBeforeSendShipmentRequest` bleibt ausschließlich Express vorbehalten.

Subscriber werden in der Consumer-App als lokale Procedures implementiert. Ohne Subscriber bleiben Ablauf, Rückgabewerte, Transaktionsgrenzen, Berechtigungen und Oberfläche unverändert. Es gibt kein `IsHandled` und keinen zusätzlichen `Commit()` in den Publishern.

## Gemeinsame Regeln

* Eventparameter enthalten nur fachliche Paket-, Auftrags-, Packing- und Rate-Daten.
* Credentials, Tokens, Authorization-Header, interne Endpunkte, Azure-Konfiguration und rohe HTTP-Responses werden nicht übergeben.
* Request-JSON nicht protokollieren; es enthält personenbezogene Versanddaten.
* Keine UI-Dialoge und keine unnötigen `Commit()`-Aufrufe im Subscriber.
* Alle Events sind hintergrundfähig, sofern der aufrufende Prozess ohne UI läuft. Subscriber dürfen keine Client-Dialoge öffnen.
* Ein Fehler in einem Before-Event bricht den laufenden Vorgang ab. After-Events nach einem `Commit()` rollen ein bereits gespeichertes Label nicht zurück.

## Aufrufreihenfolge

### Paketerzeugung

1. `OnBeforeCreatePackages`
2. je Paket `OnBeforePackageHeaderInsert`
3. je Paket `OnAfterPackageCreated`
4. `OnAfterCreatePackages`

### Label

1. `OnAfterSnapshotFromSalesHeader` während der Empfängerauflösung
2. `OnBeforeGenerateLabel`
3. Parcel DE: `OnBeforeSendParcelDEShipmentRequest` **oder** Express: `OnBeforeSendShipmentRequest`
4. bei erfolgreichem Tracking-Writeback `OnAfterUpdateTrackingOnSourceOrder`
5. `OnAfterGenerateLabel` mit `Success = true` oder `false`

`OnAfterGenerateLabel` wird für jeden `GenerateLabel`-Rückgabepfad ausgelöst. Ein separates Failure-Event ist nicht erforderlich.

### Live-Rate

1. `OnBeforeGetRate`
2. `OnAfterGetRate` auf jedem Rückgabepfad, einschließlich „nicht Express“

## OnBeforeCreatePackages

Publisher: Codeunit `72242980 "SOUDHL Packing Mgt"`

```al
[IntegrationEvent(false, false)]
local procedure OnBeforeCreatePackages(
    var SalesHeader: Record "Sales Header";
    var FixedPackageCount: Integer;
    var BoxCode: Code[20];
    var PackingMode: Enum "SOUDHL Packing Mode")
```

**Zeitpunkt:** nach Auflösung der Standardbox und des Packing Mode, vor Validierung und vor dem Löschen nicht hochgeladener Pakete.

**var-Wirkung:** `SalesHeader`, `FixedPackageCount`, `BoxCode` und `PackingMode` sind veränderbar. `FixedPackageCount = 0` bleibt automatische Ermittlung.

**Fehler:** Ein Subscriber-Fehler bricht die Paketerzeugung ab. Bestehende Pending-Pakete bleiben erhalten, weil noch nicht gelöscht wurde.

**Personenbezogene Daten:** `SalesHeader` enthält Lieferadresse und Kontaktdaten. Nicht protokollieren.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Packing Mgt",
    'OnBeforeCreatePackages',
    '', false, false)]
local procedure ChoosePackingBox(
    var SalesHeader: Record "Sales Header";
    var FixedPackageCount: Integer;
    var BoxCode: Code[20];
    var PackingMode: Enum "SOUDHL Packing Mode")
begin
    if BoxCode = '' then
        BoxCode := 'STD';
end;
```

## OnBeforePackageHeaderInsert

Publisher: Codeunit `72242980 "SOUDHL Packing Mgt"`

```al
[IntegrationEvent(false, false)]
local procedure OnBeforePackageHeaderInsert(
    var PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header";
    PackageIndex: Integer;
    PackageCount: Integer)
```

**Zeitpunkt:** nach Vorbereitung der Headerfelder und vor `Insert(true)`.

**var-Wirkung:** `PackageHeader` darf angereichert werden, etwa Billing oder Abmessungen. `PackageIndex` ist 1-basiert.

**Fehler:** Ein Subscriber-Fehler bricht die restlichen Inserts dieses Laufs ab.

**Personenbezogene Daten:** Header und Auftrag enthalten Empfängerdaten. Nicht protokollieren.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Packing Mgt",
    'OnBeforePackageHeaderInsert',
    '', false, false)]
local procedure EnrichPackageHeader(
    var PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header";
    PackageIndex: Integer;
    PackageCount: Integer)
begin
    if PackageHeader."Package Date" = 0DT then
        PackageHeader.Validate("Package Date", CurrentDateTime());
end;
```

## OnAfterPackageCreated

Publisher: Codeunit `72242980 "SOUDHL Packing Mgt"`

```al
[IntegrationEvent(false, false)]
local procedure OnAfterPackageCreated(
    PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
```

**Zeitpunkt:** nach Insert des Headers und aller zugehörigen Package Lines.

**var-Wirkung:** Parameter sind nicht `var`. Follow-up-Writes müssen den Datensatz selbst lesen und speichern.

**Fehler:** Ein Subscriber-Fehler stoppt weitere Pakete desselben Laufs. Das aktuelle Paket bleibt gespeichert.

**Personenbezogene Daten:** Header und Auftrag enthalten Empfängerdaten.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Packing Mgt",
    'OnAfterPackageCreated',
    '', false, false)]
local procedure AfterOnePackage(
    PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
begin
    // Follow-up writes on this package only.
end;
```

## OnAfterCreatePackages

Publisher: Codeunit `72242980 "SOUDHL Packing Mgt"`

```al
[IntegrationEvent(false, false)]
local procedure OnAfterCreatePackages(
    SalesHeader: Record "Sales Header";
    BoxCode: Code[20];
    PackingMode: Enum "SOUDHL Packing Mode";
    CreatedPackageCount: Integer)
```

**Zeitpunkt:** nach dem gesamten Packing-Lauf.

**var-Wirkung:** keine. `CreatedPackageCount` ist die Anzahl der in diesem Lauf erzeugten Pakete.

**Fehler:** Ein Subscriber-Fehler löscht die erzeugten Pakete nicht.

**Personenbezogene Daten:** `SalesHeader` enthält Lieferdaten.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Packing Mgt",
    'OnAfterCreatePackages',
    '', false, false)]
local procedure AfterPackingRun(
    SalesHeader: Record "Sales Header";
    BoxCode: Code[20];
    PackingMode: Enum "SOUDHL Packing Mode";
    CreatedPackageCount: Integer)
begin
    if CreatedPackageCount = 0 then
        exit;
end;
```

## OnAfterSnapshotFromSalesHeader

Publisher: Codeunit `72242965 "SOUDHL Package Recipient Mgt"`

```al
[IntegrationEvent(false, false)]
local procedure OnAfterSnapshotFromSalesHeader(
    var PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
```

**Zeitpunkt:** nachdem der Standard-Ship-to-Snapshot gesetzt wurde und bevor der Caller den Header persistiert.

**var-Wirkung:** `PackageHeader` darf für Packstation, Kontakt oder Adressnormalisierung geändert werden.

**Fehler:** Ein Subscriber-Fehler bricht den Snapshot ab.

**Personenbezogene Daten:** Name, Adresse, E-Mail und Telefon. Nicht protokollieren.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Package Recipient Mgt",
    'OnAfterSnapshotFromSalesHeader',
    '', false, false)]
local procedure NormalizeRecipient(
    var PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
begin
    PackageHeader."Recipient Name" := DelChr(PackageHeader."Recipient Name", '<>', ' ');
end;
```

## OnAfterUpdateTrackingOnSourceOrder

Publisher: Codeunit `72242965 "SOUDHL Package Recipient Mgt"`

```al
[IntegrationEvent(false, false)]
local procedure OnAfterUpdateTrackingOnSourceOrder(
    PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header";
    TrackingNo: Text)
```

**Zeitpunkt:** nach jedem erfolgreichen Writeback der Sendungsnummer auf einen Quellauftrag. Das Event läuft einmal je aktualisiertem Auftrag.

**var-Wirkung:** keine.

**Fehler:** Ein Subscriber-Fehler stoppt weitere Writebacks desselben Aufrufs.

**Personenbezogene Daten:** Auftrag und Trackingnummer. Nicht unkontrolliert loggen.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Package Recipient Mgt",
    'OnAfterUpdateTrackingOnSourceOrder',
    '', false, false)]
local procedure AfterTrackingWriteback(
    PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header";
    TrackingNo: Text)
begin
    if TrackingNo = '' then
        exit;
end;
```

## OnBeforeGenerateLabel

Publisher: Codeunit `72242952 "SOUDHL API Management"`

```al
[IntegrationEvent(false, false)]
local procedure OnBeforeGenerateLabel(
    var PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header";
    IsExpress: Boolean)
```

**Zeitpunkt:** nach Empfänger-Snapshot und erneutem `Get` des Headers, vor Zoll-, Box-, Gewichts- und Request-Verarbeitung. Läuft in beiden Labelpfaden. `IsExpress` unterscheidet Express und Parcel DE.

**var-Wirkung:** `PackageHeader` darf fachlich angereichert werden, bevor Maße und Request gelesen werden.

**Fehler:** Ein Subscriber-Fehler bricht die Labelerzeugung ab. `OnAfterGenerateLabel` wird danach mit `Success = false` ausgelöst.

**Personenbezogene Daten:** Paket- und Auftragsempfänger. Nicht protokollieren.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL API Management",
    'OnBeforeGenerateLabel',
    '', false, false)]
local procedure BeforeLabel(
    var PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header";
    IsExpress: Boolean)
begin
    if PackageHeader.Uploaded then
        Error('Package %1 is already uploaded.', PackageHeader.ID);
end;
```

## OnAfterGenerateLabel

Publisher: Codeunit `72242952 "SOUDHL API Management"`

```al
[IntegrationEvent(false, false)]
local procedure OnAfterGenerateLabel(
    PackageHeader: Record "SOUDHL Package Header";
    Success: Boolean;
    ExtraMessage: Text)
```

**Zeitpunkt:** nach dem gesamten `GenerateLabel`-Ablauf. Bei Erfolg nach `Commit()` und optionaler Kartonbestandsbuchung. Bei jedem Fehlerrückgabepfad mit `Success = false`.

**var-Wirkung:** keine. `Success = false` deckt fachliche und technische Fehler ab.

**Fehler:** Ein Subscriber-Fehler nach erfolgreichem Label rollt das committete Label nicht zurück.

**Personenbezogene Daten:** Package Header kann Empfänger und Tracking enthalten.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL API Management",
    'OnAfterGenerateLabel',
    '', false, false)]
local procedure AfterLabel(
    PackageHeader: Record "SOUDHL Package Header";
    Success: Boolean;
    ExtraMessage: Text)
begin
    if not Success then
        exit;
end;
```

## OnBeforeSendParcelDEShipmentRequest

Publisher: Codeunit `72242952 "SOUDHL API Management"`

```al
[IntegrationEvent(false, false)]
local procedure OnBeforeSendParcelDEShipmentRequest(
    var RequestJson: JsonObject;
    PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
```

**Zeitpunkt:** ausschließlich im Parcel-DE-Pfad, nachdem das Order-JSON aufgebaut wurde und bevor es serialisiert und gesendet wird. Symmetrisch zum Express-Hook `OnBeforeSendShipmentRequest`.

**var-Wirkung:** `RequestJson` darf dokumentierte Parcel-DE-Felder ergänzen. Pflichtknoten nicht entfernen und den Request nicht ersetzen.

**Fehler:** Ein Subscriber-Fehler bricht die Labelerzeugung ab.

**Personenbezogene Daten:** Das JSON enthält Absender und Empfänger. Nicht protokollieren. Keine Credentials oder Header verwalten.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL API Management",
    'OnBeforeSendParcelDEShipmentRequest',
    '', false, false)]
local procedure BeforeParcelRequest(
    var RequestJson: JsonObject;
    PackageHeader: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
begin
    if not RequestJson.Contains('profile') then
        exit;
end;
```

Die JSON-Struktur gilt als semi-stabil. Bevorzugt werden fachliche Header-Änderungen über `OnBeforeGenerateLabel`.

## OnBeforeSendShipmentRequest

Publisher: Codeunit `72242952 "SOUDHL API Management"`

```al
[IntegrationEvent(false, false)]
procedure OnBeforeSendShipmentRequest(
    var RequestJson: JsonObject;
    SOUDHLPackageHeaderRecord: Record "SOUDHL Package Header";
    SalesHeader: Record "Sales Header")
```

Das Event wird ausschließlich im **DHL-Express-Prozess** ausgelöst:

* nachdem der MyDHL-Shipment-Request aufgebaut wurde,
* bevor der Request serialisiert und gesendet wird.

Signatur und Timing sind seit 25.12 unverändert.

### Subscriber-Beispiel

```al
codeunit 50110 "My DHL Event Subscribers"
{
    [EventSubscriber(
        ObjectType::Codeunit,
        Codeunit::"SOUDHL API Management",
        'OnBeforeSendShipmentRequest',
        '', false, false)]
    local procedure OnBeforeSendDhlRequest(
        var RequestJson: JsonObject;
        PackageHeader: Record "SOUDHL Package Header";
        SalesHeader: Record "Sales Header")
    var
        ExpressHelper: Codeunit "SOUDHL Express Helper";
        ProductCode: Code[5];
    begin
        ProductCode := ExpressHelper.MapProductCode(
            Enum::"SOUDHL Express Product"::Express1200);

        if RequestJson.Contains('productCode') then
            RequestJson.Replace('productCode', ProductCode);
    end;
}
```

### Regeln für Request-Subscriber

* Nur dokumentierte MyDHL-Felder verändern.
* Pflichtknoten nicht entfernen und den kompletten Request nicht ersetzen.
* Keine Zugangsdaten, Authentifizierungsheader oder Endpoints verwalten.
* Request-JSON nicht protokollieren; es enthält personenbezogene Versanddaten.
* Keine UI-Dialoge und keine unnötigen `Commit()`-Aufrufe im Subscriber ausführen.
* Ein Fehler im Subscriber bricht die Labelerzeugung ab.
* Anpassungen gegen Sandbox und Live fachlich testen.

Da dieser Hook die Transportstruktur sichtbar macht, gilt seine JSON-Struktur als semi-stabil. Fachliche Änderungen vor dem Request-Aufbau gehören in `OnBeforeGenerateLabel`.

## OnBeforeGetRate

Publisher: Codeunit `72242952 "SOUDHL API Management"`

```al
[IntegrationEvent(false, false)]
local procedure OnBeforeGetRate(
    var ReceiverCountry: Code[10];
    var ReceiverPostalCode: Text;
    var ReceiverCity: Text;
    var WeightKg: Decimal;
    var LengthCm: Decimal;
    var WidthCm: Decimal;
    var HeightCm: Decimal;
    var ProductCode: Code[5])
```

**Zeitpunkt:** bevor der interne Express-Rate-Aufruf startet. Die öffentliche `GetRate`-Signatur bleibt unverändert.

**var-Wirkung:** alle Eingaben sind veränderbar, einschließlich Produktcode und Abmessungen.

**Fehler:** Ein Subscriber-Fehler bricht den Rate-Aufruf ab. `OnAfterGetRate` wird danach nicht ausgelöst, wenn der Subscriber einen AL-Fehler wirft.

**Personenbezogene Daten:** Empfängerort und PLZ. Credentials bleiben intern.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL API Management",
    'OnBeforeGetRate',
    '', false, false)]
local procedure AdjustRateInput(
    var ReceiverCountry: Code[10];
    var ReceiverPostalCode: Text;
    var ReceiverCity: Text;
    var WeightKg: Decimal;
    var LengthCm: Decimal;
    var WidthCm: Decimal;
    var HeightCm: Decimal;
    var ProductCode: Code[5])
begin
    if ProductCode = '' then
        ProductCode := 'P';
end;
```

## OnAfterGetRate

Publisher: Codeunit `72242952 "SOUDHL API Management"`

```al
[IntegrationEvent(false, false)]
local procedure OnAfterGetRate(
    ReceiverCountry: Code[10];
    ReceiverPostalCode: Text;
    ReceiverCity: Text;
    WeightKg: Decimal;
    LengthCm: Decimal;
    WidthCm: Decimal;
    HeightCm: Decimal;
    ProductCode: Code[5];
    Success: Boolean;
    Price: Decimal;
    Currency: Text;
    ExtraMessage: Text)
```

**Zeitpunkt:** nach jedem Express-Live-Rate-Versuch, einschließlich Konfigurations- und Servicefehlern sowie „nicht Express“.

**var-Wirkung:** keine. `Price` und `Currency` sind nur bei `Success = true` gefüllt.

**Fehler:** Ein Subscriber-Fehler ändert den bereits ermittelten Rückgabewert von `GetRate` nicht nachträglich, wenn der Caller den Boolean bereits erhalten hat. Der Fehler wird an den Aufrufer weitergegeben.

**Personenbezogene Daten:** Empfängerort. Keine rohen Responses.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL API Management",
    'OnAfterGetRate',
    '', false, false)]
local procedure AfterRate(
    ReceiverCountry: Code[10];
    ReceiverPostalCode: Text;
    ReceiverCity: Text;
    WeightKg: Decimal;
    LengthCm: Decimal;
    WidthCm: Decimal;
    HeightCm: Decimal;
    ProductCode: Code[5];
    Success: Boolean;
    Price: Decimal;
    Currency: Text;
    ExtraMessage: Text)
begin
    if not Success then
        exit;
end;
```

## OnBeforeSetPackageSubpageVisible

Publisher: Codeunit `72242964 "SOUDHL Sales UI"`

```al
[IntegrationEvent(false, false)]
procedure OnBeforeSetPackageSubpageVisible(
    SalesHeader: Record "Sales Header";
    var IsVisible: Boolean)
```

Der Standardwert ist `true`. Eine abhängige App kann die DHL-Paket-Subpage auf dem Verkaufsauftrag ausblenden, wenn sie eine eigene Versandoberfläche bereitstellt.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Sales UI",
    'OnBeforeSetPackageSubpageVisible',
    '', false, false)]
local procedure HideDhlPackageSubpage(
    SalesHeader: Record "Sales Header";
    var IsVisible: Boolean)
begin
    IsVisible := false;
end;
```

Produktiv sollte die Zuweisung nur erfolgen, wenn eine eigene Setup-Option die alternative Versandoberfläche aktiviert.

**Hintergrund:** Das Event läuft in der UI. Für Background Sessions ist es nicht relevant.

## OnBeforeSetListActionsVisible

Publisher: Codeunit `72242964 "SOUDHL Sales UI"`

```al
[IntegrationEvent(false, false)]
procedure OnBeforeSetListActionsVisible(var IsVisible: Boolean)
```

Der Standardwert ist `true`. Das Event steuert die DHL-Aktionsgruppen auf Listen und gebuchten Verkaufsbelegen.

```al
[EventSubscriber(
    ObjectType::Codeunit,
    Codeunit::"SOUDHL Sales UI",
    'OnBeforeSetListActionsVisible',
    '', false, false)]
local procedure HideDhlListActions(var IsVisible: Boolean)
begin
    IsVisible := false;
end;
```

Auch dieses Ausblenden sollte produktiv von einer eigenen Setup-Option abhängen.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.solutioo.de/entwicklerdokumentationen-business-central-dhl-connector/dhl-connector-entwicklerdokumentation/integration-events.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
