top of page
Writer's pictureTabrez Ajaz

Document Attachment on Custom Table in Dynamics 365 Business Central.

Updated: Feb 21, 2022

Welcome Dynamics 365 BC Lovers,


In this article, I will explain how to attach a document on Custom Tables. To achieve this I will create a custom table called Student and different pages to display student's records and its attached document.

As attachment is a very new functionality in D365 Business Central, by using the “Document Attachment – 1173” table we can create our page from where user can attach any document to any table record, even by extending the “Document Attachment” table we can introduce new fields to store other related information for attached documents.


Demonstration Video:


My custom table schema for students:

table 80004 Students
{
    DataClassification = ToBeClassified;

    fields
    {
        field(1; "Entry No."; Integer)
        {
            DataClassification = ToBeClassified;
            AutoIncrement = true;
        }
        field(2; "ID"; Code[20])
        {
            DataClassification = ToBeClassified;
        }
        field(3; Name; Text[250])
        {
            DataClassification = ToBeClassified;
        }
    }

    keys
    {
        key(Key1; ID)
        {
            Clustered = true;
        }
    }
} 

As my student table is ready, now let’s create a list page for document attachment using Table – 1173 “Document Attachment” from this page we can attach documents for student records.

// From below page you can upload new file or download uploaded files
page 80004 "Student's Attachment Page"
{
    PageType = List;
    SourceTable = "Document Attachment";
    SourceTableView = order(descending);
    RefreshOnActivate = true;

    layout
    {
        area(Content)
        {
            repeater(Group)
            {
                field("File Name"; "File Name")
                {
                    ApplicationArea = All;
                    Editable = false;

          // Logic for import/export the file when user click on the filename 
                    trigger OnDrillDown()
                    var
                        FromRecRef: RecordRef;
                        FileName: Text;
                        cu_FileManagement: Codeunit "File Management";
                        TempBlob: Record TempBlob;
                        ImportTxt: Label 'Attach a document.';
                        FileDialogTxt: Label 'Tab Attachments (%1)|%1';
                        FilterTxt: Label '*.jpg;*.jpeg;*.bmp;*.png;*.gif;*.tiff;*.tif;*.pdf;*.docx;*.doc;*.xlsx;*.xls;*.pptx;*.ppt;*.msg;*.xml;*.*';
                    begin
                        StudentRecs.SetRange(ID, Rec."No.");
                        if StudentRecs.FindFirst() then;
                        FromRecRef.GetTable(StudentRecs);
                        ;
                        if Rec."Document Reference ID".HasValue then
                            ExportFile(true)
                        else begin
                            FileName := cu_FileManagement.BLOBImportWithFilter(TempBlob, ImportTxt, FileName, STRSUBSTNO(FileDialogTxt, FilterTxt), FilterTxt);
                            // Now Call SaveAttachment method to save the selected file
                            importFileAsAttachment(FromRecRef, FileName, TempBlob, StudentRecs.ID); // Change 3
                            CurrPage.Update(false);
                        end;
                    end;
                }
                field("File Type"; "File Type")
                {
                    ApplicationArea = All;
                    Editable = false;
                }
                field("File Extension"; "File Extension")
                {
                    ApplicationArea = All;
                    Editable = false;
                }
                field(User; User)
                {
                    ApplicationArea = All;
                    Editable = false;
                }
                field("Attached Date"; "Attached Date")
                {
                    ApplicationArea = All;
                    Editable = false;
                }
            }
        }
    }

    trigger OnOpenPage()
    begin
        //Message('Any pop-up for the user.');
    end;

    trigger OnNewRecord(BelowxRec: Boolean)
    var
    begin
        // Any default values when attachment list page shown
        Rec."File Name" := SelectFileText;
        //Rec."Document Type" := Rec."Document Type"::Order;
    end;

    // Method: Export attached documents
    procedure ExportFile(ShowFileDialog: Boolean): Text
    var
        FullFileName: Text;
        TempBlob: Record TempBlob;
        DocOutStream: OutStream;
        cu_FileManagement: Codeunit "File Management";
    begin
        if Rec.ID = 0 then
            exit;
        // Ensure document has value in DB
        if not Rec."Document Reference ID".HasValue then
            exit;

        // Get Complete File name including it's extension
        FullFileName := Rec."File Name" + '.' + Rec."File Extension";

        // Now use Tempblob to export this file
        TempBlob.Blob.CreateOutStream(DocOutStream);
        Rec."Document Reference ID".ExportStream(DocOutStream);

        // export the file
        exit(cu_FileManagement.BLOBExport(TempBlob, FullFileName, ShowFileDialog));
    end;



    // Method: Attach a document
    procedure importFileAsAttachment(RecRef: RecordRef; FileName: Text; TempBlob: Record TempBlob; StudentID: Code[20])
    var
        IncomingFileName2: Text;
        DocStream2: Instream;
        EmptyFileNameErr: Label 'No content';
        FileManagement: Codeunit "File Management";
        NoDocumentAttachedErr: Label 'No document attached';
        FieldRef: FieldRef;
        LineNo: Integer;
        Rec_Document: Record "Document Attachment";
        Rec_Attachment: Record "Document Attachment";
    begin
        IF FileName = '' THEN
            ERROR(EmptyFileNameErr);
        // Validate file/media is not empty
        IF NOT TempBlob.Blob.HasValue THEN
            ERROR(EmptyFileNameErr);
        IncomingFileName2 := FileName;
        Clear(Rec_Attachment);
        Rec_Attachment.Reset();
        Rec_Attachment.INIT;
        Rec_Attachment.VALIDATE("File Extension", FileManagement.GetExtension(IncomingFileName2));
        Rec_Attachment.VALIDATE("File Name", COPYSTR(FileManagement.GetFileNameWithoutExtension(IncomingFileName2), 1, MAXSTRLEN(Rec."File Name")));
        // My Custom Field Codes
        /*
        Rec_Attachment.Validate("You custom field name", ValueForCustomField);        
        */
        Rec_Attachment.VALIDATE("Table ID", RecRef.NUMBER);
        Rec_Attachment.Validate("No.", StudentRecs.ID); // Give your table field by which you are attaching documents [table unique field]
        TempBlob.Blob.CREATEINSTREAM(DocStream2);
        Rec_Attachment."Document Reference ID".IMPORTSTREAM(DocStream2, '', IncomingFileName2);
        IF NOT Rec_Attachment."Document Reference ID".HASVALUE THEN
            ERROR(NoDocumentAttachedErr);
        CASE RecRef.NUMBER OF
            DATABASE::Students: // Give your table name here for which you are attaching a document
                BEGIN
                    //FieldRef := RecRef.FIELD(1);                    
                    FieldRef := RecRef.FIELD(2); // Give your field No.
                    // Question: Why 2 Here? [Answer: Because I am using ID field of student table and field id for this field is 3 in my Student table]
                    Clear(Rec_Document);
                    Rec_Document.SetRange("Table ID", RecRef.Number);
                    Rec_Document.SetRange("No.", StudentRecs.ID); // YOur custom table field name
                    IF Rec_Document.FindLast() then begin
                        Rec_Attachment.Validate("Line No.", Rec_Document."Line No." + 1000);
                    end
                    else begin
                        Rec_Attachment.Validate("Line No.", 1000);
                    end;

                END;
        END;
        Rec_Attachment.INSERT(TRUE);
    end;

    var
        StudentRecs: Record Students;
        SelectFileText: Label 'Select File... Developed by Tabrez';
} 

As our document attachment page is ready from where we can attach new documents or download any attached documents, let’s create a factbox that will show the number of documents attached to any student record, or by clicking on the document count in this factbox we can attach new documents to the student record.

// Below Page will shown in the Factbox of the list page when no. of file count will show to user
page 80005 "Student's Attachment Factbox"
{
    PageType = CardPart;
    SourceTable = Students;

    layout
    {
        area(Content)
        {
            field(Attachments; NoOfAttachments)
            {
                ApplicationArea = All;
                Editable = false;
                Caption = 'No. of Attached Documents';

                trigger OnDrillDown()
                var
                    Recs_DocAtch: Record "Document Attachment";
                begin
                    Clear(Page_StudentAttachment);
                    Clear(Recs_DocAtch);
                    Recs_DocAtch.Reset();
                    Recs_DocAtch.SetRange("No.", Rec.ID);
                    if Recs_DocAtch.FindFirst() then;
                    Page_StudentAttachment.SetRecord(Recs_DocAtch);
                    Page_StudentAttachment.SetTableView(Recs_DocAtch);
                    Page_StudentAttachment.RunModal();
                    Clear(Rec_DocumentAttachment);
                    Clear(NoOfAttachments);
                    Rec_DocumentAttachment.Reset();
                    Rec_DocumentAttachment.SetRange("No.", Rec.ID);
                    if Rec_DocumentAttachment.FindSet() then
                        NoOfAttachments := Rec_DocumentAttachment.Count;
                end;
            }
        }
    }

    trigger OnAfterGetRecord()
    begin
        Clear(NoOfAttachments);
        Clear(Rec_DocumentAttachment);
        Rec_DocumentAttachment.Reset();
        Rec_DocumentAttachment.SetRange("No.", Rec.ID);
        if Rec_DocumentAttachment.FindSet() then
            NoOfAttachments := Rec_DocumentAttachment.Count;
    end;

    var
        NoOfAttachments: Integer;
        Rec_DocumentAttachment: Record "Document Attachment";
        Page_StudentAttachment: Page "Student's Attachment Page"; // Your Page Name Here
} 

As of now we are ready to create our final page where we can see the list of students record and their no. of attached documents in the factbox.

page 80006 Students
{
    Caption = 'Student Document Management - Demo';
    PageType = List;
    ApplicationArea = All;
    UsageCategory = Administration;
    SourceTable = Students;

    layout
    {
        area(Content)
        {
            repeater(GroupName)
            {
                field("Entry No."; "Entry No.")
                {
                    ApplicationArea = All;
                }
                field(ID; ID)
                {
                    ApplicationArea = All;
                }
                field(Name; Name)
                {
                    ApplicationArea = All;
                }
            }
        }
        area(FactBoxes)
        {
        part("Student's Attachment Factbox"; "Student's Attachment Factbox")
            {
                ApplicationArea = All;
                SubPageLink = ID = field(ID);
                SubPageView = order(descending);
            }
        }
    }
} 

Output:



I hope you understand how we can attach documents to any record of any custom table in Dynamics 365 Business Central.


Stay Tuned!

729 views0 comments

Comments


bottom of page