Codeunit 6753 Send Reminder Event Handler

App
Base Application
Namespace
Microsoft.Sales.Reminder
Versions
24-28

Procedures, 4Events, 1

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Sales/Reminder/Automation/Actions/SendReminders/SendReminderEventHandler.Codeunit.al289 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.Sales.Reminder;

using Microsoft.Foundation.Reporting;
using Microsoft.Sales.History;
using System.EMail;
using System.Utilities;

/// <summary>
/// Handles events during automated reminder sending to track progress and log email delivery results.
/// </summary>
codeunit 6753 "Send Reminder Event Handler"
{
    EventSubscriberInstance = Manual;

    var
        GlobalReminderAction: Record "Reminder Action";
        SendRemindersSetup: Record "Send Reminders Setup";
        ReminderAutomationLogError: Codeunit "Reminder Automation Log Errors";
        EmailsSentSuccessfully: List of [Text];
        EmailsFailed: List of [Text];
        RemindersPrintedSuccessfully: List of [Text];
        RemindersPrintedFailed: List of [Text];
        NumberOfRecordsProcessed: Integer;
        PendingOutboxMessageId: BigInteger;
        NoRemindersSentTxt: Label 'No reminders were sent.';
        RemindersEmailedTxt: Label ' %1 reminders were emailed.', Comment = '%1 number of reminders emailed';
        RemindersEmailFailedTxt: Label ' Sending email failed for %1 reminders.', Comment = '%1 number of reminders failed to email';
        RemindersPrintingFailedTxt: Label ' Printing failed for %1 reminders.', Comment = '%1 number of reminders failed to print';
        NoRemindersEmailedTxt: Label ' No reminders were emailed.';
        RemindersPritedTxt: Label ' %1 reminders were printed.', Comment = '%1 number of reminders printed';
        NoRemindersPrintedTxt: Label ' No reminders were printed.';

    internal procedure SetGlobalReminderAction(ReminderAction: Record "Reminder Action")
    var
        ReminderActionGroupLog: Record "Reminder Action Group Log";
        ReminderActionProgress: Codeunit "Reminder Action Progress";
        ReminderActionLogErrorsImplementation: Codeunit "Reminder Automation Log Errors";
    begin
        GlobalReminderAction.Copy(ReminderAction);

        ReminderActionProgress.GetLastEntryForGroup(GlobalReminderAction."Reminder Action Group Code", ReminderActionGroupLog);
        ReminderAutomationLogError := ReminderActionLogErrorsImplementation;
        ReminderAutomationLogError.Initialize(ReminderAction);
        if SendRemindersSetup.Get(ReminderAction.Code, ReminderAction."Reminder Action Group Code") then;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Send Reminder Action Job", 'OnSendReminderSafe', '', false, false)]
    local procedure HandleSendReminderSafe(var IssuedReminderHeader: Record "Issued Reminder Header"; var SendReminderSetup: Record "Send Reminders Setup"; var Success: Boolean)
    var
        SendReminder: Codeunit "Reminder-Send";
    begin
        Clear(PendingOutboxMessageId);
        SendReminder.Set(IssuedReminderHeader, SendReminderSetup);
        SendReminder.Run();
        Success := true;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::Email, 'OnAfterEmailSendFailed', '', false, false)]
    local procedure UpdateAfterEmailSendFailed(EmailOutbox: Record "Email Outbox")
    begin
        PendingOutboxMessageId := EmailOutbox.Id;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Document-Mailing", 'OnBeforeSendEmail', '', false, false)]
    local procedure DeleteFailedEmailsBeforeSendingEmail(var TempEmailItem: Record "Email Item" temporary; var IsFromPostedDoc: Boolean; var PostedDocNo: Code[20]; var HideDialog: Boolean; var ReportUsage: Integer; var EmailSentSuccesfully: Boolean; var IsHandled: Boolean; EmailDocName: Text[250]; SenderUserID: Code[50]; EmailScenario: Enum "Email Scenario")
    var
        SendReminder: Codeunit "Send Reminder";
    begin
        SendReminder.DeleteFailedOutboxMessageIfExists(PostedDocNo);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Document-Mailing", 'OnAfterEmailSent', '', false, false)]
    local procedure UpdateStatusAfterEmailSent(var TempEmailItem: Record "Email Item" temporary; PostedDocNo: Code[20]; ReportUsage: Integer; EmailSentSuccesfully: Boolean)
    var
        SendReminder: Codeunit "Send Reminder";
        ReportUsageEnum: Enum "Report Selection Usage";
    begin
        ReportUsageEnum := Enum::"Report Selection Usage"::Reminder;
        if ReportUsage <> ReportUsageEnum.AsInteger() then
            exit;

        if not EmailSentSuccesfully then begin
            ReminderAutomationLogError.LogLastError(Enum::"Reminder Automation Error Type"::"Email Reminder");
            SendReminder.SetFailedOutboxMessageID(PendingOutboxMessageId, PostedDocNo);
            EmailsFailed.Add(PostedDocNo);
            Clear(PendingOutboxMessageId);
            exit;
        end;

        if EmailSentSuccesfully then
            EmailsSentSuccessfully.Add(PostedDocNo);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Reminder-Send", 'OnAfterSendReminder', '', false, false)]
    local procedure UpdateStatusWhenReminderIsSend(var IssuedReminderHeader: Record "Issued Reminder Header")
    var
        ReminderActionProgress: Codeunit "Reminder Action Progress";
    begin
        NumberOfRecordsProcessed += 1;
        ReminderActionProgress.UpdateStatusAndTotalRecordsProcessed(GlobalReminderAction, NumberOfRecordsProcessed, GetStatusText());
    end;

    [EventSubscriber(ObjectType::Table, Database::"Report Selections", 'OnGetSendToCustomerDirectly', '', false, false)]
    local procedure HandleGetSendToCustomerDirectly(ReportUsageEnum: Enum "Report Selection Usage"; RecordVariant: Variant; CustNo: Code[20]; var ShowDialog: Boolean; var SendToCustomerDirectly: Boolean; var Handled: Boolean)
    begin
        if Handled then
            exit;

        if ReportUsageEnum <> ReportUsageEnum::Reminder then
            exit;

        SendToCustomerDirectly := true;
        Handled := true;
    end;

    /// <summary>
    /// Retrieves the list of issued reminder numbers that were successfully emailed.
    /// </summary>
    /// <returns>A list of successfully sent reminder document numbers.</returns>
    procedure GetEmailsSent(): List of [Text]
    begin
        exit(EmailsSentSuccessfully);
    end;

    /// <summary>
    /// Retrieves the list of issued reminder numbers that failed to send via email.
    /// </summary>
    /// <returns>A list of reminder document numbers that failed to email.</returns>
    procedure GetEmailsFailed(): List of [Text]
    begin
        exit(EmailsFailed);
    end;

    /// <summary>
    /// Updates the action log status and summary after the reminder sending process completes.
    /// </summary>
    procedure UpdateStatusAfterRun()
    var
        ReminderActionLog: Record "Reminder Action Log";
        ReminderActionProgress: Codeunit "Reminder Action Progress";
    begin
        if not ReminderActionProgress.GetLastActionEntry(GlobalReminderAction, ReminderActionLog) then
            ReminderActionProgress.CreateNewActionEntry(GlobalReminderAction, Enum::"Reminder Log Status"::Completed, ReminderActionLog);
        ReminderActionLog."Status summary" := CopyStr(GetStatusText(), 1, MaxStrLen(ReminderActionLog."Status summary"));
        ReminderActionLog.Modify();
    end;

    local procedure GetStatusText(): Text
    var
        StatusText: Text;
    begin
        if NumberOfRecordsProcessed = 0 then
            exit(NoRemindersSentTxt);

        if (EmailsSentSuccessfully.Count() = 0) and (EmailsFailed.Count() = 0) then
            StatusText += NoRemindersEmailedTxt
        else begin
            if EmailsSentSuccessfully.Count() > 0 then
                StatusText += StrSubstNo(RemindersEmailedTxt, EmailsSentSuccessfully.Count());

            if EmailsFailed.Count() > 0 then
                StatusText += StrSubstNo(RemindersEmailFailedTxt, EmailsFailed.Count());
        end;

        if (RemindersPrintedSuccessfully.Count() = 0) and (RemindersPrintedFailed.Count() = 0) then
            StatusText += NoRemindersPrintedTxt
        else begin
            if RemindersPrintedSuccessfully.Count() > 0 then
                StatusText += StrSubstNo(RemindersPritedTxt, RemindersPrintedSuccessfully.Count());

            if RemindersPrintedFailed.Count() > 0 then
                StatusText += StrSubstNo(RemindersPrintingFailedTxt, RemindersPrintedFailed.Count());
        end;

        exit(StatusText);
    end;

    [EventSubscriber(ObjectType::Table, Database::"Issued Reminder Header", 'OnGetReportParameters', '', false, false)]
    local procedure HandleOnGetReportParameters(var LogInteraction: Boolean; var ShowNotDueAmounts: Boolean; var ShowMIRLines: Boolean; ReportID: Integer; var Handled: Boolean)
    begin
        if Handled then
            exit;

        ShowMIRLines := SendRemindersSetup."Show Multiple Interest Rates";
        LogInteraction := SendRemindersSetup."Log Interaction";
        ShowNotDueAmounts := SendRemindersSetup."Show Amounts Not Due";
        Handled := true;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Document-Mailing", 'OnBeforeEmailItemPreparation', '', false, false)]
    local procedure AttachRelatedDocumentsBeforeEmailFileInternal(var TempEmailItem: Record "Email Item" temporary; var PostedDocNo: Code[20]; var ReportUsage: Integer)
    var
        SourceTableList: List of [Integer];
        SourceIDList: List of [Guid];
        SourceRelationTypeList: List of [Integer];
        SourceTableID: Integer;
        SourceRelationID: Integer;
        SourceID: Guid;
        AttachRelatedDocument: Boolean;
        I: Integer;
    begin
        if ReportUsage <> Enum::"Report Selection Usage"::Reminder.AsInteger() then
            exit;

        if SendRemindersSetup."Attach Invoice Documents" = SendRemindersSetup."Attach Invoice Documents"::No then
            exit;

        TempEmailItem.GetSourceDocuments(SourceTableList, SourceIDList, SourceRelationTypeList);

        for I := 1 to SourceTableList.Count() do begin
            SourceTableID := SourceTableList.Get(I);
            SourceRelationID := SourceRelationTypeList.Get(I);
            SourceID := SourceIDList.Get(I);

            if SourceTableID = Database::"Sales Invoice Header" then
                if SendRemindersSetup."Attach Invoice Documents" = SendRemindersSetup."Attach Invoice Documents"::All then
                    AttachRelatedDocument := true
                else
                    AttachRelatedDocument := IsInvoiceOverdue(PostedDocNo, SourceID);

            if AttachRelatedDocument then
                AttachDocument(TempEmailItem, SourceTableID, SourceRelationID, SourceID);
            OnAttachRelatedDocumentsBeforeEmailFileInternalOnAfterAttachRelatedDocument(TempEmailItem, PostedDocNo, SendRemindersSetup, SourceTableID, SourceRelationID, SourceID, ReportUsage);
        end;
    end;

    local procedure IsInvoiceOverdue(PostedDocNo: Code[20]; SalesInvoiceHeaderID: Guid): Boolean
    var
        SalesInvoiceHeader: Record "Sales Invoice Header";
        IssuedReminderLine: Record "Issued Reminder Line";
    begin
        SalesInvoiceHeader.SetAutoCalcFields(Cancelled, Closed);
        if not SalesInvoiceHeader.GetBySystemId(SalesInvoiceHeaderID) then
            exit(false);

        if SalesInvoiceHeader.Cancelled or SalesInvoiceHeader.Closed then
            exit;

        IssuedReminderLine.SetRange("Reminder No.", PostedDocNo);
        IssuedReminderLine.SetRange("Document Type", IssuedReminderLine."Document Type"::Invoice);
        IssuedReminderLine.SetRange("Document No.", SalesInvoiceHeader."No.");
        IssuedReminderLine.SetRange("Line Type", IssuedReminderLine."Line Type"::"Reminder Line");
        exit(not IssuedReminderLine.IsEmpty());
    end;

    local procedure AttachDocument(var TempEmailItem: Record "Email Item" temporary; SourceTableID: Integer; SourceRelationID: Integer; SourceID: Guid)
    var
        ReportSelections: Record "Report Selections";
        SalesInvoiceHeader: Record "Sales Invoice Header";
        TempAttachementReportSelections: Record "Report Selections" temporary;
        ReportDistributionManagement: Codeunit "Report Distribution Management";
        DocumentMailing: Codeunit "Document-Mailing";
        TempBlob: Codeunit "Temp Blob";
        AttachmentStream: InStream;
        AttachmentFileName: Text[250];
        DocumentName: Text[250];
    begin
        if SourceRelationID <> Enum::"Email Relation Type"::"Related Entity".AsInteger() then
            exit;

        if SourceTableID <> Database::"Sales Invoice Header" then
            exit;

        if not SalesInvoiceHeader.GetBySystemId(SourceID) then
            exit;

        if not ReportSelections.FindEmailAttachmentUsageForCust(ReportSelections.Usage::"S.Invoice", SalesInvoiceHeader."Bill-to Customer No.", TempAttachementReportSelections) then
            exit;

        SalesInvoiceHeader.SetRecFilter();
        DocumentName := ReportDistributionManagement.GetFullDocumentTypeText(SalesInvoiceHeader);
        DocumentMailing.GetAttachmentFileName(AttachmentFileName, SalesInvoiceHeader."No.", DocumentName, ReportSelections.Usage::"S.Invoice".AsInteger());
        repeat
            TempAttachementReportSelections.SaveReportAsPDFInTempBlob(TempBlob, TempAttachementReportSelections."Report ID", SalesInvoiceHeader, TempAttachementReportSelections."Custom Report Layout Code", ReportSelections.Usage::"S.Invoice");
            TempBlob.CreateInStream(AttachmentStream);

            TempEmailItem.AddAttachment(AttachmentStream, AttachmentFileName);
        until TempAttachementReportSelections.Next() = 0;
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAttachRelatedDocumentsBeforeEmailFileInternalOnAfterAttachRelatedDocument(var TempEmailItem: Record "Email Item" temporary; var PostedDocNo: Code[20]; SendRemindersSetup: Record "Send Reminders Setup"; SourceTableID: Integer; SourceRelationID: Integer; SourceID: Guid; ReportUsage: Integer)
    begin
    end;
}