Codeunit 181 Copy Gen. Journal Mgt., source in 29
Source29
src/Layers/W1/BaseApp/Finance/GeneralLedger/Journal/CopyGenJournalMgt.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.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Ledger;
using Microsoft.Purchases.Payables;
using Microsoft.Sales.Receivables;
using System.Utilities;
/// <summary>
/// Management codeunit for copying posted general journal lines back to active general journal batches.
/// Provides functionality to recreate journal entries from posted transactions for corrections or recurring entries.
/// </summary>
/// <remarks>
/// Core functionality for copying posted journal transactions back to active journals for reprocessing.
/// Supports copying individual posted lines or complete G/L registers with validation and parameter configuration.
/// Key features: Posted line copying, G/L register recreation, parameter-based configuration, validation checks.
/// Integration: Works with Copy Gen. Journal Parameters for configuration, validates against applied entries.
/// </remarks>
codeunit 181 "Copy Gen. Journal Mgt."
{
trigger OnRun()
begin
end;
var
CopiedLinesTxt: Label '%1 posted general journal lines was copied to General Journal.\\Do you want to open target general journal?', Comment = '%1 - number of lines';
CanBeCopiedErr: Label 'You cannot copy the posted general journal lines with G/L register number %1 because they contain customer, vendor, or employee ledger entries that were posted and applied in the same G/L register.', Comment = '%1 = "G/L Register" number';
SkipValidationConfirmQst: Label 'No GL Register found with no. %1, do you still want to copy and skip validation?', Comment = 'Confirmation message when no GL Register is found for the posted lines being copied.';
/// <summary>
/// Copies posted general journal lines to an active general journal batch for reprocessing or correction.
/// Validates posted lines can be copied and prompts user for copy parameters before creating new journal lines.
/// </summary>
/// <param name="PostedGenJournalLine">Posted journal lines to copy (multiple lines supported via filters)</param>
procedure CopyToGenJournal(var PostedGenJournalLine: Record "Posted Gen. Journal Line")
var
CopyGenJournalParameters: Record "Copy Gen. Journal Parameters";
begin
if not PostedGenJournalLine.FindSet() then
exit;
CheckIfCanBeCopied(PostedGenJournalLine);
if not GetCopyParameters(CopyGenJournalParameters, PostedGenJournalLine) then
exit;
PostedGenJournalLine.FindSet();
repeat
InsertGenJournalLine(PostedGenJournalLine, CopyGenJournalParameters);
until PostedGenJournalLine.Next() = 0;
ShowFinishMessage(PostedGenJournalLine.Count, CopyGenJournalParameters);
end;
/// <summary>
/// Copies complete G/L registers (all posted lines from specific register numbers) to active general journal batches.
/// Handles bulk copying of entire posting transactions organized by G/L register with validation and parameter setup.
/// </summary>
/// <param name="SrcPostedGenJournalLine">Source posted journal lines filtered by G/L register numbers to copy</param>
procedure CopyGLRegister(var SrcPostedGenJournalLine: Record "Posted Gen. Journal Line")
var
PostedGenJournalLine: Record "Posted Gen. Journal Line";
TempPostedGenJournalLine: Record "Posted Gen. Journal Line" temporary;
TempGLRegister: Record "G/L Register" temporary;
begin
if not SrcPostedGenJournalLine.FindSet() then
exit;
repeat
TempGLRegister.Init();
TempGLRegister."No." := SrcPostedGenJournalLine."G/L Register No.";
if TempGLRegister.Insert() then;
until SrcPostedGenJournalLine.Next() = 0;
if not TempGLRegister.FindSet() then
exit;
repeat
PostedGenJournalLine.SetRange("G/L Register No.", TempGLRegister."No.");
if PostedGenJournalLine.FindSet() then
repeat
TempPostedGenJournalLine.Init();
TempPostedGenJournalLine := PostedGenJournalLine;
TempPostedGenJournalLine.Insert();
until PostedGenJournalLine.Next() = 0;
until TempGLRegister.Next() = 0;
CopyToGenJournal(TempPostedGenJournalLine);
end;
local procedure InsertGenJournalLine(PostedGenJournalLine: Record "Posted Gen. Journal Line"; CopyGenJournalParameters: Record "Copy Gen. Journal Parameters")
var
GenJournalLine: Record "Gen. Journal Line";
begin
OnBeforeInsertGenJournalLine(PostedGenJournalLine, CopyGenJournalParameters);
GenJournalLine.Init();
GenJournalLine.TransferFields(PostedGenJournalLine, true);
GenJournalLine."Journal Template Name" := CopyGenJournalParameters."Journal Template Name";
GenJournalLine."Journal Batch Name" := CopyGenJournalParameters."Journal Batch Name";
if CopyGenJournalParameters."Replace Posting Date" <> 0D then
GenJournalLine.Validate("Posting Date", CopyGenJournalParameters."Replace Posting Date");
if CopyGenJournalParameters."Replace Document No." <> '' then
GenJournalLine."Document No." := CopyGenJournalParameters."Replace Document No.";
GenJournalLine."Line No." := GenJournalLine.GetNewLineNo(GenJournalLine."Journal Template Name", GenJournalLine."Journal Batch Name");
GenJournalLine."Posting No. Series" := '';
if CopyGenJournalParameters."Reverse Sign" then begin
GenJournalLine.Validate("Document Type", GenJournalLine."Document Type"::" ");
GenJournalLine.Validate(Amount, -GenJournalLine.Amount);
end;
GenJournalLine.Insert(true);
OnAfterInsertGenJournalLine(PostedGenJournalLine, CopyGenJournalParameters, GenJournalLine);
end;
local procedure GetCopyParameters(var CopyGenJournalParameters: Record "Copy Gen. Journal Parameters"; var PostedGenJournalLine: Record "Posted Gen. Journal Line") Result: Boolean
var
TempSrcGenJournalBatch: Record "Gen. Journal Batch" temporary;
CopyGenJournalParametersPage: Page "Copy Gen. Journal Parameters";
begin
PrepareCopyGenJournalParameters(CopyGenJournalParameters, PostedGenJournalLine, TempSrcGenJournalBatch);
CopyGenJournalParametersPage.SetCopyParameters(CopyGenJournalParameters, TempSrcGenJournalBatch);
if CopyGenJournalParametersPage.RunModal() <> Action::OK then
exit(false);
CopyGenJournalParametersPage.GetCopyParameters(CopyGenJournalParameters);
if CopyGenJournalParameters."Journal Template Name" <> '' then
CopyGenJournalParameters.TestField("Journal Batch Name");
Result := true;
OnAfterGetCopyParameters(CopyGenJournalParameters, Result);
end;
local procedure ShowFinishMessage(LineCount: Integer; CopyGenJournalParameters: Record "Copy Gen. Journal Parameters")
var
GenJournalBatch: Record "Gen. Journal Batch";
ConfirmManagement: Codeunit "Confirm Management";
GenJnlManagement: Codeunit GenJnlManagement;
begin
if ConfirmManagement.GetResponse(StrSubstNo(CopiedLinesTxt, LineCount), false) then begin
GenJournalBatch.Get(CopyGenJournalParameters."Journal Template Name", CopyGenJournalParameters."Journal Batch Name");
GenJnlManagement.TemplateSelectionFromBatch(GenJournalBatch);
end;
end;
local procedure CheckIfCanBeCopied(var PostedGenJournalLine: Record "Posted Gen. Journal Line")
var
GLRegister: Record "G/L Register";
ConfirmManagement: Codeunit "Confirm Management";
ConfirmHandled: Boolean;
ConfirmResponse: Boolean;
begin
if not PostedGenJournalLine.FindSet() then
exit;
repeat
if GLRegister.Get(PostedGenJournalLine."G/L Register No.") then begin
CheckCustomerEntries(GLRegister);
CheckVendorEntries(GLRegister);
end else begin
ConfirmHandled := false;
ConfirmResponse := false;
OnCheckIfCanBeCopiedOnBeforeSkipValidationOrError(PostedGenJournalLine, ConfirmHandled, ConfirmResponse);
if ConfirmHandled then begin
if not ConfirmResponse then
Error('');
end else
if not ConfirmManagement.GetResponseOrDefault(StrSubstNo(SkipValidationConfirmQst, PostedGenJournalLine."G/L Register No."), false) then
Error('');
end;
until PostedGenJournalLine.Next() = 0;
OnAfterCheckIfCanBeCopied(PostedGenJournalLine);
end;
local procedure CheckCustomerEntries(GLRegister: Record "G/L Register")
var
DetailedCustLedgEntry: Record "Detailed Cust. Ledg. Entry";
begin
DetailedCustLedgEntry.SetCurrentKey("Cust. Ledger Entry No.", "Entry Type", "Posting Date");
DetailedCustLedgEntry.SetRange("Cust. Ledger Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
DetailedCustLedgEntry.SetFilter("Entry Type", '<>%1', DetailedCustLedgEntry."Entry Type"::"Initial Entry");
if not DetailedCustLedgEntry.IsEmpty() then
ShowCanBeCopiedError(GLRegister."No.");
end;
local procedure CheckVendorEntries(GLRegister: Record "G/L Register")
var
DetailedVendorLedgEntry: Record "Detailed Vendor Ledg. Entry";
begin
DetailedVendorLedgEntry.SetCurrentKey("Vendor Ledger Entry No.", "Entry Type", "Posting Date");
DetailedVendorLedgEntry.SetRange("Vendor Ledger Entry No.", GLRegister."From Entry No.", GLRegister."To Entry No.");
DetailedVendorLedgEntry.SetFilter("Entry Type", '<>%1', DetailedVendorLedgEntry."Entry Type"::"Initial Entry");
if not DetailedVendorLedgEntry.IsEmpty() then
ShowCanBeCopiedError(GLRegister."No.");
end;
local procedure ShowCanBeCopiedError(GLRegisterNo: Integer)
begin
Error(CanBeCopiedErr, GLRegisterNo);
end;
local procedure PrepareCopyGenJournalParameters(var CopyGenJournalParameters: Record "Copy Gen. Journal Parameters"; var PostedGenJournalLine: Record "Posted Gen. Journal Line"; var SrcGenJournalBatch: Record "Gen. Journal Batch")
var
TempGenJournalBatch: Record "Gen. Journal Batch" temporary;
begin
if not PostedGenJournalLine.FindSet() then
exit;
repeat
TempGenJournalBatch.Init();
TempGenJournalBatch."Journal Template Name" := PostedGenJournalLine."Journal Template Name";
TempGenJournalBatch.Name := PostedGenJournalLine."Journal Batch Name";
if TempGenJournalBatch.Insert() then;
until PostedGenJournalLine.Next() = 0;
if TempGenJournalBatch.Count = 1 then begin
TempGenJournalBatch.FindFirst();
SrcGenJournalBatch."Journal Template Name" := TempGenJournalBatch."Journal Template Name";
SrcGenJournalBatch.Name := TempGenJournalBatch.Name;
CopyGenJournalParameters."Journal Template Name" := TempGenJournalBatch."Journal Template Name";
CopyGenJournalParameters."Journal Batch Name" := TempGenJournalBatch.Name;
end;
end;
/// <summary>
/// Integration event raised before inserting a copied general journal line from posted transaction.
/// Allows modification of posted data or copy parameters before creating the new journal line.
/// </summary>
/// <param name="PostedGenJournalLine">Posted journal line being copied to active journal</param>
/// <param name="CopyGenJournalParameters">Copy parameters controlling destination batch and processing options</param>
[IntegrationEvent(false, false)]
local procedure OnBeforeInsertGenJournalLine(var PostedGenJournalLine: Record "Posted Gen. Journal Line"; var CopyGenJournalParameters: Record "Copy Gen. Journal Parameters")
begin
end;
/// <summary>
/// Integration event raised after validating that posted general journal lines can be copied.
/// Provides extensibility for additional validation rules or custom copy eligibility checks.
/// </summary>
/// <param name="PostedGenJournalLine">Posted journal line that passed standard copy validation checks</param>
[IntegrationEvent(false, false)]
local procedure OnAfterCheckIfCanBeCopied(PostedGenJournalLine: Record "Posted Gen. Journal Line")
begin
end;
/// <summary>
/// Integration event raised after successfully inserting a copied general journal line into the active batch.
/// Enables post-processing of the newly created journal line or additional field updates.
/// </summary>
/// <param name="PostedGenJournalLine">Source posted journal line that was copied</param>
/// <param name="CopyGenJournalParameters">Copy parameters used during the insertion process</param>
/// <param name="GenJournalLine">Newly created general journal line in the active batch</param>
[IntegrationEvent(false, false)]
local procedure OnAfterInsertGenJournalLine(PostedGenJournalLine: Record "Posted Gen. Journal Line"; CopyGenJournalParameters: Record "Copy Gen. Journal Parameters"; var GenJournalLine: Record "Gen. Journal Line")
begin
end;
/// <summary>
/// Integration event raised after retrieving copy parameters from the user interface.
/// Allows modification of copy parameters or overriding the user's parameter selection result.
/// </summary>
/// <param name="CopyGenJournalParameters">Copy parameters obtained from user input or defaults</param>
/// <param name="Result">Boolean result indicating whether copy parameters were successfully obtained</param>
[IntegrationEvent(false, false)]
local procedure OnAfterGetCopyParameters(var CopyGenJournalParameters: Record "Copy Gen. Journal Parameters"; var Result: Boolean)
begin
end;
/// <summary>
/// Integration event raised before confirming whether to skip validation when no G/L Register is found.
/// Provides extensibility for handling the confirmation or overriding the default behavior.
/// </summary>
/// <param name="PostedGenJournalLine">Posted journal line being evaluated for copy eligibility</param>
/// <param name="ConfirmHandled">Boolean flag indicating whether the confirmation was handled by the event subscriber</param>
/// <param name="ConfirmResponse">Boolean response to return as the confirm action if confirm dialog is skipped</param>
[IntegrationEvent(false, false)]
local procedure OnCheckIfCanBeCopiedOnBeforeSkipValidationOrError(PostedGenJournalLine: Record "Posted Gen. Journal Line"; var ConfirmHandled: Boolean; var ConfirmResponse: Boolean)
begin
end;
}