Codeunit 1372 Purchase Batch Post Mgt., source in 29
Source29
src/Layers/W1/BaseApp/Purchases/Posting/PurchaseBatchPostMgt.Codeunit.al426 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.Purchases.Posting;
using Microsoft.Finance.Analysis;
using Microsoft.Foundation.BatchProcessing;
using Microsoft.Intercompany.Outbox;
using Microsoft.Inventory.Analysis;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.Setup;
using System.Automation;
using System.Threading;
using System.Utilities;
codeunit 1372 "Purchase Batch Post Mgt."
{
EventSubscriberInstance = Manual;
Permissions = TableData "Batch Processing Parameter" = rimd,
TableData "Batch Processing Session Map" = rimd;
TableNo = "Purchase Header";
trigger OnRun()
var
PurchaseHeader: Record "Purchase Header";
PurchaseBatchPostMgt: Codeunit "Purchase Batch Post Mgt.";
UpdateAnalysisView: Codeunit "Update Analysis View";
UpdateItemAnalysisView: Codeunit "Update Item Analysis View";
begin
PurchaseHeader.Copy(Rec);
BindSubscription(PurchaseBatchPostMgt); // also disables automatic update of Analysis Views
PurchaseBatchPostMgt.SetPostingCodeunitId(PostingCodeunitId);
PurchaseBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
PurchaseBatchPostMgt.Code(PurchaseHeader);
Rec := PurchaseHeader;
UnBindSubscription(PurchaseBatchPostMgt); // reenable automatic update of Analysis Views
UpdateAnalysisView.UpdateAll(0, true);
UpdateItemAnalysisView.UpdateAll(0, true);
end;
var
BatchProcessingMgt: Codeunit "Batch Processing Mgt.";
PostingCodeunitId: Integer;
PostingDateIsNotSetErr: Label 'Enter the posting date.';
BatchPostingMsg: Label 'Batch posting of purchase documents.';
ApprovalPendingErr: Label 'Cannot post purchase document no. %1 of type %2 because it is pending approval.', Comment = '%1 = Document No.; %2 = Document Type';
ApprovalWorkflowErr: Label 'Cannot post purchase document no. %1 of type %2 due to the approval workflow.', Comment = '%1 = Document No.; %2 = Document Type';
InterCompanyZipFileNamePatternTok: Label 'Purchase IC Batch - %1.zip', Comment = '%1 - today date, Sample: Sales IC Batch - 23-01-2024.zip';
ProcessBarMsg: Label 'Processing: @1@@@@@@@', Comment = '1 - overall progress';
procedure RunBatch(var PurchaseHeader: Record "Purchase Header"; ReplacePostingDate: Boolean; PostingDate: Date; ReplaceDocumentDate: Boolean; CalcInvoiceDiscount: Boolean; Receive: Boolean; Invoice: Boolean)
var
TempErrorMessage: Record "Error Message" temporary;
PurchaseBatchPostMgt: Codeunit "Purchase Batch Post Mgt.";
ErrorMessages: Page "Error Messages";
begin
OnBeforeRunBatch(PurchaseHeader, ReplacePostingDate, PostingDate, ReplaceDocumentDate, Receive, Invoice);
if ReplacePostingDate and (PostingDate = 0D) then
Error(PostingDateIsNotSetErr);
BatchProcessingMgt.SetParameter(Enum::"Batch Posting Parameter Type"::Invoice, Invoice);
BatchProcessingMgt.SetParameter(Enum::"Batch Posting Parameter Type"::Receive, Receive);
BatchProcessingMgt.SetParameter(Enum::"Batch Posting Parameter Type"::"Calculate Invoice Discount", CalcInvoiceDiscount);
BatchProcessingMgt.SetParameter(Enum::"Batch Posting Parameter Type"::"Posting Date", PostingDate);
BatchProcessingMgt.SetParameter(Enum::"Batch Posting Parameter Type"::"Replace Posting Date", ReplacePostingDate);
BatchProcessingMgt.SetParameter(Enum::"Batch Posting Parameter Type"::"Replace Document Date", ReplaceDocumentDate);
OnRunBatchOnAfterAddParameters(BatchProcessingMgt);
PurchaseBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
Commit();
if PurchaseBatchPostMgt.Run(PurchaseHeader) then;
BatchProcessingMgt.ResetBatchID();
if GuiAllowed then begin
BatchProcessingMgt.GetErrorMessages(TempErrorMessage);
if TempErrorMessage.FindFirst() then begin
ErrorMessages.SetRecords(TempErrorMessage);
ErrorMessages.Run();
end;
end;
OnAfterRunBatch(PurchaseHeader, TempErrorMessage);
end;
procedure RunWithUI(var PurchaseHeader: Record "Purchase Header"; TotalCount: Integer; Question: Text)
var
ErrorContextElement: Codeunit "Error Context Element";
ErrorMessageMgt: Codeunit "Error Message Management";
ErrorMessageHandler: Codeunit "Error Message Handler";
PurchaseBatchPostMgt: Codeunit "Purchase Batch Post Mgt.";
begin
if not Confirm(StrSubstNo(Question, PurchaseHeader.Count, TotalCount), true) then
exit;
ErrorMessageMgt.Activate(ErrorMessageHandler);
ErrorMessageMgt.PushContext(ErrorContextElement, DATABASE::"Purchase Header", 0, BatchPostingMsg);
PurchaseBatchPostMgt.SetBatchProcessor(BatchProcessingMgt);
Commit();
if PurchaseBatchPostMgt.Run(PurchaseHeader) then;
BatchProcessingMgt.ResetBatchID();
if ErrorMessageMgt.GetLastErrorID() > 0 then
ErrorMessageHandler.ShowErrors();
end;
procedure GetBatchProcessor(var ResultBatchProcessingMgt: Codeunit "Batch Processing Mgt.")
begin
ResultBatchProcessingMgt := BatchProcessingMgt;
end;
procedure SetBatchProcessor(NewBatchProcessingMgt: Codeunit "Batch Processing Mgt.")
begin
BatchProcessingMgt := NewBatchProcessingMgt;
end;
procedure "Code"(var PurchaseHeader: Record "Purchase Header")
var
RecRef: RecordRef;
begin
if PostingCodeunitId = 0 then
PostingCodeunitId := CODEUNIT::"Purch.-Post";
RecRef.GetTable(PurchaseHeader);
BatchProcessingMgt.SetProcessingCodeunit(PostingCodeunitId);
BatchProcessingMgt.BatchProcess(RecRef);
RecRef.SetTable(PurchaseHeader);
end;
local procedure GetICBatchFileName() Result: Text
begin
Result := StrSubstNo(InterCompanyZipFileNamePatternTok, Format(WorkDate(), 10, '<Year4>-<Month,2>-<Day,2>'));
OnGetICBatchFileName(Result);
end;
local procedure PreparePurchaseHeader(var PurchaseHeader: Record "Purchase Header"; var BatchConfirm: Option)
var
CalcInvoiceDiscount: Boolean;
ReplacePostingDate, ReplaceVATDate, ReplaceDocumentDate : Boolean;
PostingDate, VATDate : Date;
begin
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Calculate Invoice Discount", CalcInvoiceDiscount);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Replace Posting Date", ReplacePostingDate);
BatchProcessingMgt.GetDateParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Posting Date", PostingDate);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Replace VAT Date", ReplaceVATDate);
BatchProcessingMgt.GetDateParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::"VAT Date", VATDate);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::"Replace Document Date", ReplaceDocumentDate);
if CalcInvoiceDiscount then
CalculateInvoiceDiscount(PurchaseHeader);
PurchaseHeader.BatchConfirmUpdateDeferralDate(BatchConfirm, ReplacePostingDate, PostingDate, ReplaceVATDate, VATDate);
PurchaseHeader.BatchConfirmUpdatePostingDate(ReplacePostingDate, PostingDate, ReplaceDocumentDate);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::Receive, PurchaseHeader.Receive);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::Invoice, PurchaseHeader.Invoice);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::Ship, PurchaseHeader.Ship);
BatchProcessingMgt.GetBooleanParameter(PurchaseHeader.RecordId, Enum::"Batch Posting Parameter Type"::Print, PurchaseHeader."Print Posted Documents");
OnAfterPreparePurchaseHeader(PurchaseHeader);
end;
procedure SetPostingCodeunitId(NewPostingCodeunitId: Integer)
begin
PostingCodeunitId := NewPostingCodeunitId;
end;
local procedure CalculateInvoiceDiscount(var PurchaseHeader: Record "Purchase Header")
var
PurchaseLine: Record "Purchase Line";
begin
PurchaseLine.Reset();
PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
if PurchaseLine.FindFirst() then begin
CODEUNIT.Run(CODEUNIT::"Purch.-Calc.Discount", PurchaseLine);
Commit();
PurchaseHeader.Get(PurchaseHeader."Document Type", PurchaseHeader."No.");
end;
end;
local procedure CanPostDocument(var PurchaseHeader: Record "Purchase Header"): Boolean
begin
if not CheckApprovalWorkflow(PurchaseHeader) then
exit(false);
if not PurchaseHeader.IsApprovedForPostingBatch() then
exit(false);
exit(true);
end;
[TryFunction]
local procedure CheckApprovalWorkflow(var PurchaseHeader: Record "Purchase Header")
var
ApprovalsMgmt: Codeunit "Approvals Mgmt.";
begin
if ApprovalsMgmt.IsPurchaseApprovalsWorkflowEnabled(PurchaseHeader) then
Error(ApprovalWorkflowErr, PurchaseHeader."No.", PurchaseHeader."Document Type");
if PurchaseHeader.Status = PurchaseHeader.Status::"Pending Approval" then
Error(ApprovalPendingErr, PurchaseHeader."No.", PurchaseHeader."Document Type");
end;
procedure SetParameter(ParameterId: Enum "Batch Posting Parameter Type"; ParameterValue: Variant)
var
ResultBatchProcessingMgt: Codeunit "Batch Processing Mgt.";
begin
GetBatchProcessor(ResultBatchProcessingMgt);
ResultBatchProcessingMgt.SetParameter(ParameterId, ParameterValue);
end;
local procedure ProcessBatchInBackground(var PurchaseHeader: Record "Purchase Header"; var SkippedRecordExists: Boolean)
var
JobQueueEntry: Record "Job Queue Entry";
PurchPostBatchviaJobQueue: Codeunit "Purch Post Batch via Job Queue";
begin
PrepareBatch(PurchaseHeader, JobQueueEntry, SkippedRecordExists);
PurchPostBatchviaJobQueue.EnqueuePurchaseBatch(PurchaseHeader, JobQueueEntry);
end;
local procedure PrepareBatch(var PurchaseHeader: Record "Purchase Header"; var JobQueueEntry: Record "Job Queue Entry"; var SkippedRecordExists: Boolean)
var
ErrorMessageManagement: Codeunit "Error Message Management";
Window: Dialog;
BatchConfirm: Option;
DocCounter: array[2] of Integer;
begin
if PurchaseHeader.FindSet() then begin
if GuiAllowed then begin
DocCounter[1] := PurchaseHeader.Count;
Window.Open(ProcessBarMsg);
end;
repeat
if GuiAllowed then begin
DocCounter[2] += 1;
Window.Update(1, Round(DocCounter[2] / DocCounter[1] * 10000, 1));
end;
if CanProcessPurchaseHeader(PurchaseHeader) then begin
PreparePurchaseHeader(PurchaseHeader, BatchConfirm);
PrepareJobQueueEntry(JobQueueEntry);
PurchaseHeader."Job Queue Entry ID" := JobQueueEntry.ID;
PurchaseHeader."Job Queue Status" := PurchaseHeader."Job Queue Status"::"Scheduled for Posting";
PurchaseHeader.Modify();
Commit();
end else begin
SkippedRecordExists := true;
if GetLastErrorText <> '' then begin
ErrorMessageManagement.LogError(PurchaseHeader.RecordId, GetLastErrorText, '');
ClearLastError();
end;
end;
until PurchaseHeader.Next() = 0;
if GuiAllowed then
Window.Close();
end;
end;
local procedure CanProcessPurchaseHeader(var PurchaseHeader: Record "Purchase Header"): Boolean
begin
if not CheckPurchaseHeaderJobQueueStatus(PurchaseHeader) then
exit(false);
if not CanPostDocument(PurchaseHeader) then
exit(false);
if not ReleasePurchaseHeader(PurchaseHeader) then
exit(false);
exit(true);
end;
[TryFunction]
local procedure CheckPurchaseHeaderJobQueueStatus(var PurchaseHeader: Record "Purchase Header")
begin
if not (PurchaseHeader."Job Queue Status" in [PurchaseHeader."Job Queue Status"::" ", PurchaseHeader."Job Queue Status"::Error]) then
PurchaseHeader.FieldError("Job Queue Status");
end;
local procedure ReleasePurchaseHeader(var PurchaseHeader: Record "Purchase Header"): Boolean
var
Result: Boolean;
begin
if PurchaseHeader.Status = PurchaseHeader.Status::Open then
if not Codeunit.Run(Codeunit::"Release Purchase Document", PurchaseHeader) then
exit(false);
Result := true;
OnAfterReleasePurchaseHeader(PurchaseHeader, Result);
exit(Result);
end;
local procedure PrepareJobQueueEntry(var JobQueueEntry: Record "Job Queue Entry")
begin
if not IsNullGuid(JobQueueEntry.ID) then
exit;
Clear(JobQueueEntry);
JobQueueEntry.ID := CreateGuid();
JobQueueEntry.Insert(true);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Batch Processing Mgt.", 'OnBeforeBatchProcessing', '', false, false)]
local procedure PreparePurchaseHeaderOnBeforeBatchProcessing(var RecRef: RecordRef; var BatchConfirm: Option)
var
PurchaseHeader: Record "Purchase Header";
begin
RecRef.SetTable(PurchaseHeader);
PreparePurchaseHeader(PurchaseHeader, BatchConfirm);
RecRef.GetTable(PurchaseHeader);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Batch Processing Mgt.", 'OnVerifyRecord', '', false, false)]
local procedure CheckPurchaseHeaderOnVerifyRecord(var RecRef: RecordRef; var Result: Boolean)
var
PurchaseHeader: Record "Purchase Header";
begin
RecRef.SetTable(PurchaseHeader);
Result := CanPostDocument(PurchaseHeader);
RecRef.GetTable(PurchaseHeader);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Batch Processing Mgt.", 'OnCustomProcessing', '', false, false)]
local procedure HandleOnCustomProcessing(var RecRef: RecordRef; var Handled: Boolean; var KeepParameters: Boolean)
var
PurchaseHeader: Record "Purchase Header";
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
PurchasePostViaJobQueue: Codeunit "Purchase Post via Job Queue";
begin
RecRef.SetTable(PurchaseHeader);
PurchasesPayablesSetup.Get();
if PurchasesPayablesSetup."Post with Job Queue" then begin
PurchaseHeader."Print Posted Documents" :=
PurchaseHeader."Print Posted Documents" and PurchasesPayablesSetup."Post & Print with Job Queue";
PurchasePostViaJobQueue.EnqueuePurchDocWithUI(PurchaseHeader, false);
if not IsNullGuid(PurchaseHeader."Job Queue Entry ID") then begin
Commit();
KeepParameters := true;
end;
PurchaseHeader."Print Posted Documents" := false;
RecRef.GetTable(PurchaseHeader);
Handled := true;
end;
end;
[IntegrationEvent(false, false)]
local procedure OnAfterPreparePurchaseHeader(var PurchaseHeader: Record "Purchase Header")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterRunBatch(var PurchaseHeader: Record "Purchase Header"; var TempErrorMessage: Record "Error Message" temporary)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeRunBatch(var PurchaseHeader: Record "Purchase Header"; var ReplacePostingDate: Boolean; var PostingDate: Date; var ReplaceDocumentDate: Boolean; Receive: Boolean; Invoice: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnRunBatchOnAfterAddParameters(var BatchProcessingMgt: Codeunit "Batch Processing Mgt.")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetICBatchFileName(var Result: Text)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterReleasePurchaseHeader(var PurchaseHeader: Record "Purchase Header"; var Result: Boolean);
begin
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Batch Processing Mgt.", 'OnIsPostWithJobQueueEnabled', '', false, false)]
local procedure OnIsPostWithJobQueueEnabledHandler(var Result: Boolean)
var
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
begin
PurchasesPayablesSetup.Get();
Result := PurchasesPayablesSetup."Post with Job Queue";
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Batch Processing Mgt.", 'OnProcessBatchInBackground', '', false, false)]
local procedure OnProcessBatchInBackgroundHandler(var RecRef: RecordRef; var SkippedRecordExists: Boolean)
var
PurchaseHeader: Record "Purchase Header";
begin
RecRef.SetTable(PurchaseHeader);
ProcessBatchInBackground(PurchaseHeader, SkippedRecordExists);
RecRef.GetTable(PurchaseHeader);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Batch Processing Mgt.", 'OnBatchProcessOnBeforeResetBatchID', '', false, false)]
local procedure OnBatchProcessOnBeforeResetBatchID(var RecRef: RecordRef; ProcessingCodeunitID: Integer)
var
ICOutboxExport: Codeunit "IC Outbox Export";
begin
ICOutboxExport.DownloadBatchFiles(GetICBatchFileName());
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Update Analysis View", 'OnBeforeUpdateAll', '', false, false)]
local procedure OnBeforeUpdateAnalysisView(Which: Option "Ledger Entries","Budget Entries",Both; DirectlyFromPosting: Boolean; var AnalysisView: Record "Analysis View"; var InBatchPosting: Boolean)
begin
InBatchPosting := true;
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Update Item Analysis View", 'OnBeforeUpdateAll', '', false, false)]
local procedure OnBeforeUpdateItemAnalysisView(var IsHandled: Boolean)
begin
IsHandled := true;
end;
}