Extension Entwicklung
In diesem Kapitel werden Anwendungsfälle aufgeführt, die bei der Entwicklung einer Extension für Freeze for BC helfen. Dies sind in der Regel Beispiele, die einer Notwendigkeit im Produktivbetrieb eines Partners oder Kunden entwachsen sind.

Wichtig:
Anpassungen dürfen nur durch entsprechend geschulte Berater/Entwickler durchgeführt werden. Diese befinden sich außerdem immer außerhalb des Standard-Supports.

Archivieren von Dateien
Freeze archiviert, abhängig von der Einrichtung, in verschiedenen Situationen automatisch (z.B. nach dem Buchen von Verkaufs- oder Einkaufsbelegen). Im Folgenden wird erläutert, welche Prozeduren ein Entwickler aufrufen kann, um das Archivieren einer Mappe inkl. Dateianhänge zu initiieren.  
 Angenommen, Sie möchten eine neue Archivmappe mit einer oder mehreren Datei(en) archivieren. 
 Zunächst fügen Sie dem temporären Record des Typs "DXP FRZ Attachment Buffer" die entsprechenden Werte hinzu, die ihren Dateien entsprechend. 
 Zur Vereinfachung empfehlen wir die Nutzung der folgenden Prozedur: 
 codeunit 70954897 "DXP FRZ Attachment Mgt.": 
 procedure AddFileFromStream(var TempFRZAttachmentBuffer: Record "DXP FRZ Attachment Buffer" temporary, var InStr: InStream, FileName: Text) 
 Anschließend rufen sie die folgende Prozedur auf, um einen Eintrag in der Freeze Verarbeitungswarteschlange zu erstellen, der Mappendetails und Anhänge enthält, die zur Erstellung des Archiveintrags verwendet werden. 
 
 codeunit 70954899 "DXP Freeze Queue Buffer Mgt.": 
 
 
 procedure InsertQueueBufferEntry(RecSystemID: Guid, RecTableNo: Integer, var FRZAttachmentBufferTemp: Record "DXP FRZ Attachment Buffer" temporary, ArchiveRecordID: Guid, FrzRecordType: Text[35], ReferenceDate: Date, RecordTitle: Text[250]): Boolean 
 Die Prozeduren sind überladen - wählen Sie die passende Variante für ihr Szenario aus. 
 Sofern Sie eine eigene Logik implementieren möchten, um nach der Buchung eines Verkaufs- oder Einkaufsbelegs eine Archivierung zu initiieren, deaktivieren Sie die automatische Archivierung in der Freeze Einrichtung, um unerwünschte Redundanzen zu vermeiden. 
  

Anhang Download als Zip
Diese Dokumentation bietet umfassende Anleitung für externe AL-Entwickler zur effektiven Nutzung der DXP Freeze Anhang-Download-Funktionalität in ihren Business Central Erweiterungen. 
 Überblick 
 Die DXP Freeze Result Management Codeunit bietet zwei Hauptmethoden zum Herunterladen archivierter Anhänge als ZIP-Dateien: 
 
 
 
 
 
 
 
 
 
 DownloadAttachmentsAsZipWithPagination  - Lädt Anhänge aus Suchanfrage-Ergebnissen mit Paginierung herunter 
 DownloadAttachmentsAsZipFromRecord  - Lädt Anhänge von spezifischen Business Central Datensätzen herunter 
 
 
 
 
 
 
 
 
 
 Beide Methoden organisieren Anhänge in strukturierte ZIP-Archive mit umfassenden Metadaten für Audit- und Nachverfolgungszwecke. 
 Methode 1: DownloadAttachmentsAsZipWithPagination 
 Zweck 
 Lädt alle Anhänge aus einem Suchanfrage-Ergebnissatz herunter und verarbeitet Ergebnisse seitenweise, um große Datensätze effizient zu handhaben. Die Anhänge jedes Datensatzes werden in individuelle ZIP-Dateien innerhalb eines Haupt-ZIP-Archivs organisiert. 
 Verfügbare Überladungen 
 1. Grundlegende Verwendung 
 
 
 
 
 
 
 
 
 procedure DownloadAttachmentsAsZipWithPagination(SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer): Boolean
 
 
 
 
 
 
 
 
 
 2. Mit Filtern 
 
 
 
 
 
 
 
 
 procedure DownloadAttachmentsAsZipWithPagination(SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer; FilenameFilter: Text; FileExtensionFilter: Text): Boolean
 
 
 
 
 
 
 
 
 
 3. Vollständige Kontrolle 
 
 
 
 
 
 
 
 
 procedure DownloadAttachmentsAsZipWithPagination(SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer; FilenameFilter: Text; FileExtensionFilter: Text; StoreApiLink: Text; RecordsPerPage: Integer; SuppressDialog: Boolean): Boolean
 
 
 
 
 
 
 
 
 
 4. Vorab gefüllte Datensätze (Erweitert) 
 
 
 
 
 
 
 
 
 procedure DownloadAttachmentsAsZipWithPagination(var TempFrzResultQueryHeader: Record "DXP FRZ Query Result Header" temporary; var TempFrzResultRecordHeader: Record "DXP FRZ Record Result Header" temporary; var TempFrzResultRecordField: Record "DXP FRZ Result Record-Field" temporary; var TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary; SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer; FilenameFilter: Text; FileExtensionFilter: Text; SuppressDialog: Boolean): Boolean
 
 
 
 
 
 
 
 
 
 Parameter 
 
 
 
 
 
 
 
 
 
 
 
 
 Parameter 
 Typ 
 Beschreibung 
 
 
 
 
 SearchQuery 
 Text 
 Freeze-Suchanfrage-String. Wenn leer in vorab gefüllter Überladung, verwendet vorhandene Anfrage oder führt Suche erneut aus 
 
 
 ZipArchive 
 Codeunit “Data Compression” 
 ZIP-Archiv-Objekt, das die heruntergeladenen Dateien enthalten wird 
 
 
 AttachmentCount 
 Integer (var) 
 Gibt die Gesamtanzahl der heruntergeladenen Anhänge zurück 
 
 
 FilenameFilter 
 Text 
 Filter für Anhangsdateinamen (z.B. ‘ .pdf’, 'rechnung ’) 
 
 
 FileExtensionFilter 
 Text 
 Filter für Dateierweiterungen (z.B. ‘pdf’, ‘docx’) 
 
 
 StoreApiLink 
 Text 
 Optional spezifischer Store-API-Link 
 
 
 RecordsPerPage 
 Integer 
 Anzahl Datensätze pro Seite (Standard: 100) 
 
 
 SuppressDialog 
 Boolean 
 Ob Fortschrittsdialog unterdrückt werden soll 
 
 
 
 
 
 
 
 
 
 
 
 
 Rückgabewert 
 
 
 
 
 
 
 
 
 
 Boolean :  true  wenn Anhänge gefunden und heruntergeladen wurden;  false  andernfalls 
 
 
 
 
 
 
 
 
 
 Verwendungsbeispiele 
 Grundlegender Download 
 
 
 
 
 
 
 
 
 procedure DownloadSearchResults()
var
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 ZipArchive: Codeunit "Data Compression";
 FileMgt: Codeunit "File Management";
 TempBlob: Codeunit "Temp Blob";
 AttachmentCount: Integer;
 InStr: InStream;
 OutStr: OutStream;
 SearchQuery: Text;
begin
 SearchQuery := 'rechnung AND 2024';
 
 if ResultMgt.DownloadAttachmentsAsZipWithPagination(SearchQuery, ZipArchive, AttachmentCount) then begin
 // ZIP in Datei speichern
 TempBlob.CreateOutStream(OutStr);
 ZipArchive.SaveZipArchive(OutStr);
 TempBlob.CreateInStream(InStr);
 
 FileMgt.DownloadFromStreamHandler(InStr, '', '', '', 'Suchergebnisse.zip');
 Message('Erfolgreich %1 Anhänge heruntergeladen.', AttachmentCount);
 end else
 Message('Keine Anhänge für die Suchanfrage gefunden.');
end;
 
 
 
 
 
 
 
 
 
 Mit Filtern 
 
 
 
 
 
 
 
 
 procedure DownloadPDFInvoices()
var
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 ZipArchive: Codeunit "Data Compression";
 AttachmentCount: Integer;
 SearchQuery: Text;
begin
 SearchQuery := 'typ:rechnung';
 
 if ResultMgt.DownloadAttachmentsAsZipWithPagination(
 SearchQuery, 
 ZipArchive, 
 AttachmentCount, 
 '*.pdf', // Nur PDF-Dateien
 'pdf' // Dateierweiterungsfilter
 ) then begin
 // ZIP-Archiv verarbeiten
 ProcessDownloadedFiles(ZipArchive, AttachmentCount);
 end;
end;
 
 
 
 
 
 
 
 
 
 Verwendung vorab gefüllter Datensätze 
 
 
 
 
 
 
 
 
 procedure DownloadFromExistingResults()
var
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 TempFrzResultQueryHeader: Record "DXP FRZ Query Result Header" temporary;
 TempFrzResultRecordHeader: Record "DXP FRZ Record Result Header" temporary;
 TempFrzResultRecordField: Record "DXP FRZ Result Record-Field" temporary;
 TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary;
 ZipArchive: Codeunit "Data Compression";
 AttachmentCount: Integer;
begin
 // Angenommen, diese Datensätze sind bereits aus einer vorherigen Suche gefüllt
 PopulateSearchResults(TempFrzResultQueryHeader, TempFrzResultRecordHeader, TempFrzResultRecordField, TempFrzAttachmentResult);
 
 // Download mit vorhandenen Ergebnissen ohne erneute Suchausführung
 if ResultMgt.DownloadAttachmentsAsZipWithPagination(
 TempFrzResultQueryHeader,
 TempFrzResultRecordHeader,
 TempFrzResultRecordField,
 TempFrzAttachmentResult,
 'rechnungssuche', // SearchQuery - wenn leer, wird Suche erneut ausgeführt
 ZipArchive,
 AttachmentCount,
 '', // Kein Dateinamenfilter
 '', // Kein Erweiterungsfilter
 true // Dialog unterdrücken
 ) then begin
 ProcessDownloadedFiles(ZipArchive, AttachmentCount);
 end;
end;
 
 
 
 
 
 
 
 
 
 ZIP-Struktur (Paginierung) 
 
 
 
 
 
 
 
 
 Suchergebnisse.zip
├── export-metadata.json
├── Rechnung_001_V1_20241201_1430.zip
│ ├── {GUID}_rechnung.pdf
│ └── {GUID}_begleitdokument.docx
├── Bestellung_002_V2_20241202_0900.zip
│ └── {GUID}_bestelldokument.pdf
└── Vertrag_003_V1_20241203_1200.zip
 ├── {GUID}_vertrag.pdf
 └── {GUID}_nachtrag.pdf
 
 
 
 
 
 
 
 
 
 Methode 2: DownloadAttachmentsAsZipFromRecord 
 Zweck 
 Lädt Anhänge von spezifischen Business Central Datensätzen herunter. Die Anhänge jedes ausgewählten Datensatzes werden in individuelle ZIP-Dateien innerhalb eines Haupt-ZIP-Archivs organisiert. 
 Verfügbare Überladungen 
 1. Grundlegende Verwendung 
 
 
 
 
 
 
 
 
 procedure DownloadAttachmentsAsZipFromRecord(var SelectedRecord: RecordRef; var ZipArchive: Codeunit "Data Compression"): Boolean
 
 
 
 
 
 
 
 
 
 2. Mit Filtern 
 
 
 
 
 
 
 
 
 procedure DownloadAttachmentsAsZipFromRecord(var SelectedRecord: RecordRef; var ZipArchive: Codeunit "Data Compression"; FilenameFilter: Text; FileExtensionFilter: Text): Boolean
 
 
 
 
 
 
 
 
 
 Parameter 
 
 
 
 
 
 
 
 
 
 
 
 
 Parameter 
 Typ 
 Beschreibung 
 
 
 
 
 SelectedRecord 
 RecordRef (var) 
 RecordRef mit den ausgewählten Business Central Datensätzen 
 
 
 ZipArchive 
 Codeunit “Data Compression” 
 ZIP-Archiv-Objekt, das die heruntergeladenen Dateien enthalten wird 
 
 
 FilenameFilter 
 Text 
 Filter für Anhangsdateinamen 
 
 
 FileExtensionFilter 
 Text 
 Filter für Dateierweiterungen 
 
 
 
 
 
 
 
 
 
 
 
 
 Rückgabewert 
 
 
 
 
 
 
 
 
 
 Boolean :  true  wenn Anhänge gefunden und heruntergeladen wurden;  false  andernfalls 
 
 
 
 
 
 
 
 
 
 Verwendungsbeispiele 
 Download von Verkaufsrechnungen 
 
 
 
 
 
 
 
 
 procedure DownloadInvoiceAttachments()
var
 SalesInvoiceHeader: Record "Sales Invoice Header";
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 ZipArchive: Codeunit "Data Compression";
 RecordRef: RecordRef;
 HasAttachments: Boolean;
begin
 // Spezifische Rechnungen auswählen
 SalesInvoiceHeader.SetRange("Posting Date", DMY2Date(1, 1, 2024), DMY2Date(31, 12, 2024));
 SalesInvoiceHeader.SetFilter("Sell-to Customer No.", '10000|20000');
 
 if SalesInvoiceHeader.FindSet() then begin
 RecordRef.GetTable(SalesInvoiceHeader);
 
 HasAttachments := ResultMgt.DownloadAttachmentsAsZipFromRecord(RecordRef, ZipArchive);
 
 if HasAttachments then
 SaveZipFile(ZipArchive, 'Rechnungsanhänge.zip')
 else
 Message('Keine Anhänge für die ausgewählten Rechnungen gefunden.');
 end;
end;
 
 
 
 
 
 
 
 
 
 Download mit Filtern von Seite 
 
 
 
 
 
 
 
 
 // In einer Seitenerweiterung
action(DownloadAttachmentsFiltered)
{
 Caption = 'Gefilterte Anhänge herunterladen';
 Image = ExportFile;
 
 trigger OnAction()
 var
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 ZipArchive: Codeunit "Data Compression";
 RecordRef: RecordRef;
 FilenameFilter: Text;
 FileExtensionFilter: Text;
 begin
 // Filterdialog anzeigen
 if ShowFilterDialog(FilenameFilter, FileExtensionFilter) then begin
 CurrPage.SetSelectionFilter(Rec);
 RecordRef.GetTable(Rec);
 
 if ResultMgt.DownloadAttachmentsAsZipFromRecord(
 RecordRef, 
 ZipArchive, 
 FilenameFilter, 
 FileExtensionFilter
 ) then
 DownloadZipFile(ZipArchive, 'GefilterteAnhänge.zip');
 end;
 end;
}
 
 
 
 
 
 
 
 
 
 ZIP-Struktur (Datensätze) 
 
 
 
 
 
 
 
 
 Datensatzanhänge.zip
├── export-metadata.json
├── Sales_Invoice_Header_Unternehmen_SI-001.zip
│ ├── {GUID}_rechnung.pdf
│ └── {GUID}_bedingungen.pdf
├── Sales_Invoice_Header_Unternehmen_SI-002.zip
│ └── {GUID}_rechnung.pdf
└── Sales_Invoice_Header_Unternehmen_SI-003.zip
 ├── {GUID}_rechnung.pdf
 ├── {GUID}_lieferschein.pdf
 └── {GUID}_quittung.jpg
 
 
 
 
 
 
 
 
 
 Metadaten-Struktur 
 Beide Methoden generieren umfassende Metadaten in  export-metadata.json : 
 Paginierungs-Export-Metadaten 
 
 
 
 
 
 
 
 
 { 
 "exportInfo" : { 
 "exportTimestamp" : "2024-12-19T10:13:52.248Z" , 
 "exportedBy" : "USER001" , 
 "searchQuery" : "typ:rechnung AND jahr:2024" , 
 "totalRecordsFound" : 150 , 
 "totalPages" : 15 , 
 "exportType" : "paginated-search" , 
 "description" : "Freeze Suchanfrage Export" 
 } , 
 "appliedFilters" : { 
 "filenameFilter" : "*.pdf" , 
 "fileExtensionFilter" : "pdf" 
 } , 
 "statistics" : { 
 "pagesProcessed" : 15 , 
 "totalRecordsProcessed" : 150 , 
 "recordsWithAttachments" : 120 , 
 "recordsWithoutAttachments" : 30 , 
 "totalAttachments" : 245 , 
 "exportCompletedAt" : "2024-12-19T10:15:33.021Z" 
 } , 
 "records" : [ 
 { 
 "recordId" : "{GUID}" , 
 "title" : "Rechnung REG-2024-001" , 
 "version" : 1 , 
 "archivedAt" : "2024-12-01T09:30:00Z" , 
 "archivedBy" : "SYSTEM" , 
 "type" : "Verkaufsrechnung" , 
 "masterId" : "{GUID}" , 
 "attachmentCount" : 3 , 
 "hasAttachments" : true , 
 "zipFile" : "Rechnung_REG-2024-001_V1_20241201_0930.zip" 
 } 
 ] 
 } 
 
 
 
 
 
 
 
 
 
 Datensatz-Export-Metadaten 
 
 
 
 
 
 
 
 
 { 
 "exportTimestamp" : "2024-12-19T14:30:00Z" , 
 "exportedBy" : "USER001" , 
 "totalRecordsProcessed" : 25 , 
 "description" : "DXP Freeze Anhänge Export" , 
 "sourceTable" : { 
 "tableNumber" : 112 , 
 "tableName" : "Sales Invoice Header" , 
 "tableCaption" : "Geb. Verkaufsrechnung" 
 } , 
 "appliedFilters" : { 
 "filenameFilter" : "*.pdf" , 
 "fileExtensionFilter" : "pdf" 
 } , 
 "statistics" : { 
 "totalAttachments" : 45 , 
 "recordsWithAttachments" : 20 , 
 "recordsWithoutAttachments" : 5 , 
 "totalZipFiles" : 20 
 } , 
 "records" : [ 
 { 
 "recordId" : "Sales Invoice Header: Unternehmen, SI-001" , 
 "systemId" : "{GUID}" , 
 "primaryKey" : { 
 "fields" : [ 
 { 
 "fieldName" : "Nr." , 
 "fieldValue" : "SI-001" , 
 "fieldType" : "Code" 
 } 
 ] 
 } , 
 "hasAttachments" : true , 
 "attachmentCount" : 2 , 
 "zipFile" : "Sales_Invoice_Header_Unternehmen_SI-001.zip" 
 } 
 ] 
 } 
 
 
 
 
 
 
 
 
 
 Leistungsüberlegungen 
 Paginierungsmethode 
 
 
 
 
 
 
 
 
 
 Große Ergebnismengen : Automatische Handhabung der Paginierung zur effizienten Verarbeitung großer Datensätze 
 Speicherverwaltung : Verarbeitet eine Seite nach der anderen, bereinigt Speicher zwischen Seiten 
 Fortschrittsverfolgung : Zeigt Echtzeit-Fortschritt für länger dauernde Operationen 
 Empfohlen für : Suchanfragen, die Hunderte oder Tausende von Datensätzen zurückgeben können 
 
 
 
 
 
 
 
 
 
 Datensatzmethode 
 
 
 
 
 
 
 
 
 
 Ausgewählte Datensätze : Verarbeitet nur die spezifisch ausgewählten Datensätze 
 Direkte Verarbeitung : Kein Paginierungs-Overhead für kleinere Datensätze 
 Stapelverarbeitung : Effizient für die Verarbeitung spezifischer Datensatzmengen 
 Empfohlen für : Gezielte Downloads von spezifischen Business Central Datensätzen 
 
 
 
 
 
 
 
 
 
 Fehlerbehandlung 
 Beide Methoden beinhalten umfassende Fehlerbehandlung: 
 Häufige Szenarien 
 
 
 
 
 
 
 
 
 
 Keine Ergebnisse gefunden : Gibt  false  zurück, wenn keine Datensätze oder Anhänge gefunden werden 
 Berechtigungsprobleme : Schließt automatisch Datensätze aus, auf die der Benutzer nicht zugreifen kann 
 API-Fehler : Zuverlässiger Umgang mit API-Kommunikationsfehlern 
 Leere Filter : Behandelt leere oder ungültige Filterparameter 
 
 
 
 
 
 
 
 
 
 Best Practices 
 
 
 
 
 
 
 
 
 // Rückgabewert immer prüfen
if not ResultMgt.DownloadAttachmentsAsZipWithPagination(SearchQuery, ZipArchive, AttachmentCount) then begin
 Message('Keine Anhänge gefunden oder Download fehlgeschlagen.');
 exit;
end;

// Anhanganzahl validieren
if AttachmentCount = 0 then begin
 Message('Suche abgeschlossen, aber keine Anhänge entsprechen den Kriterien.');
 exit;
end;

// Große Downloads handhaben
if AttachmentCount > 1000 then
 if not Confirm('Dies wird %1 Anhänge herunterladen. Fortfahren?', false, AttachmentCount) then
 exit;
 
 
 
 
 
 
 
 
 
 Integrationsereignisse 
 Beide Methoden unterstützen Integrationsereignisse zur Anpassung: 
 Verfügbare Ereignisse 
 
 
 
 
 
 
 
 
 
 OnBeforeDownloadAttachmentsAsZip : Verhalten vor Download-Start modifizieren 
 OnBeforeProcessAttachmentForZip : Einzelne Anhänge überspringen oder modifizieren 
 OnAfterGetAttachmentBase64 : Anhanginhalt nach Abruf modifizieren 
 OnAfterAddAttachmentToZip : Aktionen nach Hinzufügung zum ZIP durchführen 
 OnNoAttachmentsFound : Szenario ohne Anhänge behandeln 
 
 
 
 
 
 
 
 
 
 Integrationsbeispiel 
 
 
 
 
 
 
 
 
 [EventSubscriber(ObjectType::Codeunit, Codeunit::"DXP FRZ Result Mgt.", 'OnBeforeProcessAttachmentForZip', '', false, false)]
local procedure OnBeforeProcessAttachmentForZip(var TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary; var IsHandled: Boolean)
begin
 // Anhänge größer als 10MB überspringen
 if TempFrzAttachmentResult.Filesize > 10485760 then
 IsHandled := true;
end;
 
 
 
 
 
 
 
 
 
 Dateinamen-Konventionen 
 Automatische Bereinigung 
 Alle Dateinamen werden automatisch mit der  SanitizeFileName -Methode bereinigt: 
 
 
 
 
 
 
 
 
 
 Ungültige Zeichen ( < > : " / \ | ? * ) werden durch Unterstriche ersetzt 
 Leerzeichen werden durch Unterstriche ersetzt 
 Maximale Dateinamenlängen werden erzwungen 
 
 
 
 
 
 
 
 
 
 Eindeutige Benennung 
 
 
 
 
 
 
 
 
 Einzelne Dateien : Enthalten Anhang-GUID-Präfix zur Eindeutigkeit 
 ZIP-Dateien : Enthalten Datensatzinformationen und Zeitstempel 
 Keine Konflikte : Garantiert eindeutige Namen innerhalb jedes ZIP-Archivs 
 
 
 
 
 
 
 
   
  

Freeze Integration in benutzerdefinierte Seiten
Überblick 
 Die DEXPRO Freeze Extension bietet Dokumentenarchivierungs-Funktionalität, die es Benutzern ermöglicht, Dokumente, Anhänge und zugehörige Daten für jeden Business Central-Datensatz zu speichern und abzurufen. Dieser Leitfaden erklärt, wie Sie die Freeze-Funktionalität in benutzerdefinierte Seiten integrieren. 
 Kernkomponenten 
 1. Quick Freeze Infobox 
 Die zentrale Komponente ist die  "DXP FRZ Quick Freeze FB"  Seite, die folgendes bietet: 
 
 Drag-and-Drop Datei-Upload-Funktionalität 
 Anzeige archivierter Datensätze bezogen auf den aktuellen Datensatz 
 Schnellzugriff auf Freeze-Operationen 
 
 2. Management Codeunits 
 
 "DXP Extension Mgt."  - Verwaltet Freeze-Warteschlangen-Operationen und Hintergrundverarbeitung 
 "DXP Freeze Search Mgt."  - Verwaltet Suchfunktionalität für archivierte Datensätze 
 "DXP FRZ Result Mgt."  - Verwaltet Ergebnisanzeige und Archiv-Ansicht 
 
 3. Wichtige Tabellen 
 
 "DXP Frz Recent Record"  - Speichert aktuelle Freeze-Einträge 
 "DXP Freeze Setup"  - Konfigurationseinstellungen 
 "DXP Freeze Record Type"  - Verfügbare Datensatztypen für die Archivierung 
 
 Implementierungsschritte 
 Schritt 1: Infobox hinzufügen 
 Fügen Sie die Quick Freeze Infobox zum Layout-Bereich Ihrer Seite hinzu: 
 layout
{
 addfirst(factboxes)
 {
 part("DXP Quick Archive"; "DXP FRZ Quick Freeze FB")
 {
 ApplicationArea = All;
 SubPageLink = "Record System ID" = field(SystemId),
 "Record Table No." = const(Database::"Ihr Tabellenname");
 SubPageView = sorting("Entry No.") order(descending);
 }
 }
}
 
 Wichtige Hinweise: 
 
 Ersetzen Sie  Database::"Ihr Tabellenname"  mit der entsprechenden Tabellenkonstante 
 
 Schritt 2: Navigationsaktionen hinzufügen 
 Fügen Sie Freeze-bezogene Aktionen zum Aktionsbereich der Seite hinzu: 
 actions
{
 addfirst(navigation)
 {
 action("DXP Freeze")
 {
 Caption = 'Freeze öffnen';
 ApplicationArea = All;
 Image = Archive;
 ToolTip = 'Öffnet das Freeze-Archiv und zeigt mit dem ausgewählten Datensatz verknüpfte Anhänge an.';
 ShortcutKey = 'Ctrl+Alt+F';
 trigger OnAction()
 var
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 begin
 ResultMgt.SubmitSearchAndShowResults(Rec.RecordId(), FrzSearchMgt.GetSearchCombinationForTable(Rec.SystemId, Rec.RecordId.TableNo()));
 end;
 }
 }
}
 
 Schritt 3: Hervorgehobene Aktionen hinzufügen 
 actions
{
 addfirst(Category_Category16)
 {
 actionref("DXP Freeze_Promoted"; "DXP Freeze")
 {
 }
 }
 modify(Category_Category16)
 {
 Caption = 'DEXPRO Freeze', Locked = true;
 }
}
 
 Schritt 4: Seiten-Trigger hinzufügen 
 trigger OnAfterGetCurrRecord()
begin
 CurrPage."DXP Quick Archive".Page.SetSourceRecord(Rec.RecordId());
end;
 
 Schritt 5: Variablen deklarieren 
 var
 ExtMgt: Codeunit "DXP Extension Mgt.";
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
 
 Vollständiges Beispiel 
 Hier ist ein vollständiges Beispiel für eine benutzerdefinierte Belegseite: 
 pageextension 50000 "Mein benutzerdef. Beleg Erw." extends "Mein benutzerdefinierter Beleg"
{
 layout
 {
 addfirst(factboxes)
 {
 part("DXP Quick Archive"; "DXP FRZ Quick Freeze FB")
 {
 ApplicationArea = All;
 SubPageLink = "Record System ID" = field(SystemId),
 "Record Table No." = const(Database::"Ihr Tabellenname");
 SubPageView = sorting("Entry No.") order(descending);
 }
 }
 }
 
 actions
 {
 addfirst(navigation)
 {
 action("DXP Freeze")
 {
 Caption = 'Freeze öffnen';
 ApplicationArea = All;
 Image = Archive;
 ToolTip = 'Öffnet das Freeze-Archiv und zeigt mit dem ausgewählten Datensatz verknüpfte Anhänge an.';
 ShortcutKey = 'Ctrl+Alt+F';
 trigger OnAction()
 var
 ResultMgt: Codeunit "DXP FRZ Result Mgt.";
 begin
 ResultMgt.SubmitSearchAndShowResults(Rec.RecordId(), FrzSearchMgt.GetSearchCombinationForTable(Rec.SystemId, Rec.RecordId.TableNo()));
 end;
 }
 }
 
 addfirst(Category_Category16)
 {
 actionref("DXP Freeze_Promoted"; "DXP Freeze")
 {
 }
 }
 modify(Category_Category16)
 {
 Caption = 'DEXPRO Freeze', Locked = true;
 }
 }

 trigger OnAfterGetCurrRecord()
 begin
 CurrPage."DXP Quick Archive".Page.SetSourceRecord(Rec.RecordId());
 end;

 var
 ExtMgt: Codeunit "DXP Extension Mgt.";
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
}
 
 Zusätzliche Suchabfragen einrichten 
 Um auch Archiveinträge anhand von nicht direkt über die System-ID/Tabellennummer verbundenen Datensätzen (via BC archiviert) anzeigen zu können, können zusätzliche Suchabfragen eingerichtet werden. Dies ist hier dokumentiert:  https://docs.squeeze.one/books/freeze-for-dynamics-365-bc-de-de/page/zusatzliche-suchabfragen 
 Testen Ihrer Implementierung 
 
 Navigieren Sie zu Ihrer erweiterten Seite 
 Überprüfen Sie, ob die Quick Freeze Infobox erscheint 
 Testen Sie die Aktion "Freeze öffnen" (Strg+Alt+F) 
 Laden Sie Testdateien per Drag-and-Drop hoch 
 Überprüfen Sie, ob archivierte Datensätze in der Infobox erscheinen 
 
 Dieses Integrationsmuster gewährleistet konsistente Freeze-Funktionalität über alle Business Central-Seiten hinweg und behält dabei die von der DEXPRO Freeze Extension etablierte Benutzererfahrung bei.

Anhang Download
Diese Dokumentation bietet umfassende Anleitung für externe AL-Entwickler zum Abrufen und Herunterladen einzelner Anhänge aus DXP Freeze für verknüpfte Business Central Datensätze. 
 Überblick 
 Die DXP Freeze Result Management Codeunit bietet Methoden zum direkten Zugriff auf einzelne Anhänge archivierter Datensätze: 
 
 GetAttachments  - Lädt Metadaten aller Anhänge eines Datensatzes 
 GetSpecificRecordAttachment  - Lädt den Inhalt eines spezifischen Anhangs als Base64 
 Kombinierte Verwendung ermöglicht gezielte Filterung und Download einzelner Dateien 
 
 Diese Methoden ermöglichen präzise Kontrolle über welche Anhänge abgerufen werden und wie sie verarbeitet werden, ohne ZIP-Archive zu erstellen. 
 
 Methode 1: GetAttachments 
 Zweck 
 Ruft Metadaten aller Anhänge eines archivierten Datensatzes ab. Diese Methode füllt einen temporären  DXP FRZ Attachment Result  Record mit Informationen über verfügbare Anhänge ohne den eigentlichen Dateiinhalt herunterzuladen. 
 Verfügbare Überladungen 
 1. Standard-Verwendung 
 procedure GetAttachments(RecordHeaderID: Guid; RecordHeaderFileLink: Text[2048]; var TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary)
 
 2. Mit Kontrolle über Datenlöschung 
 procedure GetAttachments(RecordHeaderID: Guid; RecordHeaderFileLink: Text[2048]; var TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary; ClearAttachmentTable: Boolean)
 
 Parameter 
 
 
 
 Parameter 
 Typ 
 Beschreibung 
 
 
 
 
 RecordHeaderID 
 Guid 
 Eindeutige ID des Freeze-Datensatzes 
 
 
 RecordHeaderFileLink 
 Text[2048] 
 API-Link zum Datensatz (aus  DXP FRZ Record Result Header ."File Link") 
 
 
 TempFrzAttachmentResult 
 Record (temporary, var) 
 Temporärer Record, der mit Anhang-Metadaten gefüllt wird 
 
 
 ClearAttachmentTable 
 Boolean 
 true  = Record vor Befüllung löschen;  false  = zu bestehenden Einträgen hinzufügen 
 
 
 
 Rückgabewert 
 Keine - Die Methode füllt den übergebenen temporären Record mit Anhang-Metadaten. 
 Anhang-Metadaten-Felder 
 Jeder Eintrag in  TempFrzAttachmentResult  enthält: 
 
 
 
 Feld 
 Beschreibung 
 
 
 
 
 ID 
 Eindeutige Anhang-ID (Guid) 
 
 
 Record Header Id 
 Verknüpfung zum übergeordneten Datensatz 
 
 
 Filename 
 Dateiname mit Erweiterung 
 
 
 File Extension 
 Dateierweiterung (automatisch aus Filename extrahiert) 
 
 
 Filesize 
 Größe in Bytes 
 
 
 Author 
 Ersteller des Anhangs 
 
 
 Archived at 
 Archivierungszeitpunkt 
 
 
 File Link 
 API-Link zum Datensatz 
 
 
 
 Verwendungsbeispiel 
 procedure ListAttachmentsForSalesInvoice(SalesInvoiceNo: Code[20])
var
 SalesInvoiceHeader: Record "Sales Invoice Header";
 TempFrzResultQueryHeader: Record "DXP FRZ Query Result Header" temporary;
 TempFrzResultRecordHeader: Record "DXP FRZ Record Result Header" temporary;
 TempFrzResultRecordField: Record "DXP FRZ Result Record-Field" temporary;
 TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary;
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
 FrzResultMgt: Codeunit "DXP FRZ Result Mgt.";
 FrzApiMgt: Codeunit "DXP Freeze API Mgt.";
 QueryResult: JsonObject;
 SearchQuery: Text;
begin
 if not SalesInvoiceHeader.Get(SalesInvoiceNo) then
 Error('Rechnung %1 nicht gefunden.', SalesInvoiceNo);

 // Suchanfrage für diesen Datensatz erstellen
 SearchQuery := FrzSearchMgt.GetSearchCombinationForTable(
 SalesInvoiceHeader.SystemId, 
 Database::"Sales Invoice Header"
 );

 // Freeze durchsuchen
 QueryResult := FrzApiMgt.SubmitSearch(SearchQuery);

 // Ergebnisse verarbeiten - dies füllt den Record Header
 FrzResultMgt.CreateResult(
 QueryResult,
 TempFrzResultQueryHeader,
 TempFrzResultRecordHeader,
 TempFrzResultRecordField,
 TempFrzAttachmentResult,
 SearchQuery
 );

 // Prüfen ob Datensatz gefunden wurde
 if TempFrzResultRecordHeader.FindFirst() then begin
 // Anhänge für diesen Record Header abrufen
 FrzResultMgt.GetAttachments(
 TempFrzResultRecordHeader.ID, 
 TempFrzResultRecordHeader."File Link", 
 TempFrzAttachmentResult
 );

 // Anhänge durchlaufen
 if TempFrzAttachmentResult.FindSet() then
 repeat
 //Verarbeitung der Anhänge
 until TempFrzAttachmentResult.Next() = 0;
 end else
 Message('Keine archivierten Anhänge für Rechnung %1 gefunden.', SalesInvoiceNo);
end;
 
 
 Methode 2: GetSpecificRecordAttachment (Freeze API Mgt.) 
 Zweck 
 Lädt den tatsächlichen Inhalt eines spezifischen Anhangs als Base64-kodierten String herunter. Diese Methode wird typischerweise nach  GetAttachments  verwendet, um ausgewählte Anhänge herunterzuladen. 
 Verfügbare Überladungen 
 1. Mit automatischem Browser-Download 
 procedure GetSpecificRecordAttachment(FileLink: Text; AttachmentID: Guid; pFileName: Text): Text
 
 2. Mit Kontrolle über Browser-Download 
 procedure GetSpecificRecordAttachment(FileLink: Text; AttachmentID: Guid; pFileName: Text; DownloadFromStream: Boolean): Text
 
 Parameter 
 
 
 
 Parameter 
 Typ 
 Beschreibung 
 
 
 
 
 FileLink 
 Text 
 API-Link zum Datensatz (aus  TempFrzAttachmentResult ."File Link") 
 
 
 AttachmentID 
 Guid 
 Eindeutige Anhang-ID (aus  TempFrzAttachmentResult .ID) 
 
 
 pFileName 
 Text 
 Dateiname für Download (aus  TempFrzAttachmentResult .Filename) 
 
 
 DownloadFromStream 
 Boolean 
 true  = Sofortiger Browser-Download;  false  = Nur Base64 zurückgeben 
 
 
 
 Rückgabewert 
 
 Text : Base64-kodierter Inhalt der Datei 
 Leerer String wenn Anhang nicht gefunden oder Fehler auftritt 
 
 Verwendungsbeispiele 
 Beispiel 1: Einzelnen Anhang sofort herunterladen 
 procedure DownloadFirstPDFAttachment(SalesInvoiceNo: Code[20])
var
 SalesInvoiceHeader: Record "Sales Invoice Header";
 TempFrzResultRecordHeader: Record "DXP FRZ Record Result Header" temporary;
 TempFrzResultRecordField: Record "DXP FRZ Result Record-Field" temporary;
 TempFrzResultQueryHeader: Record "DXP FRZ Query Result Header" temporary;
 TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary;
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
 FrzResultMgt: Codeunit "DXP FRZ Result Mgt.";
 FrzApiMgt: Codeunit "DXP Freeze API Mgt.";
 QueryResult: JsonObject;
 SearchQuery: Text;
begin
 if not SalesInvoiceHeader.Get(SalesInvoiceNo) then
 Error('Rechnung %1 nicht gefunden.', SalesInvoiceNo);

 // Suchanfrage erstellen
 SearchQuery := FrzSearchMgt.GetSearchCombinationForTable(
 SalesInvoiceHeader.SystemId, 
 Database::"Sales Invoice Header"
 );

 // Freeze durchsuchen
 QueryResult := FrzApiMgt.SubmitSearch(SearchQuery);

 // Ergebnisse verarbeiten
 FrzResultMgt.CreateResult(
 QueryResult,
 TempFrzResultQueryHeader,
 TempFrzResultRecordHeader,
 TempFrzResultRecordField,
 TempFrzAttachmentResult,
 SearchQuery
 );

 // Nach PDF-Anhängen filtern
 TempFrzAttachmentResult.SetRange("File Extension", 'pdf');
 
 if TempFrzAttachmentResult.FindFirst() then begin
 // Direkter Download im Browser
 FrzApiMgt.GetSpecificRecordAttachment(
 TempFrzAttachmentResult."File Link",
 TempFrzAttachmentResult.ID,
 TempFrzAttachmentResult.Filename
 );
 
 Message('PDF-Anhang %1 wird heruntergeladen.', TempFrzAttachmentResult.Filename);
 end else
 Message('Keine PDF-Anhänge für Rechnung %1 gefunden.', SalesInvoiceNo);
end;
 
 Beispiel 2: Base64-Inhalt für weitere Verarbeitung 
 procedure GetAttachmentAsBase64(RecordRef: RecordRef; var AttachmentBase64: Text; var AttachmentFilename: Text): Boolean
var
 TempFrzResultRecordHeader: Record "DXP FRZ Record Result Header" temporary;
 TempFrzResultRecordField: Record "DXP FRZ Result Record-Field" temporary;
 TempFrzResultQueryHeader: Record "DXP FRZ Query Result Header" temporary;
 TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary;
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
 FrzResultMgt: Codeunit "DXP FRZ Result Mgt.";
 FrzApiMgt: Codeunit "DXP Freeze API Mgt.";
 SystemIdFieldRef: FieldRef;
 QueryResult: JsonObject;
 SystemId: Guid;
 SearchQuery: Text;
begin
 // SystemId aus RecordRef extrahieren
 SystemIdFieldRef := RecordRef.Field(RecordRef.SystemIdNo());
 SystemId := SystemIdFieldRef.Value();

 // Suchanfrage erstellen
 SearchQuery := FrzSearchMgt.GetSearchCombinationForTable(SystemId, RecordRef.Number());

 // Freeze durchsuchen
 QueryResult := FrzApiMgt.SubmitSearch(SearchQuery);

 // Ergebnisse verarbeiten
 FrzResultMgt.CreateResult(
 QueryResult,
 TempFrzResultQueryHeader,
 TempFrzResultRecordHeader,
 TempFrzResultRecordField,
 TempFrzAttachmentResult,
 SearchQuery
 );

 if TempFrzAttachmentResult.FindFirst() then begin
 // Base64-Inhalt abrufen OHNE Browser-Download
 AttachmentBase64 := FrzApiMgt.GetSpecificRecordAttachment(
 TempFrzAttachmentResult."File Link",
 TempFrzAttachmentResult.ID,
 TempFrzAttachmentResult.Filename,
 false // Kein automatischer Download
 );

 AttachmentFilename := TempFrzAttachmentResult.Filename;
 exit(AttachmentBase64 <> '');
 end;

 exit(false);
end;
 
 
 Spezialszenario: Ältesten PDF-Anhang herunterladen 
 Dieses Beispiel zeigt, wie Sie den ältesten (zuerst archivierten) PDF-Anhang eines Datensatzes finden und herunterladen. 
 Vollständiges Beispiel 
 procedure DownloadOldestPDFAttachment(RecordVariant: Variant): Boolean
var
 TempFrzResultRecordHeader: Record "DXP FRZ Record Result Header" temporary;
 TempFrzResultRecordField: Record "DXP FRZ Result Record-Field" temporary;
 TempFrzResultQueryHeader: Record "DXP FRZ Query Result Header" temporary;
 TempFrzAttachmentResult: Record "DXP FRZ Attachment Result" temporary;
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
 FrzResultMgt: Codeunit "DXP FRZ Result Mgt.";
 FrzApiMgt: Codeunit "DXP Freeze API Mgt.";
 RecordRef: RecordRef;
 SystemIdFieldRef: FieldRef;
 QueryResult: JsonObject;
 SystemId: Guid;
 SearchQuery: Text;
 OldestArchiveDate: DateTime;
 AttachmentBase64: Text;
begin
 // RecordRef aus Variant erstellen
 RecordRef.GetTable(RecordVariant);

 // SystemId extrahieren
 SystemIdFieldRef := RecordRef.Field(RecordRef.SystemIdNo());
 SystemId := SystemIdFieldRef.Value();

 // Suchanfrage für diesen Datensatz erstellen
 SearchQuery := FrzSearchMgt.GetSearchCombinationForTable(SystemId, RecordRef.Number());

 // Freeze durchsuchen
 QueryResult := FrzApiMgt.SubmitSearch(SearchQuery);

 // Ergebnisse mit Anhängen abrufen
 FrzResultMgt.CreateResult(
 QueryResult,
 TempFrzResultQueryHeader,
 TempFrzResultRecordHeader,
 TempFrzResultRecordField,
 TempFrzAttachmentResult,
 SearchQuery
 );

 // Nach PDF-Anhängen filtern
 TempFrzAttachmentResult.SetRange("File Extension", 'pdf');

 if TempFrzAttachmentResult.IsEmpty() then begin
 Message('Keine PDF-Anhänge für diesen Datensatz gefunden.');
 exit(false);
 end;

 // Nach Archivierungsdatum aufsteigend sortieren (älteste zuerst)
 TempFrzAttachmentResult.SetCurrentKey("Archived at");
 TempFrzAttachmentResult.Ascending(true);

 // Ersten (ältesten) Anhang abrufen
 if TempFrzAttachmentResult.FindFirst() then begin
 OldestArchiveDate := TempFrzAttachmentResult."Archived at";

 Message('Ältester PDF-Anhang gefunden:\Datei: %1\Größe: %2 KB\Archiviert am: %3\Autor: %4',
 TempFrzAttachmentResult.Filename,
 Round(TempFrzAttachmentResult.Filesize / 1024, 1),
 OldestArchiveDate,
 TempFrzAttachmentResult.Author);

 // Anhang herunterladen
 AttachmentBase64 := FrzApiMgt.GetSpecificRecordAttachment(
 TempFrzAttachmentResult."File Link",
 TempFrzAttachmentResult.ID,
 TempFrzAttachmentResult.Filename,
 true // Sofortiger Browser-Download
 );

 exit(AttachmentBase64 <> '');
 end;

 exit(false);
end;
 
 Verwendung des Beispiels 
 // Von einer Verkaufsrechnung aus
var
 SalesInvoiceHeader: Record "Sales Invoice Header";
begin
 SalesInvoiceHeader.Get('SI-001');
 DownloadOldestPDFAttachment(SalesInvoiceHeader);
end;

// Von einer gebuchten Einkaufsrechnung aus
var
 PurchInvHeader: Record "Purch. Inv. Header";
begin
 PurchInvHeader.Get('PI-001');
 DownloadOldestPDFAttachment(PurchInvHeader);
end;
 
 
 Zusammenfassung 
 Typischer Workflow 
 
 Datensatz identifizieren : SystemId und TableNo des BC-Datensatzes ermitteln 
 Suchanfrage erstellen :  FrzSearchMgt.GetSearchCombinationForTable() 
 Freeze durchsuchen :  FrzApiMgt.SubmitSearch() 
 Ergebnisse verarbeiten :  FrzResultMgt.CreateResult() 
 Anhänge filtern : Filter auf  TempFrzAttachmentResult  setzen 
 Anhänge herunterladen :  FrzApiMgt.GetSpecificRecordAttachment()

Archivierten Beleg per Suche finden
Die Seite  Anhang Download beschreibt, wie Anhänge eines bereits gefundenen Archiv-Datensatzes heruntergeladen werden. Diese Seite beschreibt den vorgelagerten Schritt: Wie findet man den passenden Archiv-Datensatz – auch mandantenübergreifend , z. B. um im Intercompany-Szenario aus einer EK-Rechnung den zugehörigen VK-Beleg des Partnermandanten zu ermitteln. 
 Ablauf 
 
 Suchbegriff (Lucene-Query) zusammenstellen 
 Suche an Freeze absetzen 
 Treffer + Anhänge in temporäre Tabellen übernehmen 
 Anhänge herunterladen (siehe Seite „Anhang Download") 
 
 Verwendete öffentliche Prozeduren 
 DXP Freeze Search Mgt. (Codeunit 70954893) 
 
 
 
 Prozedur 
 Zweck 
 
 
 
 
 GetSearchCombinationForTable(SystemId: Guid; TableNo: Integer): Text 
 Fertige Query für einen lokalen Beleg (SysLink + Kunde/Lieferant + aktuelle Company). 
 
 
 ToSafeSearchTerm(OldSearchTerm: Text): Text 
 Escaping (Lucene) + URL-Encoding eines Suchwertes. Für jeden dynamischen Wert verwenden. 
 
 
 SystemLinkSearchQuery(SystemId: Guid; TableNo: Integer): Text 
 Baustein SysLink:{GUID}-{TableNo} . 
 
 
 
 
 Mandantenübergreifend: GetSearchCombinationForTable ist hier nicht nutzbar – die Prozedur benötigt die SystemId des Originalbelegs und hängt automatisch die eigene CompanyName() an. Für die Suche in einem anderen Mandanten daher eine eigene Query bauen und die Partner-Company explizit als Feld Company setzen. 
 
 DXP Freeze API Mgt. (Codeunit 70954891) 
 
 
 
 Prozedur 
 Zweck 
 
 
 
 
 SubmitSearch(SearchQuery: Text): JsonObject 
 Suche absetzen (1 Treffer/Seite). 
 
 
 SubmitSearch(SearchQuery: Text; ItemsPerPage: Integer): JsonObject 
 Suche mit Seitengröße. 
 
 
 SubmitSearch(SearchQuery: Text; StoreName: Text[30]): JsonObject 
 Suche in einem bestimmten Store. 
 
 
 
 DXP FRZ Result Mgt. (Codeunit 70954894) 
 
 
 
 Prozedur 
 Zweck 
 
 
 
 
 CreateResultForAttachments(QueryResult: JsonObject; var TempFrzResultRecordHeader; var TempFrzAttachmentResult; SearchQueryTxt: Text) 
 Übernimmt Treffer + Anhang-Metadaten aus dem JSON in temporäre Tabellen. 
 
 
 HasRecord(SearchString: Text): Boolean 
 Prüft, ob es überhaupt einen Treffer gibt. 
 
 
 GetEffectiveResultsCount(SearchString: Text): Integer 
 Liefert die Trefferanzahl. 
 
 
 
 Query-Aufbau 
 Eine Query besteht aus Feldname:"Wert" -Paaren, verknüpft mit AND / OR . Feldnamen verwenden _ statt Leerzeichen/Sonderzeichen (z. B. Sell_to_Customer_No ). Werte immer über ToSafeSearchTerm escapen. 
 Beispiel – VK-Rechnung anhand Belegnummer, Belegtyp und Mandant: 
 (No:"VK-2026-001" AND Document_Type:"2" AND Company:"VERKAUF AG")
 
 Document_Type:"2" entspricht dem Belegtyp Invoice . 
 Codebeispiel 
 procedure FindSalesDocInArchive(SalesDocNo: Code[20]; PartnerCompany: Text): Boolean
var
 TempResultHeader: Record "DXP FRZ Record Result Header" temporary;
 TempAttachment: Record "DXP FRZ Attachment Result" temporary;
 FrzApiMgt: Codeunit "DXP Freeze API Mgt.";
 FrzResultMgt: Codeunit "DXP FRZ Result Mgt.";
 FrzSearchMgt: Codeunit "DXP Freeze Search Mgt.";
 QueryResult: JsonObject;
 SearchQuery: Text;
 Base64: Text;
begin
 // 1) Query bauen (mandantenübergreifend)
 SearchQuery := StrSubstNo(
 '(No:"%1" AND Document_Type:"2" AND Company:"%2")',
 FrzSearchMgt.ToSafeSearchTerm(SalesDocNo),
 FrzSearchMgt.ToSafeSearchTerm(PartnerCompany));

 // 2) Suche absetzen
 QueryResult := FrzApiMgt.SubmitSearch(SearchQuery, 50);

 // 3) Treffer + Anhänge übernehmen
 FrzResultMgt.CreateResultForAttachments(
 QueryResult, TempResultHeader, TempAttachment, SearchQuery);
 if TempAttachment.IsEmpty() then
 exit(false);

 // 4) Anhang als Base64 abrufen (siehe Seite „Anhang Download")
 TempAttachment.FindSet();
 repeat
 Base64 := FrzApiMgt.GetSpecificRecordAttachment(
 TempAttachment."File Link",
 TempAttachment.ID,
 TempAttachment.Filename,
 false); // false = kein direkter Browser-Download
 // ... Base64 weiterverarbeiten (z. B. in Beleganhang speichern)
 until TempAttachment.Next() = 0;

 exit(true);
end;
 
 
 Hinweis: Das Speichern in den Beleganhang (Tabelle „Document Attachment", 1173) ist Standard-Business-Central-Funktionalität und nicht Teil des Freeze-Moduls.