Freeze for Dynamics 365 BC - en-US

Manual for the administration and use of Freeze for Microsoft Dynamics 365 Business Central. With the Freeze Archive integration for Microsoft Dynamics 365 Business Central, you can access your audit-proof stored data and documents directly via the tried-and-tested Microsoft interface. Freeze Archive automatically links the documents to their business objects and also offers detailed search options via the index features and the full text of your documents.

System Requirements

System requirements for using FREEZE for Dynamics 365 BC

System Requirements

Supported Microsoft Dynamics 365 Business Central versions

Microsoft Dynamics 365 Business Central integration is possible from the following version due to minimum technical requirements:

Supportet Microsoft Dynamics 365 Business Central Versions

The prerequisite for operation is that the respective Microsoft Dynamics 365 Business Central version is still in regular support. The extended support is excluded.

 

System Requirements

Supported FREEZE versions

A licensed FREEZE system is required to connect FREEZE to Microsoft Dynamics 365 Business Central and for operation.

Installation

Installation

Licenses

Microsoft

Information about the Microsoft Business Central licenses.

FREEZE

The DEXPRO FREEZE system that should be connected to Business Central requires a valid customer license.

Installation

Obtaining the DEXPRO modules

Detailed Information are here.

OnPrem

For OnPrem installations, an runtime package with the required apps is provided upon request of a registered reseller / partner. These modules are added to the customer license by the partner and then imported into Microsoft Dynamics Business Central. It should be noted that the DEXPRO Core module forms the basis for all DEXPRO modules and must therefore be imported first.

Cloud

For cloud installations, you only need the Microsoft AppSource. This is where the required DEXPRO modules are downloaded.

Freeze_icon_appsource.png

 

Configuration & Administration

Configuration & Administration

Permission sets

In order to use the modules, the appropriate authorization set must be assigned to the respective users.

The following are supplied with:

Configuration & Administration

DEXPRO Core

The DEXPRO Core manages the individual DEXPRO apps and their documents per client.

All documents that have been entered and processed via the various DEXPRO modules in Microsoft Dynamics 365 Business Central are displayed. A global number series, which is used across all DEXPRO apps, is used to track individual documents. This offers the advantage that users only have to work with one number series per document.

Further information can be found here.

Configuration & Administration

Freeze Setup

In the FREEZE setup, both the connection to the Freeze Archive System and the processing within the app are set up.

Menu

Home

image-1729157119593.png

Copy Setup

This is used to copy the setup to another company.

Upload Placeholder

This function is used to upload a placeholder for file types that the PDF viewer cannot display.

Navigation

image-1729157241343.png

Document Class Setup

This menu item takes you to the setup for the document classes.

OAuth 2.0-Setup

The users and their access tokens for OAuth 2.0 authentication are managed in this menu item.

User Setup

You can access the user assignment to the OAuth users via this menu item.

Additional Search Queries

Setting up additional search queries is particularly useful if you want to display archive folders that have not been archived via Freeze in BC. However, there are also other use cases.

FastTabs

General

You can activate/deactivate the use of this app in this FastTab.

image-1729157336315.png

 

API

The URL of the FREEZE system is specified in this fast tab. The default archive storage and the default authentication are also stored. You can also specify here how many archive data records should be displayed simultaneously during searches.

image-1729157327342.png

Archiving

Settings can be made here as to what should be archived automatically.

image-1729157310405.png

Automatic archiving after posting a receipt. Printing and archiving in one step. Archiving of emails with attachments if they are sent via the BC Email module.

Configuration & Administration

Freeze Storage

The archive memories of the connected Freeze System are managed here.

 

image-1729157980175.png

Configuration & Administration

Document Class Setup

In the document class setup, the mapping between the respective document class and your export interface is done. Furthermore, the field mapping of each document class is downloaded here, creating a set of standard fields and their usage in Microsoft Dynamics 365 Business Central.

The document class setup is cross-app and is managed via the DEXPRO Core.

Process

image-1647269521455.png

Download field mapping

This downloads the field structure of the SQUEEZE document class. These are needed for the metadata mapping.

Navigation

image-1647269553966.png

Metadata mapping

Via this menu item you reach the metadata mapping. This defines which fields are to be transferred to Microsoft Dynamics 365 Business Central and how.

List

Document classes

This overview lists all the document classes that have been set up.

image-1647269475167.png

Card

Document class

Here, each document class is set up individually.

General

image-1694690581281.png

In this fastab the name of the document class, the next process step, as well as the automatic enrichment of the positions is set up.

Freeze

image-1729158122610.png

The standard search mask is defined here.

Configuration & Administration

User Setup

image-1729158280739.png

Alternative authentication: If users are to access the archive with alternative authentication, this can be entered here.

Show all results: The additional search queries (just like the full text search) only provide results for users who have been explicitly authorized to do so. This is necessary because archive folders that have not been archived via BC cannot be checked for effective authorizations due to the lack of a table number.

Configuration & Administration

OAuth 2.0 Setup

The OAuth 2.0 / Open Id users and their access tokens are managed here.

 

image-1729158448988.png

Configuration & Administration

Additional search queries

Creation of additional search queries

Below I have created a query that is appended to the system search query when you open Freeze via a record (here: vendor items - table 25). Search queries with the same table number are OR-linked.

image-1729158632771.png

 

Creation of additional search queries

You can access the query lines via Related:

image-1729158721056.png

Search by field name - Specifies the value of the field name to be used for the search query. These are the native fields of the archive software, but also data record fields saved in any form:

Search value source (field no.) - Specifies the value to be searched for in combination with the field name.

Fixed search value - The fixed search term is used instead of the search value.

The query lines are AND-linked.

Show the result

If you then open the vendor item Freeze...

image-1713950593376.png

...you will get the desired search result:

image-1713950552409.png

Do not forget: The additional search queries (just like the full text search) only provide results for users who have been explicitly authorized to do so in the setup. This is necessary because archive folders that have not been archived via BC cannot be checked for effective authorizations due to a lack of table numbers.

Application / Use

Application / Use

Archive search of documents

Freeze Searchmask

The Freeze search mask enables a full-text search as well as a search based on table fields according to the Apache Lucene syntax. It is also possible to display results for specific time periods.

image-1710160654346.png

A free search according to Apache Lucene syntax.

2. Folder type filter

Here you can filter the results by folder type (e.g. invoices). This filter is used in combination with the other search parameters.

3. Date filter

The date filter allows you to narrow down the results by archiving or reference date.

4. Table search mask

At this point, select any table whose structure you would like to use as a search mask. The table number is then part of the search.

Apache Lucene-Syntax

A query is divided into terms and operators. There are two types of terms: Single terms and phrases. A single term is a single word such as “test” or “hello”. A phrase is a group of words surrounded by double quotation marks, such as “hello dolly”.
Multiple terms can be combined with Boolean operators to form a more complex query. The following Boolean operators are supported: AND, OR and NOT. For example, the query “hello AND world” returns documents that contain both the words “hello” and “world”.
The following characters must be escaped in a query: + - && || ! ( ) { } [ ] ^ “ ~ * ? : \ To escape a character, simply place a backslash (\) in front of the character.
Wildcards can be used to search for words that contain a specific character string. The asterisk (*) stands for zero or more characters, while the question mark (?) stands for exactly one character. The query “te?t”, for example, returns documents containing words such as “test”, “text” and “tent”.

Data record-based search

The data record-based search is always executed when you open Freeze via a data record saved in BC (menu item “DEXPRO Freeze” or key combination CTRL+ALT+F). Here is an example of a vendor:

image-1710161648319.png

 

Typical jumping off points:

Application / Use

Archiving of documents

The following can be archived...

Application / Use

Freeze Queue Entries

All archiving processes are listed and processed here.

image-1729159479368.png

 

Extension Development

This chapter lists important integration events and examples to help you develop an extension for Freeze for MSDynamics 365 Business Central Important: Adaptations may only be carried out by appropriately trained consultants/developers. Furthermore, these are always outside the standard support provided by DEXPRO.

Extension Development

Attachment Download

The DXP Freeze Result Management codeunit provides two primary methods for downloading archived attachments as ZIP files:

  1. DownloadAttachmentsAsZipWithPagination - Downloads attachments from search query results with pagination support
  2. DownloadAttachmentsAsZipFromRecord - Downloads attachments from specific Business Central records

Both methods organize attachments into structured ZIP archives with comprehensive metadata for audit and tracking purposes.

Method 1: DownloadAttachmentsAsZipWithPagination

Purpose

Downloads all attachments from a search query result set, processing results page by page to handle large datasets efficiently. Each record’s attachments are organized into individual ZIP files within a main ZIP archive.

Overloads Available

1. Basic Usage

procedure DownloadAttachmentsAsZipWithPagination(SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer): Boolean

2. With Filters

procedure DownloadAttachmentsAsZipWithPagination(SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer; FilenameFilter: Text; FileExtensionFilter: Text): Boolean

3. Full Control

procedure DownloadAttachmentsAsZipWithPagination(SearchQuery: Text; var ZipArchive: Codeunit "Data Compression"; var AttachmentCount: Integer; FilenameFilter: Text; FileExtensionFilter: Text; StoreApiLink: Text; RecordsPerPage: Integer; SuppressDialog: Boolean): Boolean

4. Pre-populated Records (Advanced)

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

Parameters

Parameter Type Description
SearchQuery Text Freeze search query string. If empty in pre-populated overload, uses existing query or re-executes search
ZipArchive Codeunit “Data Compression” ZIP archive object that will contain the downloaded files
AttachmentCount Integer (var) Returns the total number of attachments downloaded
FilenameFilter Text Filter for attachment filenames (e.g., ‘.pdf’, 'invoice’)
FileExtensionFilter Text Filter for file extensions (e.g., ‘pdf’, ‘docx’)
StoreApiLink Text Optional specific store API link
RecordsPerPage Integer Number of records per page (default: 100)
SuppressDialog Boolean Whether to suppress progress dialog

Return Value

  • Booleantrue if attachments were found and downloaded; false otherwise

Example Usage

Basic 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 := 'invoice AND 2024';
    
    if ResultMgt.DownloadAttachmentsAsZipWithPagination(SearchQuery, ZipArchive, AttachmentCount) then begin
        // Save ZIP to file
        TempBlob.CreateOutStream(OutStr);
        ZipArchive.SaveZipArchive(OutStr);
        TempBlob.CreateInStream(InStr);
        
        FileMgt.DownloadFromStreamHandler(InStr, '', '', '', 'SearchResults.zip');
        Message('Downloaded %1 attachments successfully.', AttachmentCount);
    end else
        Message('No attachments found for the search query.');
end;

With Filters

procedure DownloadPDFInvoices()
var
    ResultMgt: Codeunit "DXP FRZ Result Mgt.";
    ZipArchive: Codeunit "Data Compression";
    AttachmentCount: Integer;
    SearchQuery: Text;
begin
    SearchQuery := 'type:invoice';
    
    if ResultMgt.DownloadAttachmentsAsZipWithPagination(
        SearchQuery, 
        ZipArchive, 
        AttachmentCount, 
        '*.pdf', // Only PDF files
        'pdf'    // File extension filter
    ) then begin
        // Process the ZIP archive
        ProcessDownloadedFiles(ZipArchive, AttachmentCount);
    end;
end;

Using Pre-populated Records

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
    // Assume these records are already populated from a previous search
    PopulateSearchResults(TempFrzResultQueryHeader, TempFrzResultRecordHeader, TempFrzResultRecordField, TempFrzAttachmentResult);
    
    // Download using existing results without re-executing search
    if ResultMgt.DownloadAttachmentsAsZipWithPagination(
        TempFrzResultQueryHeader,
        TempFrzResultRecordHeader,
        TempFrzResultRecordField,
        TempFrzAttachmentResult,
        'invoice search', // SearchQuery - if empty, will re-execute search
        ZipArchive,
        AttachmentCount,
        '',     // No filename filter
        '',     // No extension filter
        true    // Suppress dialog
    ) then begin
        ProcessDownloadedFiles(ZipArchive, AttachmentCount);
    end;
end;

ZIP Structure (Pagination)

SearchResults.zip
├── export-metadata.json
├── Invoice_001_V1_20241201_1430.zip
│   ├── {GUID}_invoice.pdf
│   └── {GUID}_supporting_doc.docx
├── PurchaseOrder_002_V2_20241202_0900.zip
│   └── {GUID}_po_document.pdf
└── Contract_003_V1_20241203_1200.zip
    ├── {GUID}_contract.pdf
    └── {GUID}_amendment.pdf

Method 2: DownloadAttachmentsAsZipFromRecord

Purpose

Downloads attachments from specific Business Central records. Each selected record’s attachments are organized into individual ZIP files within a main ZIP archive.

Overloads Available

1. Basic Usage

procedure DownloadAttachmentsAsZipFromRecord(var SelectedRecord: RecordRef; var ZipArchive: Codeunit "Data Compression"): Boolean

2. With Filters

procedure DownloadAttachmentsAsZipFromRecord(var SelectedRecord: RecordRef; var ZipArchive: Codeunit "Data Compression"; FilenameFilter: Text; FileExtensionFilter: Text): Boolean

Parameters

Parameter Type Description
SelectedRecord RecordRef (var) RecordRef containing the selected Business Central records
ZipArchive Codeunit “Data Compression” ZIP archive object that will contain the downloaded files
FilenameFilter Text Filter for attachment filenames
FileExtensionFilter Text Filter for file extensions

Return Value

  • Booleantrue if attachments were found and downloaded; false otherwise

Example Usage

Download from Sales Invoices

procedure DownloadInvoiceAttachments()
var
    SalesInvoiceHeader: Record "Sales Invoice Header";
    ResultMgt: Codeunit "DXP FRZ Result Mgt.";
    ZipArchive: Codeunit "Data Compression";
    RecordRef: RecordRef;
    HasAttachments: Boolean;
begin
    // Select specific invoices
    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, 'InvoiceAttachments.zip')
        else
            Message('No attachments found for the selected invoices.');
    end;
end;

Download with Filters from Page

// In a page extension
action(DownloadAttachmentsFiltered)
{
    Caption = 'Download Filtered Attachments';
    Image = ExportFile;
    
    trigger OnAction()
    var
        ResultMgt: Codeunit "DXP FRZ Result Mgt.";
        ZipArchive: Codeunit "Data Compression";
        RecordRef: RecordRef;
        FilenameFilter: Text;
        FileExtensionFilter: Text;
    begin
        // Show filter dialog
        if ShowFilterDialog(FilenameFilter, FileExtensionFilter) then begin
            CurrPage.SetSelectionFilter(Rec);
            RecordRef.GetTable(Rec);
            
            if ResultMgt.DownloadAttachmentsAsZipFromRecord(
                RecordRef, 
                ZipArchive, 
                FilenameFilter, 
                FileExtensionFilter
            ) then
                DownloadZipFile(ZipArchive, 'FilteredAttachments.zip');
        end;
    end;
}

ZIP Structure (Records)

RecordAttachments.zip
├── export-metadata.json
├── Sales_Invoice_Header_Company_SI-001.zip
│   ├── {GUID}_invoice.pdf
│   └── {GUID}_terms.pdf
├── Sales_Invoice_Header_Company_SI-002.zip
│   └── {GUID}_invoice.pdf
└── Sales_Invoice_Header_Company_SI-003.zip
    ├── {GUID}_invoice.pdf
    ├── {GUID}_delivery_note.pdf
    └── {GUID}_receipt.jpg

Metadata Structure

Both methods generate comprehensive metadata in export-metadata.json:

Pagination Export Metadata

{
  "exportInfo": {
    "exportTimestamp": "2024-12-19T10:13:52.248Z",
    "exportedBy": "USER001",
    "searchQuery": "type:invoice AND year:2024",
    "totalRecordsFound": 150,
    "totalPages": 15,
    "exportType": "paginated-search",
    "description": "Freeze Search Query 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": "Invoice INV-2024-001",
      "version": 1,
      "archivedAt": "2024-12-01T09:30:00Z",
      "archivedBy": "SYSTEM",
      "type": "Sales Invoice",
      "masterId": "{GUID}",
      "attachmentCount": 3,
      "hasAttachments": true,
      "zipFile": "Invoice_INV-2024-001_V1_20241201_0930.zip"
    }
  ]
}

Record Export Metadata

{
  "exportTimestamp": "2024-12-19T14:30:00Z",
  "exportedBy": "USER001",
  "totalRecordsProcessed": 25,
  "description": "DXP Freeze Attachments Export",
  "sourceTable": {
    "tableNumber": 112,
    "tableName": "Sales Invoice Header",
    "tableCaption": "Posted Sales Invoice"
  },
  "appliedFilters": {
    "filenameFilter": "*.pdf",
    "fileExtensionFilter": "pdf"
  },
  "statistics": {
    "totalAttachments": 45,
    "recordsWithAttachments": 20,
    "recordsWithoutAttachments": 5,
    "totalZipFiles": 20
  },
  "records": [
    {
      "recordId": "Sales Invoice Header: Company, SI-001",
      "systemId": "{GUID}",
      "primaryKey": {
        "fields": [
          {
            "fieldName": "No.",
            "fieldValue": "SI-001",
            "fieldType": "Code"
          }
        ]
      },
      "hasAttachments": true,
      "attachmentCount": 2,
      "zipFile": "Sales_Invoice_Header_Company_SI-001.zip"
    }
  ]
}

Performance Considerations

Pagination Method

  • Large Result Sets: Automatically handles pagination to process large datasets efficiently
  • Memory Management: Processes one page at a time, clearing memory between pages
  • Progress Tracking: Shows real-time progress for long-running operations
  • Recommended For: Search queries that may return hundreds or thousands of records

Record Method

  • Selected Records: Processes only the records you specifically select
  • Direct Processing: No pagination overhead for smaller datasets
  • Batch Processing: Efficient for processing specific record sets
  • Recommended For: Targeted downloads from specific Business Central records

Error Handling

Both methods include comprehensive error handling:

Common Scenarios

  • No Results Found: Returns false when no records or attachments are found
  • Permission Issues: Automatically excludes records the user cannot access
  • API Failures: Gracefully handles API communication errors
  • Empty Filters: Handles empty or invalid filter parameters

Best Practices

// Always check return value
if not ResultMgt.DownloadAttachmentsAsZipWithPagination(SearchQuery, ZipArchive, AttachmentCount) then begin
    Message('No attachments found or download failed.');
    exit;
end;

// Validate attachment count
if AttachmentCount = 0 then begin
    Message('Search completed but no attachments matched the criteria.');
    exit;
end;

// Handle large downloads
if AttachmentCount > 1000 then
    if not Confirm('This will download %1 attachments. Continue?', false, AttachmentCount) then
        exit;

Integration Events

Both methods support integration events for customization:

Available Events

  • OnBeforeDownloadAttachmentsAsZip: Modify behavior before download starts
  • OnBeforeProcessAttachmentForZip: Skip or modify individual attachments
  • OnAfterGetAttachmentBase64: Modify attachment content after retrieval
  • OnAfterAddAttachmentToZip: Perform actions after adding to ZIP
  • OnNoAttachmentsFound: Handle no attachments scenario

Example Integration

[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
    // Skip attachments larger than 10MB
    if TempFrzAttachmentResult.Filesize > 10485760 then
        IsHandled := true;
end;

File Naming Conventions

Automatic Sanitization

All filenames are automatically sanitized using the SanitizeFileName method:

  • Invalid characters (< > : " / \ | ? *) are replaced with underscores
  • Spaces are replaced with underscores
  • Maximum filename lengths are enforced

Unique Naming

  • Individual Files: Include attachment GUID prefix to ensure uniqueness
  • ZIP Files: Include record information and timestamps
  • No Conflicts: Guaranteed unique names within each ZIP archive