Anhang Download
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 herunterDownloadAttachmentsAsZipFromRecord
- 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 modifizierenOnBeforeProcessAttachmentForZip
: Einzelne Anhänge überspringen oder modifizierenOnAfterGetAttachmentBase64
: Anhanginhalt nach Abruf modifizierenOnAfterAddAttachmentToZip
: Aktionen nach Hinzufügung zum ZIP durchführenOnNoAttachmentsFound
: 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
No Comments