diff --git a/src/Layers/NL/BaseApp/Bank/DirectDebit/SEPACTPrepareSource.Codeunit.al b/src/Layers/NL/BaseApp/Bank/DirectDebit/SEPACTPrepareSource.Codeunit.al index f940fd65b42..408883b1982 100644 --- a/src/Layers/NL/BaseApp/Bank/DirectDebit/SEPACTPrepareSource.Codeunit.al +++ b/src/Layers/NL/BaseApp/Bank/DirectDebit/SEPACTPrepareSource.Codeunit.al @@ -6,6 +6,7 @@ namespace Microsoft.Bank.DirectDebit; using Microsoft.Bank.Payment; using Microsoft.Finance.GeneralLedger.Journal; +using System.Environment.Configuration; /// /// Prepares general journal line data for SEPA credit transfer XML export by copying and organizing @@ -58,6 +59,7 @@ codeunit 1222 "SEPA CT-Prepare Source" AppliedDocNoList: Text; DescriptionLen: Integer; IsHandled: Boolean; + RemittanceTruncated: Boolean; begin IsHandled := false; OnBeforeCreateTempJnlLines(FromGenJnlLine, TempGenJnlLine, IsHandled); @@ -106,12 +108,17 @@ codeunit 1222 "SEPA CT-Prepare Source" TempGenJnlLine.Description := CopyStr(AppliedDocNoList, 1, DescriptionLen); if StrLen(AppliedDocNoList) > DescriptionLen then TempGenJnlLine."Message to Recipient" := - CopyStr(AppliedDocNoList, DescriptionLen + 1, DescriptionLen + MaxStrLen(TempGenJnlLine."Message to Recipient")); + CopyStr(AppliedDocNoList, DescriptionLen + 1, MaxStrLen(TempGenJnlLine."Message to Recipient")); + if StrLen(AppliedDocNoList) > DescriptionLen + MaxStrLen(TempGenJnlLine."Message to Recipient") then + RemittanceTruncated := true; end; TempGenJnlLine.Insert(); until PaymentHistoryLine.Next() = 0; + if RemittanceTruncated then + NotifyRemittanceTruncated(); + OnAfterCreateTempJnlLines(FromGenJnlLine, TempGenJnlLine); end; @@ -149,5 +156,53 @@ codeunit 1222 "SEPA CT-Prepare Source" local procedure OnCopyJnlLinesOnBeforeTempGenJnlLineInsert(var FromGenJournalLine: Record "Gen. Journal Line"; var TempGenJournalLine: Record "Gen. Journal Line" temporary; GenJournalBatch: Record "Gen. Journal Batch") begin end; + + local procedure NotifyRemittanceTruncated() + var + MyNotifications: Record "My Notifications"; + RemittanceNotification: Notification; + begin + if not GuiAllowed() then + exit; + if not MyNotifications.IsEnabled(GetRemittanceTruncationNotificationId()) then + exit; + + RemittanceNotification.Id := GetRemittanceTruncationNotificationId(); + RemittanceNotification.Message(RemittanceTruncatedMsg); + RemittanceNotification.Scope(NotificationScope::LocalScope); + RemittanceNotification.AddAction(DontShowAgainTxt, Codeunit::"SEPA CT-Prepare Source", 'DisableRemittanceTruncationNotification'); + RemittanceNotification.Send(); + end; + + /// + /// Disables the remittance truncation notification for the current user. + /// + /// The notification whose action was invoked. + procedure DisableRemittanceTruncationNotification(RemittanceNotification: Notification) + var + MyNotifications: Record "My Notifications"; + begin + MyNotifications.Disable(GetRemittanceTruncationNotificationId()); + end; + + local procedure GetRemittanceTruncationNotificationId(): Guid + begin + exit(RemittanceTruncationNotificationIdTok); + end; + + [EventSubscriber(ObjectType::Page, Page::"My Notifications", 'OnInitializingNotificationWithDefaultState', '', false, false)] + local procedure OnInitializingNotificationWithDefaultStateRegisterNotifications() + var + MyNotifications: Record "My Notifications"; + begin + MyNotifications.InsertDefault(GetRemittanceTruncationNotificationId(), RemittanceTruncationNotificationNameTxt, RemittanceTruncationNotificationDescriptionTxt, true); + end; + + var + RemittanceTruncatedMsg: Label 'The list of applied documents will be shortened in the exported payment file. To avoid this, split the payment or turn off combining entries on the transaction mode.'; + DontShowAgainTxt: Label 'Don''t show this again'; + RemittanceTruncationNotificationNameTxt: Label 'Remittance information shortened on payment export'; + RemittanceTruncationNotificationDescriptionTxt: Label 'Notify me when the list of applied documents is too long for the remittance information and will be shortened in the exported payment file.'; + RemittanceTruncationNotificationIdTok: Label 'd9f2b3a7-6c41-4e8b-9a2d-7f0c1e5b84a3', Locked = true; } diff --git a/src/Layers/NL/Tests/Local/UTTABTelebank.Codeunit.al b/src/Layers/NL/Tests/Local/UTTABTelebank.Codeunit.al index e79503fdc37..8d2396192dc 100644 --- a/src/Layers/NL/Tests/Local/UTTABTelebank.Codeunit.al +++ b/src/Layers/NL/Tests/Local/UTTABTelebank.Codeunit.al @@ -160,6 +160,44 @@ codeunit 144055 "UT TAB Telebank" AppliedDocNoListErr); end; + [Test] + [TransactionModel(TransactionModel::AutoRollback)] + [Scope('OnPrem')] + procedure PrepareSourceTruncatesRemittanceExceedingFieldLengths() + var + PaymentHistory: Record "Payment History"; + PaymentHistoryLine: Record "Payment History Line"; + TempGenJnlLine: Record "Gen. Journal Line" temporary; + AppliedDocNoList: Text; + DescriptionLen: Integer; + begin + // [SCENARIO] Preparing SEPA CT source from a payment line whose combined applied document numbers + // exceed Description plus Message to Recipient must truncate gracefully instead of raising a length error. + + // [GIVEN] A vendor payment history line with applied documents longer than Description + Message to Recipient combined + MockVendorPaymentHistoryWithLongAppliedDocs(PaymentHistory, PaymentHistoryLine); + DescriptionLen := MaxStrLen(TempGenJnlLine.Description); + AppliedDocNoList := PaymentHistoryLine.GetAppliedDocNoList(DescriptionLen); + Assert.IsTrue( + StrLen(AppliedDocNoList) > DescriptionLen + MaxStrLen(TempGenJnlLine."Message to Recipient"), + 'Test data must exceed the combined Description and Message to Recipient length.'); + + // [WHEN] SEPA CT-Prepare Source builds the temporary journal lines + TempGenJnlLine.SetRange("Bal. Account No.", PaymentHistory."Our Bank"); + TempGenJnlLine.SetRange("Document No.", PaymentHistory."Run No."); + Codeunit.Run(Codeunit::"SEPA CT-Prepare Source", TempGenJnlLine); + + // [THEN] The list is split across Description (first part) and Message to Recipient (next part) without overflow + TempGenJnlLine.Reset(); + TempGenJnlLine.FindFirst(); + Assert.AreEqual( + CopyStr(AppliedDocNoList, 1, DescriptionLen), TempGenJnlLine.Description, + TempGenJnlLine.FieldName(Description)); + Assert.AreEqual( + CopyStr(AppliedDocNoList, DescriptionLen + 1, MaxStrLen(TempGenJnlLine."Message to Recipient")), + TempGenJnlLine."Message to Recipient", TempGenJnlLine.FieldName("Message to Recipient")); + end; + [Test] [TransactionModel(TransactionModel::AutoRollback)] [Scope('OnPrem')] @@ -814,6 +852,40 @@ codeunit 144055 "UT TAB Telebank" DetailLine.Insert(); end; + local procedure MockVendorPaymentHistoryWithLongAppliedDocs(var PaymentHistory: Record "Payment History"; var PaymentHistoryLine: Record "Payment History Line") + var + Index: Integer; + begin + PaymentHistory.Init(); + PaymentHistory."Our Bank" := LibraryERM.CreateBankAccountNo(); + PaymentHistory."Run No." := LibraryUtility.GenerateGUID(); + PaymentHistory.Insert(); + + PaymentHistoryLine.Init(); + PaymentHistoryLine."Our Bank" := PaymentHistory."Our Bank"; + PaymentHistoryLine."Run No." := PaymentHistory."Run No."; + PaymentHistoryLine."Line No." := 10000; + PaymentHistoryLine."Account Type" := PaymentHistoryLine."Account Type"::Vendor; + PaymentHistoryLine."Account No." := LibraryPurchase.CreateVendorNo(); + PaymentHistoryLine."Description 1" := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(PaymentHistoryLine."Description 1")); + PaymentHistoryLine.Insert(); + + // 12 applied documents of 30 characters each exceed Description plus Message to Recipient combined + for Index := 1 to 12 do + MockAppliedVendorDocument(PaymentHistoryLine, Index); + end; + + local procedure MockAppliedVendorDocument(PaymentHistoryLine: Record "Payment History Line"; Index: Integer) + var + VendorLedgerEntry: Record "Vendor Ledger Entry"; + begin + VendorLedgerEntry.Init(); + VendorLedgerEntry."Entry No." := LibraryUtility.GetNewRecNo(VendorLedgerEntry, VendorLedgerEntry.FieldNo("Entry No.")); + VendorLedgerEntry."External Document No." := CopyStr(PadStr('EXTDOC' + Format(Index), 30, '0'), 1, 30); + VendorLedgerEntry.Insert(); + CreateDetailLine(PaymentHistoryLine, VendorLedgerEntry."Entry No."); + end; + local procedure CreateExportProtocol(): Code[20] var ExportProtocol: Record "Export Protocol";