Codeunit 764 Aged Acc. Payable, source in 29
Source29
src/Layers/W1/BaseApp/Finance/ReceivablesPayables/AgedAccPayable.Codeunit.al287 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.Finance.ReceivablesPayables;
using Microsoft.Purchases.Payables;
using Microsoft.Utilities;
using System.Visualization;
/// <summary>
/// Manages aged accounts payable analysis and chart generation for vendor aging reports.
/// Provides business chart data for visualizing vendor payment aging and overdue amounts.
/// </summary>
/// <remarks>
/// Core engine for vendor aging analysis with configurable period lengths and drill-down capabilities.
/// Calculates overdue amounts by vendor and period for business intelligence dashboards.
/// Supports both summary and per-vendor aging analysis with chart visualization integration.
/// </remarks>
codeunit 764 "Aged Acc. Payable"
{
trigger OnRun()
begin
end;
var
ChartDescriptionMsg: Label 'Shows pending payment amounts to vendors summed for a period that you select.\\The first column shows the amount on pending payments that are not past the due date. The following column or columns show overdue amounts within the selected period from the payment due date. The chart shows overdue payment amounts going back up to five years from today''s date depending on the period that you select.';
ChartPerVendorDescriptionMsg: Label 'Shows pending payment amount to the vendor summed for a period that you select.\The first column shows the amount on pending payments that are not past the due date. The following column or columns show overdue amounts within the selected period from the payment due date. The chart shows overdue payment amounts going back up to five years from today''s date depending on the period that you select.';
/// <summary>
/// Updates business chart data with aged accounts payable information.
/// Calculates vendor aging amounts by period and populates chart buffer for visualization.
/// </summary>
/// <param name="BusChartBuf">Business chart buffer to populate with aging data</param>
/// <param name="TempEntryNoAmountBuf">Temporary buffer for entry number and amount calculations</param>
procedure UpdateData(var BusChartBuf: Record "Business Chart Buffer"; var TempEntryNoAmountBuf: Record "Entry No. Amount Buffer" temporary)
var
PeriodIndex: Integer;
PeriodLength: Text[1];
NoOfPeriods: Integer;
begin
BusChartBuf.Initialize();
BusChartBuf.SetXAxis(OverDueText(), BusChartBuf."Data Type"::String);
BusChartBuf.AddDecimalMeasure(AmountText(), 1, BusChartBuf."Chart Type"::Column);
InitParameters(BusChartBuf, PeriodLength, NoOfPeriods, TempEntryNoAmountBuf);
CalculateAgedAccPayable(
BusChartBuf."Period Filter Start Date", PeriodLength, NoOfPeriods,
TempEntryNoAmountBuf);
if TempEntryNoAmountBuf.FindSet() then
repeat
PeriodIndex := TempEntryNoAmountBuf."Entry No.";
BusChartBuf.AddColumn(FormatColumnName(PeriodIndex, PeriodLength, NoOfPeriods, BusChartBuf."Period Length"));
BusChartBuf.SetValueByIndex(0, PeriodIndex, RoundAmount(TempEntryNoAmountBuf.Amount));
until TempEntryNoAmountBuf.Next() = 0
end;
[Scope('OnPrem')]
procedure UpdateDataPerVendor(var BusChartBuf: Record "Business Chart Buffer"; VendorNo: Code[20]; var TempEntryNoAmountBuf: Record "Entry No. Amount Buffer" temporary)
var
PeriodIndex: Integer;
PeriodLength: Text[1];
NoOfPeriods: Integer;
begin
BusChartBuf.Initialize();
BusChartBuf.SetXAxis(OverDueText(), BusChartBuf."Data Type"::String);
BusChartBuf.AddDecimalMeasure(AmountText(), 1, BusChartBuf."Chart Type"::Column);
InitParameters(BusChartBuf, PeriodLength, NoOfPeriods, TempEntryNoAmountBuf);
CalculateAgedAccPayablePerVendor(
VendorNo, '', BusChartBuf."Period Filter Start Date", PeriodLength, NoOfPeriods,
TempEntryNoAmountBuf);
if TempEntryNoAmountBuf.FindSet() then
repeat
PeriodIndex := TempEntryNoAmountBuf."Entry No.";
BusChartBuf.AddColumn(FormatColumnName(PeriodIndex, PeriodLength, NoOfPeriods, BusChartBuf."Period Length"));
BusChartBuf.SetValueByIndex(0, PeriodIndex, RoundAmount(TempEntryNoAmountBuf.Amount));
until TempEntryNoAmountBuf.Next() = 0
end;
local procedure CalculateAgedAccPayable(StartDate: Date; PeriodLength: Text[1]; NoOfPeriods: Integer; var TempEntryNoAmountBuffer: Record "Entry No. Amount Buffer" temporary)
var
VendLedgEntry: Record "Vendor Ledger Entry";
RemainingAmountLCY: Decimal;
EndDate: Date;
Index: Integer;
begin
VendLedgEntry.Reset();
VendLedgEntry.SetCurrentKey("Vendor No.", Open, Positive, "Due Date");
VendLedgEntry.SetRange(Open, true);
VendLedgEntry.SetAutoCalcFields("Remaining Amt. (LCY)");
OnCalculateAgedAccPayableOnAfterFilterVendLedgEntry(VendLedgEntry);
for Index := 0 to NoOfPeriods - 1 do begin
RemainingAmountLCY := 0;
VendLedgEntry.SetFilter(
"Due Date",
DateFilterByAge(Index, StartDate, PeriodLength, NoOfPeriods, EndDate));
if VendLedgEntry.FindSet() then
repeat
RemainingAmountLCY += VendLedgEntry."Remaining Amt. (LCY)";
until VendLedgEntry.Next() = 0;
InsertAmountBuffer(Index, '', -RemainingAmountLCY, StartDate, EndDate, TempEntryNoAmountBuffer)
end;
end;
local procedure CalculateAgedAccPayablePerVendor(VendorNo: Code[20]; VendorGroupCode: Code[20]; StartDate: Date; PeriodLength: Text[1]; NoOfPeriods: Integer; var TempEntryNoAmountBuffer: Record "Entry No. Amount Buffer" temporary)
var
VendLedgEntryRemainAmt: Query "Vend. Ledg. Entry Remain. Amt.";
RemainingAmountLCY: Decimal;
EndDate: Date;
Index: Integer;
begin
if VendorNo <> '' then
VendLedgEntryRemainAmt.SetRange(Vendor_No, VendorNo);
if VendorGroupCode <> '' then
VendLedgEntryRemainAmt.SetRange(Vendor_Posting_Group, VendorGroupCode);
VendLedgEntryRemainAmt.SetRange(IsOpen, true);
for Index := 0 to NoOfPeriods - 1 do begin
RemainingAmountLCY := 0;
VendLedgEntryRemainAmt.SetFilter(
Due_Date,
DateFilterByAge(Index, StartDate, PeriodLength, NoOfPeriods, EndDate));
VendLedgEntryRemainAmt.Open();
if VendLedgEntryRemainAmt.Read() then
RemainingAmountLCY := VendLedgEntryRemainAmt.Sum_Remaining_Amt_LCY;
InsertAmountBuffer(Index, VendorGroupCode, RemainingAmountLCY, StartDate, EndDate, TempEntryNoAmountBuffer)
end;
end;
local procedure DateFilterByAge(Index: Integer; var StartDate: Date; PeriodLength: Text[1]; NoOfPeriods: Integer; var EndDate: Date): Text
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
exit(AgedAccReceivable.DateFilterByAge(Index, StartDate, PeriodLength, NoOfPeriods, EndDate));
end;
local procedure InsertAmountBuffer(Index: Integer; BussUnitCode: Code[20]; AmountLCY: Decimal; StartDate: Date; EndDate: Date; var TempEntryNoAmountBuffer: Record "Entry No. Amount Buffer" temporary)
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
AgedAccReceivable.InsertAmountBuffer(
Index, BussUnitCode, AmountLCY, StartDate, EndDate, TempEntryNoAmountBuffer);
end;
local procedure InitParameters(BusChartBuf: Record "Business Chart Buffer"; var PeriodLength: Text[1]; var NoOfPeriods: Integer; var TempEntryNoAmountBuf: Record "Entry No. Amount Buffer" temporary)
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
AgedAccReceivable.InitParameters(BusChartBuf, PeriodLength, NoOfPeriods, TempEntryNoAmountBuf);
end;
local procedure FormatColumnName(Index: Integer; PeriodLength: Text[1]; NoOfColumns: Integer; Period: Option): Text
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
exit(AgedAccReceivable.FormatColumnName(Index, PeriodLength, NoOfColumns, Period));
end;
/// <summary>
/// Provides drill-down functionality for aged accounts payable chart data.
/// Opens vendor ledger entries filtered by vendor and aging period for detailed analysis.
/// </summary>
/// <param name="BusChartBuf">Business chart buffer containing chart configuration</param>
/// <param name="VendorNo">Vendor number to filter drill-down data</param>
/// <param name="TempEntryNoAmountBuf">Entry buffer containing period and amount data</param>
procedure DrillDown(var BusChartBuf: Record "Business Chart Buffer"; VendorNo: Code[20]; var TempEntryNoAmountBuf: Record "Entry No. Amount Buffer" temporary)
var
MeasureName: Text;
VendorGroupCode: Code[10];
begin
if VendorNo <> '' then
VendorGroupCode := ''
else begin
MeasureName := BusChartBuf.GetMeasureName(BusChartBuf."Drill-Down Measure Index");
VendorGroupCode := CopyStr(MeasureName, 1, MaxStrLen(VendorGroupCode));
end;
if TempEntryNoAmountBuf.Get('', BusChartBuf."Drill-Down X Index") then
DrillDownVendLedgEntries(VendorNo, TempEntryNoAmountBuf."Start Date", TempEntryNoAmountBuf."End Date");
end;
/// <summary>
/// Provides drill-down functionality for aged accounts payable by vendor group.
/// Opens aggregated vendor ledger entries for the selected aging period.
/// </summary>
/// <param name="BusChartBuf">Business chart buffer containing chart configuration</param>
/// <param name="TempEntryNoAmountBuf">Entry buffer containing period and amount data</param>
procedure DrillDownByGroup(var BusChartBuf: Record "Business Chart Buffer"; var TempEntryNoAmountBuf: Record "Entry No. Amount Buffer" temporary)
begin
DrillDown(BusChartBuf, '', TempEntryNoAmountBuf);
end;
local procedure DrillDownVendLedgEntries(VendorNo: Code[20]; StartDate: Date; EndDate: Date)
var
VendLedgEntry: Record "Vendor Ledger Entry";
begin
VendLedgEntry.SetCurrentKey("Vendor No.", Open, Positive, "Due Date");
if VendorNo <> '' then
VendLedgEntry.SetRange("Vendor No.", VendorNo);
if EndDate = 0D then
VendLedgEntry.SetFilter("Due Date", '>=%1', StartDate)
else
VendLedgEntry.SetRange("Due Date", StartDate, EndDate);
VendLedgEntry.SetRange(Open, true);
if VendLedgEntry.IsEmpty() then
exit;
PAGE.Run(PAGE::"Vendor Ledger Entries", VendLedgEntry);
end;
/// <summary>
/// Returns description text for aged accounts payable charts.
/// Provides different descriptions for per-vendor and summary aging analysis.
/// </summary>
/// <param name="PerVendor">True for per-vendor description, false for summary description</param>
/// <returns>Descriptive text explaining the chart purpose and data</returns>
procedure Description(PerVendor: Boolean): Text
begin
if PerVendor then
exit(ChartPerVendorDescriptionMsg);
exit(ChartDescriptionMsg);
end;
/// <summary>
/// Updates status text for the business chart display.
/// Provides current status information for chart visualization.
/// </summary>
/// <param name="BusChartBuf">Business chart buffer containing chart data</param>
/// <returns>Status text for chart display</returns>
procedure UpdateStatusText(BusChartBuf: Record "Business Chart Buffer"): Text
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
exit(AgedAccReceivable.UpdateStatusText(BusChartBuf));
end;
/// <summary>
/// Saves user settings for aged accounts payable chart configuration.
/// Persists period length and other chart preferences for future sessions.
/// </summary>
/// <param name="BusChartBuf">Business chart buffer containing settings to save</param>
procedure SaveSettings(BusChartBuf: Record "Business Chart Buffer")
var
BusChartUserSetup: Record "Business Chart User Setup";
begin
BusChartUserSetup."Period Length" := BusChartBuf."Period Length";
BusChartUserSetup.SaveSetupCU(BusChartUserSetup, CODEUNIT::"Aged Acc. Payable");
end;
local procedure RoundAmount(Amount: Decimal): Decimal
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
exit(AgedAccReceivable.RoundAmount(Amount));
end;
local procedure OverDueText(): Text
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
exit(AgedAccReceivable.OverDueText());
end;
local procedure AmountText(): Text
var
AgedAccReceivable: Codeunit "Aged Acc. Receivable";
begin
exit(AgedAccReceivable.AmountText());
end;
/// <summary>
/// Integration event raised after filtering vendor ledger entries during aged accounts payable calculation.
/// Enables custom filtering logic and additional entry selection criteria.
/// </summary>
/// <param name="VendorLedgerEntry">Vendor ledger entry record with applied filters</param>
[IntegrationEvent(false, false)]
local procedure OnCalculateAgedAccPayableOnAfterFilterVendLedgEntry(var VendorLedgerEntry: Record "Vendor Ledger Entry")
begin
end;
}