Codeunit 1700 Exp. Launcher Pos. Pay, source in 29
Source29
src/Layers/W1/BaseApp/Bank/PositivePay/ExpLauncherPosPay.Codeunit.al304 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.Bank.PositivePay;
using Microsoft.Bank.BankAccount;
using Microsoft.Bank.Check;
using Microsoft.Bank.Setup;
using System.IO;
/// <summary>
/// Launches and orchestrates the positive pay export process for check ledger entries.
/// This codeunit serves as the main entry point for positive pay file generation and export operations.
/// </summary>
/// <remarks>
/// The Export Launcher Positive Pay codeunit coordinates the entire positive pay export workflow from start to finish.
/// It validates bank account setup, creates data exchange entries, processes check ledger entries, and generates
/// output files in the required format. The codeunit handles both header, detail, and footer record generation
/// through the data exchange framework. It also manages the integration with bank export/import setup configurations
/// and provides progress feedback during large data exports. The export process creates audit trail records
/// and updates check ledger entries with export tracking information.
/// </remarks>
codeunit 1700 "Exp. Launcher Pos. Pay"
{
Permissions = TableData "Check Ledger Entry" = rimd,
TableData "Data Exch." = rimd;
TableNo = "Check Ledger Entry";
trigger OnRun()
begin
PositivePayProcess(Rec, true);
end;
/// <summary>
/// Executes the complete positive pay export process for the specified check ledger entries.
/// </summary>
/// <param name="CheckLedgerEntry">The check ledger entries to include in the positive pay export.</param>
/// <param name="ShowDialog">Indicates whether to display progress dialogs to the user during processing.</param>
/// <remarks>
/// This procedure orchestrates the entire positive pay export workflow including validation, data preparation,
/// file generation, and user feedback. It processes header, detail, and footer records through the data exchange
/// framework and creates the final export file. The procedure also updates check ledger entries with export
/// tracking information and creates audit trail records for compliance purposes.
/// </remarks>
[Scope('OnPrem')]
procedure PositivePayProcess(var CheckLedgerEntry: Record "Check Ledger Entry"; ShowDialog: Boolean)
var
DataExch: Record "Data Exch.";
DataExchDef: Record "Data Exch. Def";
CheckLedgerEntry2: Record "Check Ledger Entry";
BankAccount: Record "Bank Account";
BankExportImportSetup: Record "Bank Export/Import Setup";
FileManagement: Codeunit "File Management";
ExpWritingPosPay: Codeunit "Exp. Writing Pos. Pay";
ExpExternalDataPosPay: Codeunit "Exp. External Data Pos. Pay";
DataExchEntryCodeDetail: Integer;
DataExchEntryCodeFooter: Integer;
DataExchDefCode: Code[20];
Filename: Text;
HeaderArray: array[100] of Integer;
DetailArray: array[100] of Integer;
FooterArray: array[100] of Integer;
begin
CheckLedgerEntry2.CopyFilters(CheckLedgerEntry);
CheckLedgerEntry2.FindFirst();
BankAccount.Get(CheckLedgerEntry2."Bank Account No.");
BankExportImportSetup.SetRange(Code, BankAccount."Positive Pay Export Code");
if BankExportImportSetup.FindFirst() then begin
DataExchDefCode := BankExportImportSetup."Data Exch. Def. Code";
Filename := FileManagement.ServerTempFileName('txt');
ProcessHeaders(BankAccount, DataExchDefCode, HeaderArray, Filename);
ProcessDetails(CheckLedgerEntry2, DataExchDefCode, DataExchEntryCodeDetail, DetailArray, Filename);
ProcessFooters(BankAccount, DataExchDefCode, FooterArray, Filename, DataExchEntryCodeDetail, DataExchEntryCodeFooter);
ExpWritingPosPay.ExportPositivePay(DataExchEntryCodeDetail, DataExchEntryCodeFooter, Filename, FooterArray);
// This should only be called from a test codeunit, calling CreateExportFile MUST pass in a FALSE parameter
DataExchDef.Get(DataExchDefCode);
if DataExchDef."Ext. Data Handling Codeunit" > 0 then begin
DataExch.Get(DataExchEntryCodeDetail);
if DataExchDef."Ext. Data Handling Codeunit" = CODEUNIT::"Exp. External Data Pos. Pay" then
ExpExternalDataPosPay.CreateExportFile(DataExch, ShowDialog)
else
CODEUNIT.Run(DataExchDef."Ext. Data Handling Codeunit", DataExch);
end;
if DataExchDef."User Feedback Codeunit" > 0 then begin
DataExch.Get(DataExchEntryCodeDetail);
CODEUNIT.Run(DataExchDef."User Feedback Codeunit", DataExch);
end;
// Clean up the work tables.
ExpWritingPosPay.CleanUpPositivePayWorkTables(HeaderArray, DetailArray, FooterArray);
end;
end;
/// <summary>
/// Updates check ledger entries with positive pay export tracking information.
/// </summary>
/// <param name="CheckLedgerEntry">The check ledger entries to update with export information.</param>
/// <param name="DataExchEntryCodeDetail">The data exchange entry code for audit trail linking.</param>
local procedure UpdateCheckLedger(var CheckLedgerEntry: Record "Check Ledger Entry"; DataExchEntryCodeDetail: Integer)
var
CheckLedgerEntry2: Record "Check Ledger Entry";
begin
CheckLedgerEntry2.CopyFilters(CheckLedgerEntry);
CheckLedgerEntry2.SetFilter(
"Entry Status",
'%1|%2|>%3',
CheckLedgerEntry2."Entry Status"::Printed,
CheckLedgerEntry2."Entry Status"::Posted,
CheckLedgerEntry2."Entry Status"::"Test Print");
CheckLedgerEntry2.SetRange("Positive Pay Exported", false);
CheckLedgerEntry2.ModifyAll("Data Exch. Entry No.", DataExchEntryCodeDetail, true);
CheckLedgerEntry2.SetFilter(
"Entry Status",
'%1|%2|%3',
CheckLedgerEntry2."Entry Status"::Voided,
CheckLedgerEntry2."Entry Status"::"Financially Voided",
CheckLedgerEntry2."Entry Status"::"Test Print");
CheckLedgerEntry2.ModifyAll("Data Exch. Voided Entry No.", DataExchEntryCodeDetail, true);
end;
/// <summary>
/// Processes header records for the positive pay export by creating data exchange entries and generating header files.
/// </summary>
/// <param name="BankAccount">The bank account for which headers are being processed.</param>
/// <param name="DataExchDefCode">The data exchange definition code defining the export format.</param>
/// <param name="HeaderArray">Array to store the data exchange entry numbers for generated headers.</param>
/// <param name="Filename">The target filename for the export file.</param>
local procedure ProcessHeaders(var BankAccount: Record "Bank Account"; DataExchDefCode: Code[20]; var HeaderArray: array[100] of Integer; Filename: Text)
var
DataExch: Record "Data Exch.";
DataExchDef: Record "Data Exch. Def";
DataExchLineDef: Record "Data Exch. Line Def";
DataExchMapping: Record "Data Exch. Mapping";
PositivePayExportMgt: Codeunit "Positive Pay Export Mgt";
HdrCount: Integer;
begin
HdrCount := 0;
DataExchLineDef.Init();
DataExchLineDef.SetRange("Data Exch. Def Code", DataExchDefCode);
DataExchLineDef.SetRange("Line Type", DataExchLineDef."Line Type"::Header);
if DataExchLineDef.FindSet() then
repeat
// Insert the Data Exchange Header records
DataExch."Entry No." := 0;
DataExch."Data Exch. Def Code" := DataExchDefCode;
DataExch."Data Exch. Line Def Code" := DataExchLineDef.Code;
DataExch.Insert();
Commit();
HdrCount := HdrCount + 1;
HeaderArray[HdrCount] := DataExch."Entry No.";
// It is only here where we know the True DataExch."Entry No"..
DataExchMapping.SetRange("Data Exch. Def Code", DataExchDefCode);
DataExchMapping.SetRange("Data Exch. Line Def Code", DataExchLineDef.Code);
DataExchMapping.FindFirst();
// Populate the Header/Detail/Footer work tables
PositivePayExportMgt.PreparePosPayHeader(DataExch, BankAccount."Bank Account No.");
if DataExchMapping."Pre-Mapping Codeunit" > 0 then
CODEUNIT.Run(DataExchMapping."Pre-Mapping Codeunit", DataExch);
// Create the Entries and values in the Data Exch. Field table
if DataExchMapping."Mapping Codeunit" > 0 then
CODEUNIT.Run(DataExchMapping."Mapping Codeunit", DataExch);
DataExchDef.Get(DataExchDefCode);
if DataExchDef."Reading/Writing Codeunit" = CODEUNIT::"Exp. Writing Pos. Pay" then
PositivePayExportMgt.ExportDataExchToFlatFile(DataExch."Entry No.", Filename, DataExchLineDef."Line Type", HdrCount);
until DataExchLineDef.Next() = 0;
end;
/// <summary>
/// Processes detail records for the positive pay export by converting check ledger entries into data exchange format.
/// </summary>
/// <param name="CheckLedgerEntry">The check ledger entries to process for the export.</param>
/// <param name="DataExchDefCode">The data exchange definition code defining the export format.</param>
/// <param name="DataExchEntryCodeDetail">Returns the data exchange entry code for the detail records.</param>
/// <param name="DetailArray">Array to store the data exchange entry numbers for generated details.</param>
/// <param name="Filename">The target filename for the export file.</param>
local procedure ProcessDetails(var CheckLedgerEntry: Record "Check Ledger Entry"; DataExchDefCode: Code[20]; var DataExchEntryCodeDetail: Integer; var DetailArray: array[100] of Integer; Filename: Text)
var
DataExch: Record "Data Exch.";
DataExchDef: Record "Data Exch. Def";
DataExchLineDef: Record "Data Exch. Line Def";
DataExchMapping: Record "Data Exch. Mapping";
PositivePayExportMgt: Codeunit "Positive Pay Export Mgt";
CurrentDataExchEntryCodeDetail: Integer;
DetailCount: Integer;
begin
DetailCount := 0;
DataExchLineDef.Init();
DataExchLineDef.SetRange("Data Exch. Def Code", DataExchDefCode);
DataExchLineDef.SetRange("Line Type", DataExchLineDef."Line Type"::Detail);
if DataExchLineDef.FindSet() then begin
repeat
// Insert the Data Exchange Detail records
DataExch."Entry No." := 0;
DataExch."Data Exch. Def Code" := DataExchDefCode;
DataExch."Data Exch. Line Def Code" := DataExchLineDef.Code;
DataExch.Insert();
Commit();
DetailCount := DetailCount + 1;
DetailArray[DetailCount] := DataExch."Entry No.";
// It is only here where we know the True DataExch."Entry No"..
DataExchMapping.SetRange("Data Exch. Def Code", DataExchDefCode);
DataExchMapping.SetRange("Data Exch. Line Def Code", DataExchLineDef.Code);
DataExchMapping.FindFirst();
if DataExchEntryCodeDetail = 0 then
DataExchEntryCodeDetail := DataExch."Entry No.";
CurrentDataExchEntryCodeDetail := DataExch."Entry No.";
UpdateCheckLedger(CheckLedgerEntry, CurrentDataExchEntryCodeDetail);
// Populate the Header/Detail/Footer work tables
if DataExchMapping."Pre-Mapping Codeunit" > 0 then
CODEUNIT.Run(DataExchMapping."Pre-Mapping Codeunit", DataExch);
// Create the Entries and values in the Data Exch. Field table
if DataExchMapping."Mapping Codeunit" > 0 then
CODEUNIT.Run(DataExchMapping."Mapping Codeunit", DataExch);
DataExchDef.Get(DataExchDefCode);
if DataExchDef."Reading/Writing Codeunit" > 0 then
if DataExchDef."Reading/Writing Codeunit" = CODEUNIT::"Exp. Writing Pos. Pay" then
PositivePayExportMgt.ExportDataExchToFlatFile(DataExch."Entry No.", Filename, DataExchLineDef."Line Type", 0)
else
CODEUNIT.Run(DataExchDef."Reading/Writing Codeunit", DataExch);
until DataExchLineDef.Next() = 0;
// When we are done, we need to set the Check Ledger record(s) Entry No back to the original.
if DataExchEntryCodeDetail > 0 then
UpdateCheckLedger(CheckLedgerEntry, DataExchEntryCodeDetail);
end;
end;
/// <summary>
/// Processes footer records for the positive pay export by creating summary information and generating footer files.
/// </summary>
/// <param name="BankAccount">The bank account for which footers are being processed.</param>
/// <param name="DataExchDefCode">The data exchange definition code defining the export format.</param>
/// <param name="FooterArray">Array to store the data exchange entry numbers for generated footers.</param>
/// <param name="Filename">The target filename for the export file.</param>
/// <param name="DataExchEntryCodeDetail">The data exchange entry code of the associated detail records.</param>
/// <param name="DataExchEntryCodeFooter">Returns the data exchange entry code for the footer record.</param>
local procedure ProcessFooters(var BankAccount: Record "Bank Account"; DataExchDefCode: Code[20]; var FooterArray: array[100] of Integer; Filename: Text; DataExchEntryCodeDetail: Integer; var DataExchEntryCodeFooter: Integer)
var
DataExch: Record "Data Exch.";
DataExchDef: Record "Data Exch. Def";
DataExchLineDef: Record "Data Exch. Line Def";
DataExchMapping: Record "Data Exch. Mapping";
PositivePayExportMgt: Codeunit "Positive Pay Export Mgt";
FooterCount: Integer;
begin
FooterCount := 0;
DataExchLineDef.Init();
DataExchLineDef.SetRange("Data Exch. Def Code", DataExchDefCode);
DataExchLineDef.SetRange("Line Type", DataExchLineDef."Line Type"::Footer);
if DataExchLineDef.FindSet() then
repeat
// Insert the Data Exchange Footer records
DataExch."Entry No." := 0;
DataExch."Data Exch. Def Code" := DataExchDefCode;
DataExch."Data Exch. Line Def Code" := DataExchLineDef.Code;
DataExch.Insert();
Commit();
FooterCount := FooterCount + 1;
FooterArray[FooterCount] := DataExch."Entry No.";
// It is only here where we know the True DataExch."Entry No"..
DataExchMapping.SetRange("Data Exch. Def Code", DataExchDefCode);
DataExchMapping.SetRange("Data Exch. Line Def Code", DataExchLineDef.Code);
DataExchMapping.FindFirst();
// Populate the Header/Detail/Footer work tables
if DataExchMapping."Pre-Mapping Codeunit" > 0 then
CODEUNIT.Run(DataExchMapping."Pre-Mapping Codeunit", DataExch);
// Create the Entries and values in the Data Exch. Field table
PositivePayExportMgt.PreparePosPayFooter(DataExch, DataExchEntryCodeDetail, BankAccount."Bank Account No.");
if DataExchMapping."Mapping Codeunit" > 0 then
CODEUNIT.Run(DataExchMapping."Mapping Codeunit", DataExch);
DataExchDef.Get(DataExchDefCode);
if DataExchDef."Reading/Writing Codeunit" = CODEUNIT::"Exp. Writing Pos. Pay" then
PositivePayExportMgt.ExportDataExchToFlatFile(DataExch."Entry No.", Filename, DataExchLineDef."Line Type", 0);
DataExchEntryCodeFooter := DataExch."Entry No.";
until DataExchLineDef.Next() = 0;
end;
}