Table 61 Electronic Document Format, source in 29

Source29

src/Layers/W1/BaseApp/Foundation/Reporting/ElectronicDocumentFormat.Table.al506 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Foundation.Reporting;

using Microsoft.Projects.Project.Job;
using Microsoft.Sales.Document;
using Microsoft.Sales.History;
#if not CLEAN29
using Microsoft.Sales.Peppol;
#endif
using System.IO;
using System.Reflection;
#if not CLEAN29
using System.Telemetry;
#endif
using System.Utilities;

table 61 "Electronic Document Format"
{
    Caption = 'Electronic Document Format';
    LookupPageID = "Electronic Document Format";
    DataClassification = CustomerContent;

    fields
    {
        field(1; "Code"; Code[20])
        {
            Caption = 'Code';
            ToolTip = 'Specifies a code to identify the electronic document format in the system.';
            NotBlank = true;
        }
        field(2; Usage; Enum "Electronic Document Format Usage")
        {
            Caption = 'Usage';
            ToolTip = 'Specifies if the electronic document format is used for sales invoices or sales credit memos.';
        }
        field(4; Description; Text[250])
        {
            Caption = 'Description';
            ToolTip = 'Specifies the electronic document format.';
        }
        field(5; "Codeunit ID"; Integer)
        {
            BlankZero = true;
            Caption = 'Codeunit ID';
            ToolTip = 'Specifies which codeunit is used to manage electronic document sending for this document sending method.';
            NotBlank = true;
            TableRelation = AllObjWithCaption."Object ID" where("Object Type" = const(Codeunit));

#if not CLEAN29
            trigger OnValidate()
            var
                PEPPOLManagement: Codeunit "PEPPOL Management";
                FeatureTelemetry: Codeunit "Feature Telemetry";
            begin
                if ShouldLogUptake() then begin
                    FeatureTelemetry.LogUptake('0000KOQ', PEPPOLManagement.GetPeppolTelemetryTok(), Enum::"Feature Uptake Status"::Discovered);
                    FeatureTelemetry.LogUptake('0000KOR', PEPPOLManagement.GetPeppolTelemetryTok(), Enum::"Feature Uptake Status"::"Set up");
                end;
            end;
#endif
        }
        field(6; "Codeunit Caption"; Text[250])
        {
            CalcFormula = lookup(AllObjWithCaption."Object Caption" where("Object Type" = const(Codeunit),
                                                                           "Object ID" = field("Codeunit ID")));
            Caption = 'Codeunit Caption';
            ToolTip = 'Specifies the name of the codeunit.';
            Editable = false;
            FieldClass = FlowField;
        }
        field(7; "Delivery Codeunit ID"; Integer)
        {
            BlankZero = true;
            Caption = 'Delivery Codeunit ID';
            ToolTip = 'Specifies which delivery codeunit is used to manage electronic document sending for this document sending method.';
            TableRelation = AllObjWithCaption."Object ID" where("Object Type" = const(Codeunit));
        }
        field(8; "Delivery Codeunit Caption"; Text[250])
        {
            CalcFormula = lookup(AllObjWithCaption."Object Caption" where("Object Type" = const(Codeunit),
                                                                           "Object ID" = field("Delivery Codeunit ID")));
            Caption = 'Delivery Codeunit Caption';
            ToolTip = 'Specifies the name of the delivery codeunit.';
            Editable = false;
            FieldClass = FlowField;
        }
    }

    keys
    {
        key(Key1; "Code", Usage)
        {
            Clustered = true;
        }
    }

    fieldgroups
    {
    }

    trigger OnInsert()
    begin
        CheckCodeunitExist();
    end;

    trigger OnModify()
    begin
        CheckCodeunitExist();
    end;

    var
        DataCompression: Codeunit "Data Compression";

        UnSupportedTableTypeErr: Label 'The %1 table is not supported.', Comment = '%1 = Sales Document Type';
        NonExistingDocumentFormatErr: Label 'The electronic document format %1 does not exist for the document type %2.', Comment = '%1 : document format, %2 document use eq Invoice';
        UnSupportedDocumentTypeErr: Label 'The document type %1 is not supported.', Comment = '%1 : document ytp eq Invocie ';
        ElectronicDocumentNotCreatedErr: Label 'The electronic document has not been created.';
        ElectronicFormatErr: Label 'The electronic format %1 does not exist.', Comment = '%1=Specified Electronic Format';

    procedure SendElectronically(var TempBlob: Codeunit "Temp Blob"; var ClientFileName: Text[250]; DocumentVariant: Variant; ElectronicFormat: Code[20])
    var
        RecordExportBuffer: Record "Record Export Buffer";
        TempErrorMessage: Record "Error Message" temporary;
        ErrorMessage: Record "Error Message";
        EntryTempBlob: Codeunit "Temp Blob";
        RecRef: RecordRef;
        EntryFileInStream: InStream;
        ZipFileOutStream: OutStream;
        DocumentUsage: Enum "Electronic Document Format Usage";
        StartID: Integer;
        EndID: Integer;
        IsMissingFileContent: Boolean;
    begin
        GetDocumentFormatUsage(DocumentUsage, DocumentVariant);

        if not Get(ElectronicFormat, DocumentUsage) then begin
            Usage := DocumentUsage;
            Error(NonExistingDocumentFormatErr, ElectronicFormat, Format(Usage));
        end;

        RecRef.GetTable(DocumentVariant);
        OnSendElectronicallyOnAfterRecRefGetTable(Rec, RecRef);

        StartID := 0;
        RecordExportBuffer.LockTable();
        if RecRef.FindSet() then
            repeat
                Clear(RecordExportBuffer);
                RecordExportBuffer.RecordID := RecRef.RecordId;
                RecordExportBuffer.ClientFileName :=
                  GetAttachmentFileName(RecRef, GetDocumentNo(RecRef), GetDocumentType(RecRef), 'xml');
                RecordExportBuffer.ZipFileName :=
                  GetAttachmentFileName(RecRef, GetDocumentNo(RecRef), GetDocumentType(RecRef), 'zip');
                OnSendElectronicallyOnBeforeRecordExportBufferInsert(RecordExportBuffer, RecRef);
                RecordExportBuffer.Insert(true);
                if StartID = 0 then
                    StartID := RecordExportBuffer.ID;
                EndID := RecordExportBuffer.ID;
            until RecRef.Next() = 0;

        RecordExportBuffer.SetRange(ID, StartID, EndID);
        if RecordExportBuffer.FindSet() then
            repeat
                ErrorMessage.SetContext(RecordExportBuffer);
                ErrorMessage.ClearLog();

                CODEUNIT.Run("Codeunit ID", RecordExportBuffer);

                TempErrorMessage.CopyFromContext(RecordExportBuffer);
                ErrorMessage.ClearLog(); // Clean up

                OnSendElectronicallyOnAfterRecordExportBufferFileGenerated(RecordExportBuffer, RecRef);

                if not RecordExportBuffer."File Content".HasValue() then
                    IsMissingFileContent := true;
            until RecordExportBuffer.Next() = 0;

        // Display errors in case anything went wrong.
        TempErrorMessage.ShowErrorMessages(true);
        if IsMissingFileContent then
            Error(ElectronicDocumentNotCreatedErr);

        if RecordExportBuffer.Count > 1 then begin
            TempBlob.CreateOutStream(ZipFileOutStream);
            DataCompression.CreateZipArchive();
            ClientFileName := CopyStr(RecordExportBuffer.ZipFileName, 1, 250);
            RecordExportBuffer.FindSet();
            repeat
                RecordExportBuffer.GetFileContent(EntryTempBlob);
                EntryTempBlob.CreateInStream(EntryFileInStream);
                DataCompression.AddEntry(EntryFileInStream, RecordExportBuffer.ClientFileName);
            until RecordExportBuffer.Next() = 0;
            DataCompression.SaveZipArchive(ZipFileOutStream);
            DataCompression.CloseZipArchive();
        end else
            if RecordExportBuffer.FindFirst() then begin
                RecordExportBuffer.GetFileContent(TempBlob);
                ClientFileName := RecordExportBuffer.ClientFileName;
            end;

        OnSendElectronicallyOnBeforeDeleteAll(RecordExportBuffer, ClientFileName, DocumentVariant);

        RecordExportBuffer.DeleteAll();

        OnAfterSendElectronically(Rec, ClientFileName, DocumentVariant, ElectronicFormat);
    end;


    procedure ValidateElectronicSalesDocument(SalesHeader: Record "Sales Header"; ElectronicFormat: Code[20])
    var
        ElectronicDocumentFormat: Record "Electronic Document Format";
    begin
        if not ElectronicDocumentFormat.Get(ElectronicFormat, Usage::"Sales Validation") then
            exit; // no validation required

        CODEUNIT.Run(ElectronicDocumentFormat."Codeunit ID", SalesHeader);
    end;

    procedure ValidateElectronicJobsDocument(Job: Record Job; ElectronicFormat: Code[20])
    var
        ElectronicDocumentFormat: Record "Electronic Document Format";
    begin
        if not ElectronicDocumentFormat.Get(ElectronicFormat, Usage::"Job Quote") then
            exit; // no validation required

        CODEUNIT.Run(ElectronicDocumentFormat."Codeunit ID", Job);
    end;

    procedure ValidateElectronicJobTasksDocument(JobTask: Record "Job Task"; ElectronicFormat: Code[20])
    var
        ElectronicDocumentFormat: Record "Electronic Document Format";
    begin
        if not ElectronicDocumentFormat.Get(ElectronicFormat, Usage::"Job Task Quote") then
            exit; // no validation required

        CODEUNIT.Run(ElectronicDocumentFormat."Codeunit ID", JobTask);
    end;

    procedure GetAttachmentFileName(RecordVariant: Variant; DocumentNo: Code[20]; DocumentType: Text; Extension: Code[3]) FileName: Text[250]
    var
        FileMgt: Codeunit "File Management";
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetAttachmentFileName(RecordVariant, DocumentNo, DocumentType, Extension, IsHandled, FileName);
        if not IsHandled then
            FileName :=
                CopyStr(
                    StrSubstNo('%1 - %2 %3.%4', FileMgt.StripNotsupportChrInFileName(CompanyName), DocumentType, DocumentNo, Extension), 1, 250);
    end;


    procedure GetDocumentFormatUsage(var DocumentFormatUsage: Enum "Electronic Document Format Usage"; DocumentVariant: Variant)
    var
        DocumentRecordRef: RecordRef;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetDocumentFormatUsage(Rec, DocumentVariant, DocumentFormatUsage, IsHandled);
        if IsHandled then
            exit;

        DocumentRecordRef.GetTable(DocumentVariant);
        case DocumentRecordRef.Number of
            Database::"Sales Invoice Header":
                DocumentFormatUsage := DocumentFormatUsage::"Sales Invoice";
            Database::"Sales Cr.Memo Header":
                DocumentFormatUsage := DocumentFormatUsage::"Sales Credit Memo";
            Database::"Sales Header":
                GetDocumentUsageForSalesHeader(DocumentFormatUsage, DocumentVariant);
            Database::Job:
                DocumentFormatUsage := DocumentFormatUsage::"Job Quote";
            Database::"Job Task":
                DocumentFormatUsage := DocumentFormatUsage::"Job Task Quote";
            else begin
                IsHandled := false;
                OnGetDocumentFormatUsageCaseElse(DocumentRecordRef, DocumentFormatUsage, IsHandled);
                if not IsHandled then
                    Error(UnSupportedTableTypeErr, DocumentRecordRef.Caption);
            end;
        end;
    end;

    procedure GetDocumentNo(DocumentVariant: Variant): Code[20]
    var
        SalesInvoiceHeader: Record "Sales Invoice Header";
        SalesCrMemoHeader: Record "Sales Cr.Memo Header";
        SalesHeader: Record "Sales Header";
        Job: Record Job;
        DocumentRecordRef: RecordRef;
        DocumentNo: Code[20];
        IsHandled: Boolean;
    begin
        if DocumentVariant.IsRecord then
            DocumentRecordRef.GetTable(DocumentVariant)
        else
            if DocumentVariant.IsRecordRef then
                DocumentRecordRef := DocumentVariant;

        case DocumentRecordRef.Number of
            DATABASE::"Sales Invoice Header":
                begin
                    SalesInvoiceHeader := DocumentVariant;
                    exit(SalesInvoiceHeader."No.");
                end;
            DATABASE::"Sales Cr.Memo Header":
                begin
                    SalesCrMemoHeader := DocumentVariant;
                    exit(SalesCrMemoHeader."No.");
                end;
            DATABASE::"Sales Header":
                begin
                    SalesHeader := DocumentVariant;
                    exit(SalesHeader."No.");
                end;
            DATABASE::Job:
                begin
                    Job := DocumentVariant;
                    exit(Job."No.");
                end;
            else begin
                IsHandled := false;
                OnGetDocumentNoCaseElse(DocumentVariant, DocumentNo, IsHandled, DocumentRecordRef);
                if IsHandled then
                    exit(DocumentNo);

                Error(UnSupportedTableTypeErr, DocumentRecordRef.Caption);
            end;
        end;
    end;

    local procedure GetDocumentUsageForSalesHeader(var DocumentFormatUsage: Enum "Electronic Document Format Usage"; SalesHeader: Record "Sales Header")
    var
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeGetDocumentFormatUsageForSalesHeader(Rec, SalesHeader, DocumentFormatUsage, IsHandled);
        if IsHandled then
            exit;

        case SalesHeader."Document Type" of
            SalesHeader."Document Type"::Order:
                exit;
            SalesHeader."Document Type"::Invoice:
                DocumentFormatUsage := Usage::"Sales Invoice";
            SalesHeader."Document Type"::"Credit Memo":
                DocumentFormatUsage := Usage::"Sales Credit Memo";
            else
                Error(UnSupportedDocumentTypeErr, Format(SalesHeader."Document Type"));
        end;
    end;

    local procedure CheckCodeunitExist()
    var
        AllObj: Record AllObj;
    begin
        AllObj.Get(AllObj."Object Type"::Codeunit, "Codeunit ID");
    end;

    procedure ValidateElectronicFormat(ElectronicFormat: Code[20])
    var
        ElectronicDocumentFormat: Record "Electronic Document Format";
    begin
        ElectronicDocumentFormat.SetRange(Code, ElectronicFormat);
        if ElectronicDocumentFormat.IsEmpty() then
            Error(ElectronicFormatErr, ElectronicFormat);
    end;

    procedure GetDocumentType(DocumentVariant: Variant) DocumentTypeText: Text[50]
    var
        DummySalesHeader: Record "Sales Header";
        TranslationHelper: Codeunit "Translation Helper";
        ReportDistributionManagement: Codeunit "Report Distribution Management";
        DocumentRecordRef: RecordRef;
    begin
        TranslationHelper.SetGlobalLanguageByCode(ReportDistributionManagement.GetDocumentLanguageCode(DocumentVariant));

        if DocumentVariant.IsRecord then
            DocumentRecordRef.GetTable(DocumentVariant)
        else
            if DocumentVariant.IsRecordRef then
                DocumentRecordRef := DocumentVariant;
        case DocumentRecordRef.Number of
            DATABASE::"Sales Invoice Header":
                DocumentTypeText := Format("Sales Document Type"::Invoice);
            DATABASE::"Sales Cr.Memo Header":
                DocumentTypeText := Format("Sales Document Type"::"Credit Memo");
            DATABASE::Job:
                DocumentTypeText := Format("Sales Document Type"::Quote);
            DATABASE::"Sales Header":
                begin
                    DummySalesHeader := DocumentVariant;
                    if DummySalesHeader."Document Type" = DummySalesHeader."Document Type"::Quote then
                        DocumentTypeText := Format(DummySalesHeader."Document Type"::Quote);
                end;
            else
                OnGetDocumentTypeCaseElse(DocumentVariant, DocumentTypeText, DocumentRecordRef);
        end;

        TranslationHelper.RestoreGlobalLanguage();
    end;

    procedure InsertElectronicFormat(InsertElectronicFormatCode: Code[20]; InsertElectronicFormatDescription: Text[250]; CodeunitID: Integer; DeliveryCodeunitID: Integer; InsertElectronicFormatUsage: Option)
    var
        ElectronicDocumentFormat: Record "Electronic Document Format";
    begin
        if ElectronicDocumentFormat.Get(InsertElectronicFormatCode, InsertElectronicFormatUsage) then
            exit;

        ElectronicDocumentFormat.Init();
        ElectronicDocumentFormat.Code := InsertElectronicFormatCode;
        ElectronicDocumentFormat.Description := InsertElectronicFormatDescription;
        ElectronicDocumentFormat."Codeunit ID" := CodeunitID;
        ElectronicDocumentFormat."Delivery Codeunit ID" := DeliveryCodeunitID;
        ElectronicDocumentFormat.Usage := "Electronic Document Format Usage".FromInteger(InsertElectronicFormatUsage);
        ElectronicDocumentFormat.Insert();
    end;

#if not CLEAN29
    local procedure ShouldLogUptake() Result: Boolean
    begin
        if "Codeunit ID" in [
            Codeunit::"PEPPOL Validation", Codeunit::"Exp. Sales Inv. PEPPOL BIS3.0", Codeunit::"Exp. Sales CrM. PEPPOL BIS3.0"]
        then
            exit(true);

        OnAfterShouldLogUptake(Rec, Result);
    end;
#endif

    [IntegrationEvent(false, false)]
    [Scope('OnPrem')]
    procedure OnDiscoverElectronicFormat()
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetDocumentFormatUsage(ElectronicDocumentFormat: Record "Electronic Document Format"; DocumentVariant: Variant; var DocumentFormatUsage: Enum "Electronic Document Format Usage"; var IsHandled: Boolean)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetDocumentFormatUsageForSalesHeader(ElectronicDocumentFormat: Record "Electronic Document Format"; SalesHeader: Record "Sales Header"; var DocumentUsage: Enum "Electronic Document Format Usage"; var IsHandled: Boolean)
    begin
    end;


    [IntegrationEvent(false, false)]
    local procedure OnGetDocumentNoCaseElse(DocumentVariant: Variant; var DocumentNo: Code[20]; var IsHandled: Boolean; DocumentRecordRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetDocumentTypeCaseElse(DocumentVariant: Variant; var DocumentTypeText: Text[50]; DocumentRecordRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSendElectronicallyOnBeforeDeleteAll(var RecordExportBuffer: Record "Record Export Buffer"; var ClientFileName: Text[250]; DocumentVariant: Variant)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSendElectronicallyOnBeforeRecordExportBufferInsert(var RecordExportBuffer: Record "Record Export Buffer"; RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnSendElectronicallyOnAfterRecRefGetTable(ElectronicDocumentFormat: Record "Electronic Document Format"; var RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeGetAttachmentFileName(RecordVariant: Variant; DocumentNo: Code[20]; DocumentType: Text; Extension: Code[3]; var IsHandled: Boolean; var FileName: Text[250])
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnGetDocumentFormatUsageCaseElse(DocumentRecordRef: RecordRef; var DocumentFormatUsage: Enum "Electronic Document Format Usage"; var IsHandled: Boolean)
    begin
    end;

#if not CLEAN29
    [Obsolete('Peppol functionality is replaced by PEPPOL App. This event will be removed in future versions.', '29.0')]
    [IntegrationEvent(false, false)]
    local procedure OnAfterShouldLogUptake(var ElectronicDocumentFormat: Record "Electronic Document Format"; var Result: Boolean)
    begin
    end;
#endif

    [IntegrationEvent(false, false)]
    local procedure OnSendElectronicallyOnAfterRecordExportBufferFileGenerated(var RecordExportBuffer: Record "Record Export Buffer"; RecRef: RecordRef)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterSendElectronically(var ElectronicDocumentFormat: Record "Electronic Document Format"; var ClientFileName: Text[250]; DocumentVariant: Variant; ElectronicFormat: Code[20])
    begin
    end;
}