Belege aus anderen Extensions archivieren

Überblick

Freeze archiviert Belege automatisch an festen Stellen in Business Central: beim Buchen, beim Löschen eines Belegs und beim E-Mail-Versand über das BC-E-Mail-Modul. Viele Kunden nutzen zusätzlich andere Extensions, die Belege drucken, per E-Mail versenden oder als E-Rechnung ausgeben. Diese Extensions nutzen oft eigene Wege, an denen Freeze nicht automatisch mitarbeitet.

Diese Seite zeigt Partnern, wie sie solche Belege trotzdem in Freeze archivieren. Oft reicht dafür eine Einstellung in Freeze. Wenn nicht, schreiben Sie eine kleine eigene Extension, die die Belege an Freeze übergibt. Eine Änderung an Freeze ist in keinem Fall nötig.

Der Grundgedanke ist einfach: Jede Archivierung in Freeze beginnt mit einem Eintrag in den Freeze Warteschlangeneinträgen. Den Upload ins Archiv, Wiederholungsversuche und die Prüfung übernimmt danach der Freeze-Job. Ihre Extension muss also nur einen solchen Eintrag anlegen.

Vorher prüfen: Ist eine zusätzliche Archivierung nötig?

Wenn in der Freeze Einrichtung die Optionen Nach Buchung archivieren und Ausgehende Belege archivieren aktiv sind, archiviert Freeze beim Buchen bereits ein PDF des Belegs. Freeze erzeugt dieses PDF über die Berichtsauswahl.

Klären Sie deshalb mit dem Kunden, was genau fehlt. Typische Lücken sind:

Die einfachste Möglichkeit: Anhänge des Belegs

Viele Extensions legen das ausgegebene Dokument als Anhang an den Beleg, z. B. an den Auftrag oder an die gebuchte Rechnung. Technisch ist das ein Datensatz in der Tabelle Document Attachment. Benutzer sehen ihn bei den Anhängen des Belegs. Für diesen Fall brauchen Sie keine eigene Extension.

Schalten Sie in der Freeze Einrichtung die Option Anhänge archivieren ein. Dann nimmt Freeze jedes Mal, wenn es einen Beleg archiviert, alle Anhänge dieses Belegs mit. Das passiert:

Das gilt für Einkaufs- und Verkaufsbelege, offen und gebucht (z. B. Rechnungen, Gutschriften, Lieferungen und Rücksendungen), sowie für Debitoren, Kreditoren und Artikel.

Entscheidend ist der Zeitpunkt. Freeze nimmt nur die Anhänge mit, die in diesem Moment schon am Beleg hängen. Anhänge, die erst später dazukommen, archiviert Freeze nicht von selbst.

Die andere Extension hängt ihr Dokument an … Ergebnis
… den Auftrag oder die Rechnung, bevor gebucht wird Business Central überträgt die Anhänge beim Buchen auf den gebuchten Beleg. Freeze archiviert sie dabei automatisch mit. Es ist nichts weiter zu tun.
… den gebuchten Beleg, aber erst später, z. B. beim Versand Freeze archiviert das Dokument nicht automatisch. Benutzer können danach auf dem gebuchten Beleg Jetzt archivieren ausführen. Freeze legt dann eine neue Version der vorhandenen Mappe an, mit dem Beleg-PDF und allen aktuellen Anhängen. Soll das automatisch geschehen, nutzen Sie Möglichkeit 1 oder 2 weiter unten.

So testen Sie es: Buchen Sie einen Testbeleg, an dem die andere Extension ihr Dokument angehängt hat. Warten Sie auf den Freeze-Job und öffnen Sie dann die Archivsuche des gebuchten Belegs. Das Dokument der anderen Extension muss unter den Anhängen der Mappe stehen.

Weitere Möglichkeiten im Überblick

Reichen die Anhänge nicht aus, z. B. weil die andere Extension ihr Dokument gar nicht oder erst nach dem Buchen anhängt, gibt es diese Möglichkeiten:

Möglichkeit So funktioniert es Gut geeignet, wenn …
1. Direkt beim Ausgeben archivieren Ihre Extension reagiert auf ein Event der anderen Extension, z. B. „Beleg wurde versendet“, und übergibt die Datei sofort an Freeze. die andere Extension ein passendes Event mit Zugriff auf die Datei und den Beleg anbietet.
2. Nachträglich per Aufgabenwarteschlange archivieren Ein Aufgabenwarteschlangenposten liest regelmäßig das Protokoll der anderen Extension und übergibt neue Einträge an Freeze. die andere Extension kein passendes Event hat, aber versendete Belege mit Datei protokolliert. Auch für bereits versendete Altbelege.
3. Beim Buchen eine andere Datei archivieren Ihre Extension tauscht über ein Freeze-Event das PDF aus, das Freeze beim Buchen archiviert. nur das Layout abweicht und der Buchungszeitpunkt ausreicht.
4. Manuell archivieren Benutzer ziehen die Datei in die Infobox Quick Freeze. es nur um Einzelfälle geht. Siehe Schnellarchivierung (Quick Freeze).

Möglichkeit 3 archiviert den Stand zum Buchungszeitpunkt, nicht das Dokument, das später tatsächlich versendet wurde. Wenn das versendete Dokument archiviert werden muss, wählen Sie Möglichkeit 1 oder 2.

Die Bausteine

Für alle Möglichkeiten brauchen Sie nur wenige öffentliche Prozeduren aus Freeze:

Codeunit Prozedur Wofür
DXP FRZ Attachment Mgt. AddFileFromStream(var TempFrzAttachmentBuffer; var InStr; FileName; LinkedRecordRef) Eine Datei in den Zwischenspeicher legen. Mehrfach aufrufen für mehrere Dateien.
DXP Freeze Queue Buffer Mgt. InsertFREEZEQueueEntryWithAttachments(LinkedRecordRef; var TempFrzAttachmentBuffer; FrzRecordType; ReferenceDate) Den Warteschlangeneintrag mit allen Dateien anlegen. Ab hier übernimmt Freeze.
DXP Freeze Queue Buffer Mgt. InsertQueueBufferEntry(RecSystemID; RecTableNo; var TempFrzAttachmentBuffer; FrzRecordType; ReferenceDate) und danach GetEntryNo() Wie oben. Zusätzlich liefert GetEntryNo() danach die Lfd. Nr. des neuen Eintrags, z. B. für ein eigenes Protokoll (Beispiel 2).
DXP Freeze Helper GetFreezeRecordTypeFromReportSelectionUsage(ReportSelectionUsage) Den passenden Mappentyp ermitteln, genauso wie Freeze es selbst tut.
DXP Freeze Setup Mgt. IsModuleActivated(), ArchiveEmailAttachments() Prüfen, ob Freeze aktiv ist und der Kunde die Archivierung versendeter Belege eingeschaltet hat.

Beispiel 1: Direkt beim Ausgeben archivieren

Die andere Extension veröffentlicht in diesem Beispiel ein Event OnAfterDocumentSent. Es liefert den Beleg, die Berichtsverwendung und das PDF. Ersetzen Sie Codeunit, Eventname und Parameter durch das Event der Extension, die Ihr Kunde einsetzt.

codeunit 50100 "PTE Archive Sent Documents"
{
    // Platzhalter: Codeunit und Event der anderen Extension
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Other Ext. Send Mgt.", 'OnAfterDocumentSent', '', false, false)]
    local procedure ArchiveInFreeze(DocumentRecordId: RecordId; ReportUsage: Enum "Report Selection Usage"; var PdfTempBlob: Codeunit "Temp Blob"; PdfFileName: Text)
    var
        TempFrzAttachmentBuffer: Record "DXP FRZ Attachment Buffer" temporary;
        FrzAttachmentMgt: Codeunit "DXP FRZ Attachment Mgt.";
        FrzQueueBufferMgt: Codeunit "DXP Freeze Queue Buffer Mgt.";
        FrzHelper: Codeunit "DXP Freeze Helper";
        FrzSetupMgt: Codeunit "DXP Freeze Setup Mgt.";
        LinkedRecRef: RecordRef;
        PdfInStr: InStream;
        DocumentNotFoundErr: Label 'The document %1 could not be found and was not archived in Freeze.', Comment = '%1 = Record ID';
    begin
        // 1. Einrichtung des Kunden respektieren
        if not FrzSetupMgt.IsModuleActivated() then
            exit;
        if not FrzSetupMgt.ArchiveEmailAttachments() then
            exit;

        // 2. Den gebuchten Beleg öffnen, z. B. die VK-Rechnung
        if not LinkedRecRef.Get(DocumentRecordId) then
            Error(DocumentNotFoundErr, Format(DocumentRecordId));

        // 3. Die Datei in den Zwischenspeicher legen
        PdfTempBlob.CreateInStream(PdfInStr);
        FrzAttachmentMgt.AddFileFromStream(TempFrzAttachmentBuffer, PdfInStr, PdfFileName, LinkedRecRef);

        // 4. Warteschlangeneintrag anlegen: Mappentyp wie bei Freeze, Bezugsdatum = Belegdatum
        FrzQueueBufferMgt.InsertFREEZEQueueEntryWithAttachments(
            LinkedRecRef,
            TempFrzAttachmentBuffer,
            Format(FrzHelper.GetFreezeRecordTypeFromReportSelectionUsage(ReportUsage)),
            GetDocumentDate(LinkedRecRef));
    end;

    local procedure GetDocumentDate(LinkedRecRef: RecordRef): Date
    var
        SalesInvoiceHeader: Record "Sales Invoice Header";
        SalesCrMemoHeader: Record "Sales Cr.Memo Header";
    begin
        case LinkedRecRef.Number() of
            Database::"Sales Invoice Header":
                begin
                    LinkedRecRef.SetTable(SalesInvoiceHeader);
                    exit(SalesInvoiceHeader."Document Date");
                end;
            Database::"Sales Cr.Memo Header":
                begin
                    LinkedRecRef.SetTable(SalesCrMemoHeader);
                    exit(SalesCrMemoHeader."Document Date");
                end;
        end;
        exit(WorkDate());
    end;
}

Wichtige Hinweise:

Beispiel 2: Nachträglich per Aufgabenwarteschlange archivieren

Die andere Extension führt in diesem Beispiel ein Protokoll Other Ext. Sent Log. Jeder Eintrag enthält den Beleg, die Berichtsverwendung und das PDF. Ihre Extension merkt sich in einer eigenen kleinen Tabelle, welche Einträge schon an Freeze übergeben wurden.

Schritt 1: Tabelle für bereits übergebene Einträge.

table 50100 "PTE Freeze Transfer Log"
{
    DataClassification = SystemMetadata;

    fields
    {
        field(1; "Source Entry No."; Integer) { }
        field(2; "Freeze Queue Entry No."; Integer) { }
        field(3; "Transferred At"; DateTime) { }
    }

    keys
    {
        key(PK; "Source Entry No.") { Clustered = true; }
    }
}

Schritt 2: Codeunit, die als Aufgabenwarteschlangenposten läuft.

codeunit 50101 "PTE Transfer Sent Log"
{
    trigger OnRun()
    var
        SentLog: Record "Other Ext. Sent Log"; // Platzhalter: Protokolltabelle der anderen Extension
        TransferLog: Record "PTE Freeze Transfer Log";
        FrzSetupMgt: Codeunit "DXP Freeze Setup Mgt.";
    begin
        if not FrzSetupMgt.IsModuleActivated() then
            exit;
        if not FrzSetupMgt.ArchiveEmailAttachments() then
            exit;

        SentLog.SetRange(Status, SentLog.Status::Sent);
        if SentLog.FindSet() then
            repeat
                if not TransferLog.Get(SentLog."Entry No.") then
                    TransferEntry(SentLog);
            until SentLog.Next() = 0;
    end;

    local procedure TransferEntry(var SentLog: Record "Other Ext. Sent Log")
    var
        TempFrzAttachmentBuffer: Record "DXP FRZ Attachment Buffer" temporary;
        TransferLog: Record "PTE Freeze Transfer Log";
        FrzAttachmentMgt: Codeunit "DXP FRZ Attachment Mgt.";
        FrzQueueBufferMgt: Codeunit "DXP Freeze Queue Buffer Mgt.";
        FrzHelper: Codeunit "DXP Freeze Helper";
        LinkedRecRef: RecordRef;
        SystemIdFieldRef: FieldRef;
        PdfInStr: InStream;
        DocumentNotFoundErr: Label 'Log entry %1: the document %2 could not be found.', Comment = '%1 = Entry No., %2 = Record ID';
    begin
        if not LinkedRecRef.Get(SentLog."Document Record ID") then
            Error(DocumentNotFoundErr, SentLog."Entry No.", Format(SentLog."Document Record ID"));

        SentLog.CalcFields("PDF File");
        SentLog."PDF File".CreateInStream(PdfInStr);
        FrzAttachmentMgt.AddFileFromStream(TempFrzAttachmentBuffer, PdfInStr, SentLog."File Name", LinkedRecRef);

        // InsertQueueBufferEntry statt InsertFREEZEQueueEntryWithAttachments,
        // damit GetEntryNo() danach die Lfd. Nr. des neuen Eintrags liefert
        SystemIdFieldRef := LinkedRecRef.Field(LinkedRecRef.SystemIdNo());
        FrzQueueBufferMgt.InsertQueueBufferEntry(
            SystemIdFieldRef.Value(),
            LinkedRecRef.Number(),
            TempFrzAttachmentBuffer,
            Format(FrzHelper.GetFreezeRecordTypeFromReportSelectionUsage(SentLog."Report Usage")),
            SentLog."Document Date");

        TransferLog.Init();
        TransferLog."Source Entry No." := SentLog."Entry No.";
        TransferLog."Freeze Queue Entry No." := FrzQueueBufferMgt.GetEntryNo();
        TransferLog."Transferred At" := CurrentDateTime();
        TransferLog.Insert();
        Commit();
    end;
}

Wichtige Hinweise:

Beispiel 3: Beim Buchen eine andere Datei archivieren

Freeze ruft beim Buchen für jede Zeile der Berichtsauswahl das Event OnBeforeSaveReportAsPDFInTempBlob auf, bevor es das PDF erzeugt. Ihre Extension kann hier ein eigenes PDF liefern.

codeunit 50102 "PTE Freeze Posting PDF"
{
    [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP FRZ Attachment Mgt.", 'OnBeforeSaveReportAsPDFInTempBlob', '', false, false)]
    local procedure UseOtherPdf(var ReportSelectionUsage: Enum "Report Selection Usage"; var ReportID: Integer; var TempBlobList: Codeunit "Temp Blob List"; var RecVarToPrint: Variant; var CustNoOrBillToNo: Code[20]; var IsHandled: Boolean)
    var
        TempBlob: Codeunit "Temp Blob";
    begin
        if IsHandled then
            exit;
        if ReportSelectionUsage <> ReportSelectionUsage::"S.Invoice" then
            exit;

        // Platzhalter: PDF über die andere Extension erzeugen
        if not CreatePdfWithOtherExtension(RecVarToPrint, TempBlob) then
            exit; // Freeze erzeugt dann wie gewohnt das PDF aus der Berichtsauswahl

        TempBlobList.Add(TempBlob);
        IsHandled := true;
    end;

    local procedure CreatePdfWithOtherExtension(RecVarToPrint: Variant; var TempBlob: Codeunit "Temp Blob"): Boolean
    begin
        // Hier die Funktion der anderen Extension aufrufen
    end;
}

Wichtige Hinweise:

Wichtige Regeln

Weitere Integrationsevents

Diese Events in Freeze sind für das Archivieren zusätzlicher Belege nützlich:

Codeunit Event Wann Wofür
DXP FRZ Attachment Mgt. OnBeforeSaveReportAsPDFInTempBlob Beim Buchen, vor dem Erzeugen jedes PDFs Eigenes PDF statt des Standardberichts liefern (Beispiel 3).
DXP FRZ Attachment Mgt. OnAfterPrintOutgoingSalesDocToPDF, OnAfterPrintOutgoingPurchaseDocToPDF Beim Buchen, nachdem die PDFs erzeugt wurden Dateien ergänzen oder austauschen.
DXP Freeze Helper OnBeforeGetFreezeRecordTypeFromReportSelectionUsage Beim Ermitteln des Mappentyps Einen eigenen Mappentyp für bestimmte Berichtsverwendungen festlegen.
DXP Freeze Queue Buffer Mgt. OnBeforeDoUpdate Beim Anlegen des Warteschlangeneintrags Festlegen, ob ein weiterer Eintrag zum selben Datensatz eine neue Version oder eine neue Mappe wird.
DXP Freeze Queue Processing OnAfterPerformFREEZE, OnAfterProcessWaitingQueueBufferEntry Im Freeze-Job, nach dem Upload Nachverarbeitung, z. B. der anderen Extension den Archivierungsstatus melden.

Setzen Sie IsHandled im Event OnBeforePerformFREEZE nur, wenn Ihre Extension den Upload ins Archiv vollständig selbst übernimmt. Tragen Sie dann die Felder "Archive Record ID" (Archivdatensatz ID) und "API Path" (API Pfad) im Warteschlangeneintrag ein. Ab Freeze 1.30 setzt Freeze den Eintrag sonst auf den Status Fehler.

Testen Ihrer Implementierung

  1. Prüfen Sie, dass Freeze aktiv ist und in der Freeze Einrichtung die Option Email & Anhänge archivieren eingeschaltet ist.
  2. Geben Sie einen Testbeleg über die andere Extension aus.
  3. Öffnen Sie die Freeze Warteschlangeneinträge. Ein neuer Eintrag mit dem richtigen Mappentyp und Bezugsdatum sollte erscheinen.
  4. Warten Sie auf den Freeze-Job (jede Minute). Der Status wechselt über Wartend und Verarbeitet zu Archiviert.
  5. Öffnen Sie den Beleg in Business Central und prüfen Sie in der Archivsuche, dass die Datei dort erscheint.

Verwandte Seiten


Revision #3
Created 2026-11-09 08:40:48 UTC by Bernd Feddersen
Updated 2026-11-09 10:32:34 UTC by Bernd Feddersen