Codeunit 1313 Correct Posted Purch. Invoice, source in 29
Source29
src/Layers/W1/BaseApp/Purchases/History/CorrectPostedPurchInvoice.Codeunit.al1242 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.History;
using Microsoft.EServices.EDocument;
using Microsoft.Finance.Currency;
using Microsoft.Finance.Dimension;
using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.Finance.GeneralLedger.Journal;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Finance.VAT.Setup;
using Microsoft.Foundation.NoSeries;
using Microsoft.Inventory;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Ledger;
using Microsoft.Inventory.Posting;
using Microsoft.Inventory.Setup;
using Microsoft.Purchases.Document;
using Microsoft.Purchases.Payables;
using Microsoft.Purchases.Posting;
using Microsoft.Purchases.Setup;
using Microsoft.Purchases.Vendor;
using Microsoft.Utilities;
using Microsoft.Warehouse.Request;
using System.Environment.Configuration;
codeunit 1313 "Correct Posted Purch. Invoice"
{
Permissions = TableData "Purch. Inv. Header" = rm,
TableData "Purch. Cr. Memo Hdr." = rm;
TableNo = "Purch. Inv. Header";
trigger OnRun()
var
PurchaseHeader: Record "Purchase Header";
ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
NoSeries: Codeunit "No. Series";
RedoApplications: Boolean;
begin
RedoApplications := UnapplyCostApplication(ItemJnlPostLine, Rec."No.");
OnRunOnBeforeCreateCopyDocument(Rec);
CreateCopyDocument(Rec, PurchaseHeader, PurchaseHeader."Document Type"::"Credit Memo", false);
PurchaseHeader."Vendor Cr. Memo No." := PurchaseHeader."No.";
CheckPurchaseOrderLinesCanAbsorbCancellation(Rec."No.");
SuppressCommit := not NoSeries.IsNoSeriesInDateOrder(PurchaseHeader."Posting No. Series");
OnAfterCreateCorrectivePurchCrMemo(Rec, PurchaseHeader, CancellingOnly, SuppressCommit);
if not SuppressCommit then
Commit();
CODEUNIT.Run(CODEUNIT::"Purch.-Post", PurchaseHeader);
SetTrackInfoForCancellation(Rec);
if RedoApplications then
ItemJnlPostLine.RedoApplications();
UpdatePurchaseOrderLinesFromCancelledInvoice(Rec."No.");
ResetIncomingDocumentForCancelledInvoice(Rec."No.");
OnRunOnAfterUpdatePurchaseOrderLinesFromCancelledInvoice(Rec, PurchaseHeader);
Commit();
end;
var
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
CancellingOnly: Boolean;
SuppressCommit: Boolean;
PostedInvoiceIsPaidCorrectErr: Label 'You cannot correct this posted purchase invoice because it is fully or partially paid.\\To reverse a paid purchase invoice, you must manually create a purchase credit memo.';
PostedInvoiceIsPaidCCancelErr: Label 'You cannot cancel this posted purchase invoice because it is fully or partially paid.\\To reverse a paid purchase invoice, you must manually create a purchase credit memo.';
AlreadyCorrectedErr: Label 'You cannot correct this posted purchase invoice because it has been canceled.';
AlreadyCancelledErr: Label 'You cannot cancel this posted purchase invoice because it has already been canceled.';
CorrCorrectiveDocErr: Label 'You cannot correct this posted purchase invoice because it represents a correction of a credit memo.';
CancelCorrectiveDocErr: Label 'You cannot cancel this posted purchase invoice because it represents a correction of a credit memo.';
CancelledQtyExceedsOrderErr: Label 'The credit memo quantity to reverse exceeds the received or invoiced quantity on purchase order %1 line %2. A corrective credit memo cannot reverse more than was originally received and invoiced.', Comment = '%1 = Purchase order no. %2 = Purchase order line no.';
VendorIsBlockedCorrectErr: Label 'You cannot correct this posted purchase invoice because vendor %1 is blocked.', Comment = '%1 = Customer name';
VendorIsBlockedCancelErr: Label 'You cannot cancel this posted purchase invoice because vendor %1 is blocked.', Comment = '%1 = Customer name';
ItemIsBlockedCorrectErr: Label 'You cannot correct this posted purchase invoice because item %1 %2 is blocked.', Comment = '%1 = Item No. %2 = Item Description';
ItemIsBlockedCancelErr: Label 'You cannot cancel this posted purchase invoice because item %1 %2 is blocked.', Comment = '%1 = Item No. %2 = Item Description';
ItemVariantIsBlockedCorrectErr: Label 'You cannot correct this posted purchase invoice because item variant %1 for item %2 %3 is blocked.', Comment = '%1 - Item Variant Code, %2 = Item No. %3 = Item Description';
ItemVariantIsBlockedCancelErr: Label 'You cannot cancel this posted purchase invoice because item variant %1 for item %2 %3 is blocked.', Comment = '%1 - Item Variant Code, %2 = Item No. %3 = Item Description';
AccountIsBlockedCorrectErr: Label 'You cannot correct this posted purchase invoice because %1 %2 is blocked.', Comment = '%1 = Table Caption %2 = Account number.';
AccountIsBlockedCancelErr: Label 'You cannot cancel this posted purchase invoice because %1 %2 is blocked.', Comment = '%1 = Table Caption %2 = Account number.';
NoFreeInvoiceNoSeriesCorrectErr: Label 'You cannot correct this posted purchase invoice because no unused invoice numbers are available. \\You must extend the range of the number series for purchase invoices.';
NoFreeInvoiceNoSeriesCancelErr: Label 'You cannot cancel this posted purchase invoice because no unused invoice numbers are available. \\You must extend the range of the number series for purchase invoices.';
NoFreeCMSeriesCorrectErr: Label 'You cannot correct this posted purchase invoice because no unused credit memo numbers are available. \\You must extend the range of the number series for credit memos.';
NoFreeCMSeriesCancelErr: Label 'You cannot cancel this posted purchase invoice because no unused credit memo numbers are available. \\You must extend the range of the number series for credit memos.';
NoFreePostCMSeriesCorrectErr: Label 'You cannot correct this posted purchase invoice because no unused posted credit memo numbers are available. \\You must extend the range of the number series for posted credit memos.';
NoFreePostCMSeriesCancelErr: Label 'You cannot cancel this posted purchase invoice because no unused posted credit memo numbers are available. \\You must extend the range of the number series for posted credit memos.';
PurchaseLineFromOrderCorrectErr: Label 'You cannot correct this posted purchase invoice because item %1 %2 is used on a purchase order.', Comment = '%1 = Item no. %2 = Item description';
PurchaseLineFromOrderCancelErr: Label 'You cannot cancel this posted purchase invoice because item %1 %2 is used on a purchase order.', Comment = '%1 = Item no. %2 = Item description';
ShippedQtyReturnedCorrectErr: Label 'You cannot correct this posted purchase invoice because item %1 %2 has already been fully or partially returned.', Comment = '%1 = Item no. %2 = Item description.';
ShippedQtyReturnedCancelErr: Label 'You cannot cancel this posted purchase invoice because item %1 %2 has already been fully or partially returned.', Comment = '%1 = Item no. %2 = Item description.';
UsedInJobCorrectErr: Label 'You cannot correct this posted purchase invoice because item %1 %2 is used in a job.', Comment = '%1 = Item no. %2 = Item description.';
UsedInJobCancelErr: Label 'You cannot cancel this posted purchase invoice because item %1 %2 is used in a job.', Comment = '%1 = Item no. %2 = Item description.';
PostingNotAllowedCorrectErr: Label 'You cannot correct this posted purchase invoice because it was posted in a posting period that is closed.';
PostingNotAllowedCancelErr: Label 'You cannot cancel this posted purchase invoice because it was posted in a posting period that is closed.';
InvoiceIsBasedOnOrderCorrectErr: Label 'You cannot correct this posted purchase invoice because the invoice is based on a purchase order.';
InvoiceIsBasedOnOrderCancelErr: Label 'You cannot cancel this posted purchase invoice because the invoice is based on a purchase order.';
LineTypeNotAllowedCorrectErr: Label 'You cannot correct this posted purchase invoice because the purchase invoice line for %1 %2 is of type %3, which is not allowed on a simplified purchase invoice.', Comment = '%1 = Item no. %2 = Item description %3 = Item type.';
LineTypeNotAllowedCancelErr: Label 'You cannot cancel this posted purchase invoice because the purchase invoice line for %1 %2 is of type %3, which is not allowed on a simplified purchase invoice.', Comment = '%1 = Item no. %2 = Item description %3 = Item type.';
InvalidDimCodeCorrectErr: Label 'You cannot correct this posted purchase invoice because the dimension rule setup for account ''%1'' %2 prevents %3 %4 from being canceled.', Comment = '%1 = Table caption %2 = Account number %3 = Item no. %4 = Item description.';
InvalidDimCodeCancelErr: Label 'You cannot cancel this posted purchase invoice because the dimension rule setup for account ''%1'' %2 prevents %3 %4 from being canceled.', Comment = '%1 = Table caption %2 = Account number %3 = Item no. %4 = Item description.';
InvalidDimCombinationCorrectErr: Label 'You cannot correct this posted purchase invoice because the dimension combination for item %1 %2 is not allowed.', Comment = '%1 = Item no. %2 = Item description.';
InvalidDimCombinationCancelErr: Label 'You cannot cancel this posted purchase invoice because the dimension combination for item %1 %2 is not allowed.', Comment = '%1 = Item no. %2 = Item description.';
InvalidDimCombHeaderCorrectErr: Label 'You cannot correct this posted purchase invoice because the combination of dimensions on the invoice is blocked.';
InvalidDimCombHeaderCancelErr: Label 'You cannot cancel this posted purchase invoice because the combination of dimensions on the invoice is blocked.';
ExternalDocCorrectErr: Label 'You cannot correct this posted purchase invoice because the external document number is required on the invoice.';
ExternalDocCancelErr: Label 'You cannot cancel this posted purchase invoice because the external document number is required on the invoice.';
InventoryPostClosedCorrectErr: Label 'You cannot correct this posted purchase invoice because the posting inventory period is already closed.';
InventoryPostClosedCancelErr: Label 'You cannot cancel this posted purchase invoice because the posting inventory period is already closed.';
#pragma warning disable AA0470
PostingCreditMemoFailedOpenPostedCMQst: Label 'Canceling the invoice failed because of the following error: \\%1\\A credit memo is posted. Do you want to open the posted credit memo?';
PostingCreditMemoFailedOpenCMQst: Label 'Canceling the invoice failed because of the following error: \\%1\\A credit memo is created but not posted. Do you want to open the credit memo?';
CreatingCreditMemoFailedNothingCreatedErr: Label 'Canceling the invoice failed because of the following error: \\%1.';
#pragma warning restore AA0470
WrongDocumentTypeForCopyDocumentErr: Label 'You cannot correct or cancel this type of document.';
InvoicePartiallyPaidMsg: Label 'Invoice %1 is partially paid or credited. The corrective credit memo may not be fully closed by the invoice.', Comment = '%1 - invoice no.';
InvoiceClosedMsg: Label 'Invoice %1 is closed. The corrective credit memo will not be applied to the invoice.', Comment = '%1 - invoice no.';
SkipLbl: Label 'Skip';
CreateCreditMemoLbl: Label 'Create credit memo anyway';
ShowEntriesLbl: Label 'Show applied entries';
CreateCreditMemoQst: Label 'The invoice was posted from an order. A Purchase Credit memo will be created which you complete and post manually. The quantities will be corrected in the existing Purchase Order.\ \Do you want to continue?';
procedure CancelPostedInvoice(var PurchInvHeader: Record "Purch. Inv. Header"): Boolean
begin
CancellingOnly := true;
exit(CreateCreditMemo(PurchInvHeader));
end;
local procedure CreateCreditMemo(var PurchInvHeader: Record "Purch. Inv. Header"): Boolean
var
PurchaseHeader: Record "Purchase Header";
PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr.";
IsHandled: Boolean;
begin
TestCorrectInvoiceIsAllowed(PurchInvHeader, CancellingOnly);
if not CODEUNIT.Run(CODEUNIT::"Correct Posted Purch. Invoice", PurchInvHeader) then begin
PurchCrMemoHdr.SetRange("Applies-to Doc. No.", PurchInvHeader."No.");
if PurchCrMemoHdr.FindFirst() then begin
if Confirm(StrSubstNo(PostingCreditMemoFailedOpenPostedCMQst, GetLastErrorText)) then begin
IsHandled := false;
OnBeforeShowPostedPurchCreditMemo(PurchCrMemoHdr, IsHandled);
if not IsHandled then
PAGE.Run(PAGE::"Posted Purchase Credit Memo", PurchCrMemoHdr);
end;
end else begin
PurchaseHeader.SetRange("Applies-to Doc. No.", PurchInvHeader."No.");
if PurchaseHeader.FindFirst() then begin
IsHandled := false;
OnCreateCreditMemoOnBeforeConfirmPostingCreditMemoFailedOpen(PurchaseHeader, IsHandled);
if not IsHandled then begin
if Confirm(StrSubstNo(PostingCreditMemoFailedOpenCMQst, GetLastErrorText)) then
OnBeforeShowPurchaseCreditMemo(PurchaseHeader, IsHandled);
if not IsHandled then
PAGE.Run(PAGE::"Purchase Credit Memo", PurchaseHeader);
end;
end else
Error(CreatingCreditMemoFailedNothingCreatedErr, GetLastErrorText);
end;
exit(false);
end;
exit(true);
end;
local procedure CreateCopyDocument(var PurchInvHeader: Record "Purch. Inv. Header"; var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type"; SkipCopyFromDescription: Boolean)
var
CopyDocMgt: Codeunit "Copy Document Mgt.";
begin
OnBeforeCreateCopyDocument(PurchInvHeader, PurchaseHeader, DocumentType, SkipCopyFromDescription);
Clear(PurchaseHeader);
PurchaseHeader."Document Type" := DocumentType;
PurchaseHeader."No." := '';
PurchaseHeader.SetAllowSelectNoSeries();
OnBeforePurchaseHeaderInsert(PurchaseHeader, PurchInvHeader);
PurchaseHeader.Insert(true);
case DocumentType of
PurchaseHeader."Document Type"::"Credit Memo":
CopyDocMgt.SetPropertiesForCorrectiveCreditMemo(true);
PurchaseHeader."Document Type"::Invoice:
CopyDocMgt.SetPropertiesForInvoiceCorrection(SkipCopyFromDescription);
else
Error(WrongDocumentTypeForCopyDocumentErr);
end;
CopyDocMgt.CopyPurchaseDocForInvoiceCancelling(PurchInvHeader."No.", PurchaseHeader);
OnAfterCreateCopyDocument(PurchaseHeader, SkipCopyFromDescription, PurchInvHeader);
end;
procedure CreateCreditMemoCopyDocument(var PurchInvHeader: Record "Purch. Inv. Header"; var PurchaseHeader: Record "Purchase Header"): Boolean
var
PurchHeader: Record "Purchase Header";
begin
if not PurchInvHeader.IsFullyOpen() then begin
ShowInvoiceAppliedNotification(PurchInvHeader);
exit(false);
end;
PurchHeader.SetRange("Document Type", PurchHeader."Document Type"::Order);
PurchHeader.SetRange("No.", PurchInvHeader."Order No.");
if not PurchHeader.IsEmpty then
if not Confirm(CreateCreditMemoQst) then
exit(false);
CreateCopyDocument(PurchInvHeader, PurchaseHeader, PurchaseHeader."Document Type"::"Credit Memo", false);
exit(true);
end;
procedure CreateCorrectiveCreditMemo(var InvoiceNotification: Notification)
var
PurchHeader: Record "Purchase Header";
PurchInvHeader: Record "Purch. Inv. Header";
IsHandled: Boolean;
begin
PurchInvHeader.Get(InvoiceNotification.GetData(PurchInvHeader.FieldName("No.")));
InvoiceNotification.Recall();
CreateCopyDocument(PurchInvHeader, PurchHeader, PurchHeader."Document Type"::"Credit Memo", false);
IsHandled := false;
OnBeforeShowPurchaseCreditMemo(PurchHeader, IsHandled);
if not IsHandled then
PAGE.Run(PAGE::"Purchase Credit Memo", PurchHeader);
end;
procedure ShowAppliedEntries(var InvoiceNotification: Notification)
var
VendLedgerEntry: Record "Vendor Ledger Entry";
PurchInvHeader: Record "Purch. Inv. Header";
begin
PurchInvHeader.Get(InvoiceNotification.GetData(PurchInvHeader.FieldName("No.")));
VendLedgerEntry.Get(PurchInvHeader."Vendor Ledger Entry No.");
PAGE.RunModal(PAGE::"Applied Vendor Entries", VendLedgerEntry);
end;
procedure SkipCorrectiveCreditMemo(var InvoiceNotification: Notification)
begin
InvoiceNotification.Recall();
end;
procedure CancelPostedInvoiceStartNewInvoice(var PurchInvHeader: Record "Purch. Inv. Header"; var PurchaseHeader: Record "Purchase Header")
begin
CancellingOnly := false;
if CreateCreditMemo(PurchInvHeader) then begin
CreateCopyDocument(PurchInvHeader, PurchaseHeader, PurchaseHeader."Document Type"::Invoice, true);
OnCancelPostedInvoiceStartNewInvoiceOnAfterCreateCorrPurchaseInvoice(PurchaseHeader, PurchInvHeader);
Commit();
end;
end;
procedure TestCorrectInvoiceIsAllowed(var PurchInvHeader: Record "Purch. Inv. Header"; Cancelling: Boolean)
begin
CancellingOnly := Cancelling;
TestIfPostingIsAllowed(PurchInvHeader);
TestIfInvoiceIsCorrectedOnce(PurchInvHeader);
TestIfInvoiceIsNotCorrectiveDoc(PurchInvHeader);
TestIfInvoiceIsPaid(PurchInvHeader);
TestIfVendorIsBlocked(PurchInvHeader, PurchInvHeader."Buy-from Vendor No.");
TestIfVendorIsBlocked(PurchInvHeader, PurchInvHeader."Pay-to Vendor No.");
TestVendorDimension(PurchInvHeader, PurchInvHeader."Pay-to Vendor No.");
TestDimensionOnHeader(PurchInvHeader);
TestPurchaseLines(PurchInvHeader);
TestIfAnyFreeNumberSeries(PurchInvHeader);
TestExternalDocument(PurchInvHeader);
TestInventoryPostingClosed(PurchInvHeader);
OnAfterTestCorrectInvoiceIsAllowed(PurchInvHeader, Cancelling);
end;
local procedure ShowInvoiceAppliedNotification(PurchInvHeader: Record "Purch. Inv. Header")
var
NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt.";
InvoiceNotification: Notification;
NotificationText: Text;
begin
InvoiceNotification.Id := CreateGuid();
InvoiceNotification.Scope(NOTIFICATIONSCOPE::LocalScope);
InvoiceNotification.SetData(PurchInvHeader.FieldName("No."), PurchInvHeader."No.");
PurchInvHeader.CalcFields(Closed);
if PurchInvHeader.Closed then
NotificationText := StrSubstNo(InvoiceClosedMsg, PurchInvHeader."No.")
else
NotificationText := StrSubstNo(InvoicePartiallyPaidMsg, PurchInvHeader."No.");
InvoiceNotification.Message(NotificationText);
InvoiceNotification.AddAction(ShowEntriesLbl, CODEUNIT::"Correct Posted Purch. Invoice", 'ShowAppliedEntries');
InvoiceNotification.AddAction(SkipLbl, CODEUNIT::"Correct Posted Purch. Invoice", 'SkipCorrectiveCreditMemo');
InvoiceNotification.AddAction(CreateCreditMemoLbl, CODEUNIT::"Correct Posted Purch. Invoice", 'CreateCorrectiveCreditMemo');
NotificationLifecycleMgt.SendNotification(InvoiceNotification, PurchInvHeader.RecordId);
end;
local procedure SetTrackInfoForCancellation(var PurchInvHeader: Record "Purch. Inv. Header")
var
PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr.";
CancelledDocument: Record "Cancelled Document";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSetTrackInfoForCancellation(PurchInvHeader, IsHandled);
if IsHandled then
exit;
PurchCrMemoHdr.SetRange("Applies-to Doc. No.", PurchInvHeader."No.");
if PurchCrMemoHdr.FindLast() then
CancelledDocument.InsertPurchInvToCrMemoCancelledDocument(PurchInvHeader."No.", PurchCrMemoHdr."No.");
end;
local procedure TestDimensionOnHeader(PurchInvHeader: Record "Purch. Inv. Header")
var
DimensionManagement: Codeunit DimensionManagement;
begin
if not DimensionManagement.CheckDimIDComb(PurchInvHeader."Dimension Set ID") then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::DimCombHeaderErr, PurchInvHeader);
end;
local procedure TestIfVendorIsBlocked(PurchInvHeader: Record "Purch. Inv. Header"; VendNo: Code[20])
var
Vendor: Record Vendor;
begin
Vendor.Get(VendNo);
if Vendor.Blocked in [Vendor.Blocked::All] then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::VendorBlocked, PurchInvHeader);
end;
local procedure TestVendorDimension(PurchInvHeader: Record "Purch. Inv. Header"; VendNo: Code[20])
var
Vendor: Record Vendor;
DimensionManagement: Codeunit DimensionManagement;
TableID: array[10] of Integer;
No: array[10] of Code[20];
begin
Vendor.Get(VendNo);
TableID[1] := DATABASE::Vendor;
No[1] := Vendor."No.";
if not DimensionManagement.CheckDimValuePosting(TableID, No, PurchInvHeader."Dimension Set ID") then
ErrorHelperAccount(Enum::"Correct Purch. Inv. Error Type"::DimErr, Vendor."No.", Vendor.TableCaption(), Vendor."No.", Vendor.Name);
end;
local procedure TestPurchaseLines(PurchInvHeader: Record "Purch. Inv. Header")
var
PurchInvLine: Record "Purch. Inv. Line";
Item: Record Item;
ItemVariant: Record "Item Variant";
DimensionManagement: Codeunit DimensionManagement;
ReceivedQtyNoReturned: Decimal;
RevUnitCostLCY: Decimal;
TableID: array[10] of Integer;
No: array[10] of Code[20];
ThrowItemReturnedError: Boolean;
begin
PurchInvLine.SetRange("Document No.", PurchInvHeader."No.");
if PurchInvLine.Find('-') then
repeat
if not IsCommentLine(PurchInvLine) then begin
if (not PurchInvLine.IsCancellationSupported()) and NotInvRndAccount(PurchInvHeader."Vendor Posting Group", PurchInvLine) then
ErrorHelperLine(Enum::"Correct Purch. Inv. Error Type"::WrongItemType, PurchInvLine);
if PurchInvLine.Type = PurchInvLine.Type::Item then begin
Item.Get(PurchInvLine."No.");
if Item.IsInventoriableType() then
if (PurchInvLine.Quantity > 0) and (PurchInvLine."Job No." = '') and WasNotCancelled(PurchInvHeader."No.") then begin
PurchInvLine.CalcReceivedPurchNotReturned(ReceivedQtyNoReturned, RevUnitCostLCY, false);
ThrowItemReturnedError := PurchInvLine.Quantity <> ReceivedQtyNoReturned;
OnTestPurchaseLinesOnAfterCalcThrowItemReturnedError(PurchInvHeader, PurchInvLine, ThrowItemReturnedError);
if ThrowItemReturnedError then
ErrorHelperLine(Enum::"Correct Purch. Inv. Error Type"::ItemIsReturned, PurchInvLine);
end;
if Item.Blocked then
ErrorHelperLine(Enum::"Correct Purch. Inv. Error Type"::ItemBlocked, PurchInvLine);
if PurchInvLine."Variant Code" <> '' then begin
ItemVariant.SetLoadFields(Blocked);
if ItemVariant.Get(PurchInvLine."No.", PurchInvLine."Variant Code") and ItemVariant.Blocked then
ErrorHelperLine("Correct Purch. Inv. Error Type"::ItemVariantBlocked, PurchInvLine);
end;
TableID[1] := DATABASE::Item;
No[1] := PurchInvLine."No.";
if not DimensionManagement.CheckDimValuePosting(TableID, No, PurchInvLine."Dimension Set ID") then
ErrorHelperAccount(Enum::"Correct Purch. Inv. Error Type"::DimErr, No[1], Item.TableCaption(), Item."No.", Item.Description);
if Item.IsInventoriableType() then
TestInventoryPostingSetup(PurchInvLine);
end;
TestGenPostingSetup(PurchInvLine);
TestVendorPostingGroup(PurchInvHeader);
TestVATPostingSetup(PurchInvLine);
if not DimensionManagement.CheckDimIDComb(PurchInvLine."Dimension Set ID") then
ErrorHelperLine(Enum::"Correct Purch. Inv. Error Type"::DimCombErr, PurchInvLine);
end;
until PurchInvLine.Next() = 0;
end;
local procedure TestGLAccount(AccountNo: Code[20]; PurchInvLine: Record "Purch. Inv. Line")
var
GLAccount: Record "G/L Account";
Item: Record Item;
DimensionManagement: Codeunit DimensionManagement;
TableID: array[10] of Integer;
No: array[10] of Code[20];
begin
GLAccount.Get(AccountNo);
if GLAccount.Blocked then
ErrorHelperAccount(Enum::"Correct Purch. Inv. Error Type"::AccountBlocked, AccountNo, GLAccount.TableCaption(), '', '');
TableID[1] := DATABASE::"G/L Account";
No[1] := AccountNo;
if PurchInvLine.Type = PurchInvLine.Type::Item then begin
Item.Get(PurchInvLine."No.");
if not DimensionManagement.CheckDimValuePosting(TableID, No, PurchInvLine."Dimension Set ID") then
ErrorHelperAccount(Enum::"Correct Purch. Inv. Error Type"::DimErr, AccountNo, GLAccount.TableCaption(), Item."No.", Item.Description);
end;
end;
local procedure TestGLAccount(AccountNo: Code[20]; PurchInvHeader: Record "Purch. Inv. Header")
var
GLAccount: Record "G/L Account";
VendorPostingGroup: Record "Vendor Posting Group";
DimensionManagement: Codeunit DimensionManagement;
TableID: array[10] of Integer;
No: array[10] of Code[20];
begin
GLAccount.Get(AccountNo);
if GLAccount.Blocked then
ErrorHelperAccount(Enum::"Correct Purch. Inv. Error Type"::AccountBlocked, AccountNo, GLAccount.TableCaption(), '', '');
TableID[1] := DATABASE::"G/L Account";
No[1] := AccountNo;
if not DimensionManagement.CheckDimValuePosting(TableID, No, PurchInvHeader."Dimension Set ID") then
ErrorHelperAccount(
Enum::"Correct Purch. Inv. Error Type"::DimErr, AccountNo, GLAccount.TableCaption(),
PurchInvHeader."Vendor Posting Group", VendorPostingGroup.TableCaption());
end;
local procedure TestIfInvoiceIsPaid(PurchInvHeader: Record "Purch. Inv. Header")
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeTestIfInvoiceIsPaid(PurchInvHeader, IsHandled);
if IsHandled then
exit;
PurchInvHeader.CalcFields("Amount Including VAT");
PurchInvHeader.CalcFields("Remaining Amount");
if PurchInvHeader."Amount Including VAT" <> PurchInvHeader."Remaining Amount" then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::IsPaid, PurchInvHeader);
end;
local procedure TestIfInvoiceIsCorrectedOnce(PurchInvHeader: Record "Purch. Inv. Header")
var
CancelledDocument: Record "Cancelled Document";
begin
if CancelledDocument.FindPurchCancelledInvoice(PurchInvHeader."No.") then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::IsCorrected, PurchInvHeader);
end;
local procedure TestIfInvoiceIsNotCorrectiveDoc(PurchInvHeader: Record "Purch. Inv. Header")
var
CancelledDocument: Record "Cancelled Document";
begin
if CancelledDocument.FindPurchCorrectiveInvoice(PurchInvHeader."No.") then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::IsCorrective, PurchInvHeader);
end;
local procedure TestIfPostingIsAllowed(PurchInvHeader: Record "Purch. Inv. Header")
var
GenJnlCheckLine: Codeunit "Gen. Jnl.-Check Line";
begin
if GenJnlCheckLine.DateNotAllowed(PurchInvHeader."Posting Date") then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::PostingNotAllowed, PurchInvHeader);
end;
local procedure TestIfAnyFreeNumberSeries(PurchInvHeader: Record "Purch. Inv. Header")
var
GenJournalTemplate: Record "Gen. Journal Template";
GeneralLedgerSetup: Record "General Ledger Setup";
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
PostingDate: Date;
PostingNoSeries: Code[20];
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeTestIfAnyFreeNumberSeries(PurchInvHeader, CancellingOnly, IsHandled);
if IsHandled then
exit;
PostingDate := WorkDate();
PurchasesPayablesSetup.Get();
if not TryPeekNextNo(PurchasesPayablesSetup."Credit Memo Nos.", PostingDate) then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::SerieNumCM, PurchInvHeader);
GeneralLedgerSetup.Get();
if GeneralLedgerSetup."Journal Templ. Name Mandatory" then begin
GenJournalTemplate.Get(PurchasesPayablesSetup."P. Cr. Memo Template Name");
PostingNoSeries := GenJournalTemplate."Posting No. Series";
end else
PostingNoSeries := PurchasesPayablesSetup."Posted Credit Memo Nos.";
if not TryPeekNextNo(PostingNoSeries, PostingDate) then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::SerieNumPostCM, PurchInvHeader);
if (not CancellingOnly) and (not TryPeekNextNo(PurchasesPayablesSetup."Invoice Nos.", PostingDate)) then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::SerieNumInv, PurchInvHeader);
end;
[TryFunction]
local procedure TryPeekNextNo(NoSeriesCode: Code[20]; UsageDate: Date)
var
NoSeries: Codeunit "No. Series";
begin
if NoSeries.PeekNextNo(NoSeriesCode, UsageDate) = '' then
Error('');
end;
local procedure TestExternalDocument(PurchInvHeader: Record "Purch. Inv. Header")
var
PurchasesPayablesSetup: Record "Purchases & Payables Setup";
begin
PurchasesPayablesSetup.Get();
if (PurchInvHeader."Vendor Invoice No." = '') and PurchasesPayablesSetup."Ext. Doc. No. Mandatory" then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::ExtDocErr, PurchInvHeader);
end;
local procedure TestInventoryPostingClosed(PurchInvHeader: Record "Purch. Inv. Header")
var
InventoryPeriod: Record "Inventory Period";
PurchInvLine: Record "Purch. Inv. Line";
DocumentHasLineWithRestrictedType: Boolean;
begin
PurchInvLine.SetRange("Document No.", PurchInvHeader."No.");
PurchInvLine.SetFilter(Quantity, '<>%1', 0);
PurchInvLine.SetFilter(Type, '%1|%2', PurchInvLine.Type::Item, PurchInvLine.Type::"Charge (Item)");
DocumentHasLineWithRestrictedType := not PurchInvLine.IsEmpty();
if DocumentHasLineWithRestrictedType then begin
InventoryPeriod.SetRange(Closed, true);
InventoryPeriod.SetFilter("Ending Date", '>=%1', PurchInvHeader."Posting Date");
if InventoryPeriod.FindFirst() then
ErrorHelperHeader(Enum::"Correct Purch. Inv. Error Type"::InventoryPostClosed, PurchInvHeader);
end;
end;
local procedure TestGenPostingSetup(PurchInvLine: Record "Purch. Inv. Line")
var
GenPostingSetup: Record "General Posting Setup";
begin
if PurchInvLine."VAT Calculation Type" = PurchInvLine."VAT Calculation Type"::"Sales Tax" then
exit;
GenPostingSetup.Get(PurchInvLine."Gen. Bus. Posting Group", PurchInvLine."Gen. Prod. Posting Group");
if PurchInvLine.Type <> PurchInvLine.Type::"G/L Account" then begin
GenPostingSetup.TestField("Purch. Account");
TestGLAccount(GenPostingSetup."Purch. Account", PurchInvLine);
GenPostingSetup.TestField("Purch. Credit Memo Account");
TestGLAccount(GenPostingSetup."Purch. Credit Memo Account", PurchInvLine);
end;
if IsCheckDirectCostAppliedAccount(PurchInvLine) then begin
GenPostingSetup.TestField("Direct Cost Applied Account");
TestGLAccount(GenPostingSetup."Direct Cost Applied Account", PurchInvLine);
end;
if HasLineDiscountSetup(PurchInvLine) then
if GenPostingSetup."Purch. Line Disc. Account" <> '' then
TestGLAccount(GenPostingSetup."Purch. Line Disc. Account", PurchInvLine);
end;
local procedure TestVendorPostingGroup(PurchInvHeader: Record "Purch. Inv. Header")
var
VendorPostingGroup: Record "Vendor Posting Group";
begin
VendorPostingGroup.Get(PurchInvHeader."Vendor Posting Group");
VendorPostingGroup.TestField("Payables Account");
TestGLAccount(VendorPostingGroup."Payables Account", PurchInvHeader);
end;
local procedure TestVATPostingSetup(PurchInvLine: Record "Purch. Inv. Line")
var
VATPostingSetup: Record "VAT Posting Setup";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeTestVATPostingSetup(PurchInvLine, IsHandled); //due to GST extensions for Indian Version
if IsHandled then
exit;
VATPostingSetup.Get(PurchInvLine."VAT Bus. Posting Group", PurchInvLine."VAT Prod. Posting Group");
if VATPostingSetup."VAT Calculation Type" <> VATPostingSetup."VAT Calculation Type"::"Sales Tax" then begin
VATPostingSetup.TestField("Purchase VAT Account");
TestGLAccount(VATPostingSetup."Purchase VAT Account", PurchInvLine);
end;
end;
local procedure TestInventoryPostingSetup(PurchInvLine: Record "Purch. Inv. Line")
var
InventoryPostingSetup: Record "Inventory Posting Setup";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeTestInventoryPostingSetup(PurchInvLine, IsHandled);
if IsHandled then
exit;
InventoryPostingSetup.Get(PurchInvLine."Location Code", PurchInvLine."Posting Group");
InventoryPostingSetup.TestField("Inventory Account");
TestGLAccount(InventoryPostingSetup."Inventory Account", PurchInvLine);
end;
local procedure IsCommentLine(PurchInvLine: Record "Purch. Inv. Line") Result: Boolean
begin
Result := (PurchInvLine.Type = PurchInvLine.Type::" ") or (PurchInvLine."No." = '');
OnAfterIsCommentLine(PurchInvLine, Result);
end;
local procedure WasNotCancelled(InvNo: Code[20]): Boolean
var
PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr.";
begin
PurchCrMemoHdr.SetRange("Applies-to Doc. Type", PurchCrMemoHdr."Applies-to Doc. Type"::Invoice);
PurchCrMemoHdr.SetRange("Applies-to Doc. No.", InvNo);
exit(PurchCrMemoHdr.IsEmpty);
end;
local procedure NotInvRndAccount(VendorPostingGroupCode: Code[20]; PurchInvLine: Record "Purch. Inv. Line"): Boolean
var
VendorPostingGroup: Record "Vendor Posting Group";
begin
if PurchInvLine.Type <> PurchInvLine.Type::"G/L Account" then
exit(true);
VendorPostingGroup.Get(VendorPostingGroupCode);
exit((VendorPostingGroup."Invoice Rounding Account" <> PurchInvLine."No.") or (not PurchInvLine."System-Created Entry"));
end;
local procedure UnapplyCostApplication(var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; InvNo: Code[20]): Boolean
var
TempItemLedgEntry: Record "Item Ledger Entry" temporary;
TempItemApplicationEntry: Record "Item Application Entry" temporary;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeUnAppyCostApplication(InvNo, IsHandled);
if IsHandled then
exit(false);
FindItemLedgEntries(TempItemLedgEntry, InvNo);
if FindAppliedInbndEntries(TempItemApplicationEntry, TempItemLedgEntry) then begin
repeat
ItemJnlPostLine.UnApply(TempItemApplicationEntry);
until TempItemApplicationEntry.Next() = 0;
exit(true);
end;
end;
procedure FindItemLedgEntries(var ItemLedgEntry: Record "Item Ledger Entry"; InvNo: Code[20])
var
PurchInvLine: Record "Purch. Inv. Line";
begin
PurchInvLine.SetRange("Document No.", InvNo);
PurchInvLine.SetRange(Type, PurchInvLine.Type::Item);
if PurchInvLine.FindSet() then
repeat
PurchInvLine.GetItemLedgEntries(ItemLedgEntry, false);
until PurchInvLine.Next() = 0;
end;
local procedure FindAppliedInbndEntries(var TempItemApplicationEntry: Record "Item Application Entry" temporary; var ItemLedgEntry: Record "Item Ledger Entry"): Boolean
var
ItemApplicationEntry: Record "Item Application Entry";
begin
TempItemApplicationEntry.Reset();
TempItemApplicationEntry.DeleteAll();
if ItemLedgEntry.FindSet() then
repeat
if ItemApplicationEntry.AppliedOutbndEntryExists(ItemLedgEntry."Entry No.", true, false) then
repeat
TempItemApplicationEntry := ItemApplicationEntry;
if not TempItemApplicationEntry.Find() then
TempItemApplicationEntry.Insert();
until ItemApplicationEntry.Next() = 0;
until ItemLedgEntry.Next() = 0;
exit(TempItemApplicationEntry.FindSet());
end;
procedure ErrorHelperHeader(HeaderErrorType: Enum "Correct Purch. Inv. Error Type"; PurchInvHeader: Record "Purch. Inv. Header")
var
Vendor: Record Vendor;
begin
if CancellingOnly then
case HeaderErrorType of
Enum::"Correct Purch. Inv. Error Type"::IsPaid:
Error(PostedInvoiceIsPaidCCancelErr);
Enum::"Correct Purch. Inv. Error Type"::VendorBlocked:
begin
Vendor.Get(PurchInvHeader."Pay-to Vendor No.");
Error(VendorIsBlockedCancelErr, Vendor.Name);
end;
Enum::"Correct Purch. Inv. Error Type"::IsCorrected:
Error(AlreadyCancelledErr);
Enum::"Correct Purch. Inv. Error Type"::IsCorrective:
Error(CancelCorrectiveDocErr);
Enum::"Correct Purch. Inv. Error Type"::SerieNumInv:
Error(NoFreeInvoiceNoSeriesCancelErr);
Enum::"Correct Purch. Inv. Error Type"::SerieNumCM:
Error(NoFreeCMSeriesCancelErr);
Enum::"Correct Purch. Inv. Error Type"::SerieNumPostCM:
Error(NoFreePostCMSeriesCancelErr);
Enum::"Correct Purch. Inv. Error Type"::FromOrder:
Error(InvoiceIsBasedOnOrderCancelErr);
Enum::"Correct Purch. Inv. Error Type"::PostingNotAllowed:
Error(PostingNotAllowedCancelErr);
Enum::"Correct Purch. Inv. Error Type"::ExtDocErr:
Error(ExternalDocCancelErr);
Enum::"Correct Purch. Inv. Error Type"::InventoryPostClosed:
Error(InventoryPostClosedCancelErr);
Enum::"Correct Purch. Inv. Error Type"::DimCombHeaderErr:
Error(InvalidDimCombHeaderCancelErr);
end
else
case HeaderErrorType of
Enum::"Correct Purch. Inv. Error Type"::IsPaid:
Error(PostedInvoiceIsPaidCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::VendorBlocked:
begin
Vendor.Get(PurchInvHeader."Pay-to Vendor No.");
Error(VendorIsBlockedCorrectErr, Vendor.Name);
end;
Enum::"Correct Purch. Inv. Error Type"::IsCorrected:
Error(AlreadyCorrectedErr);
Enum::"Correct Purch. Inv. Error Type"::IsCorrective:
Error(CorrCorrectiveDocErr);
Enum::"Correct Purch. Inv. Error Type"::SerieNumInv:
Error(NoFreeInvoiceNoSeriesCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::SerieNumPostCM:
Error(NoFreePostCMSeriesCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::SerieNumCM:
Error(NoFreeCMSeriesCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::FromOrder:
Error(InvoiceIsBasedOnOrderCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::PostingNotAllowed:
Error(PostingNotAllowedCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::ExtDocErr:
Error(ExternalDocCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::InventoryPostClosed:
Error(InventoryPostClosedCorrectErr);
Enum::"Correct Purch. Inv. Error Type"::DimCombHeaderErr:
Error(InvalidDimCombHeaderCorrectErr);
end;
end;
local procedure ErrorHelperLine(LineErrorType: Enum "Correct Purch. Inv. Error Type"; PurchInvLine: Record "Purch. Inv. Line")
var
Item: Record Item;
begin
if CancellingOnly then
case LineErrorType of
Enum::"Correct Purch. Inv. Error Type"::ItemBlocked:
begin
Item.Get(PurchInvLine."No.");
Error(ItemIsBlockedCancelErr, Item."No.", Item.Description);
end;
"Correct Purch. Inv. Error Type"::ItemVariantBlocked:
begin
Item.SetLoadFields(Description);
Item.Get(PurchInvLine."No.");
Error(ItemVariantIsBlockedCancelErr, PurchInvLine."Variant Code", Item."No.", Item.Description);
end;
Enum::"Correct Purch. Inv. Error Type"::ItemIsReturned:
begin
Item.Get(PurchInvLine."No.");
Error(ShippedQtyReturnedCancelErr, Item."No.", Item.Description);
end;
Enum::"Correct Purch. Inv. Error Type"::LineFromOrder:
Error(PurchaseLineFromOrderCancelErr, PurchInvLine."No.", PurchInvLine.Description);
Enum::"Correct Purch. Inv. Error Type"::WrongItemType:
Error(LineTypeNotAllowedCancelErr, PurchInvLine."No.", PurchInvLine.Description, PurchInvLine.Type);
Enum::"Correct Purch. Inv. Error Type"::LineFromJob:
Error(UsedInJobCancelErr, PurchInvLine."No.", PurchInvLine.Description);
Enum::"Correct Purch. Inv. Error Type"::DimCombErr:
Error(InvalidDimCombinationCancelErr, PurchInvLine."No.", PurchInvLine.Description);
end
else
case LineErrorType of
Enum::"Correct Purch. Inv. Error Type"::ItemBlocked:
begin
Item.Get(PurchInvLine."No.");
Error(ItemIsBlockedCorrectErr, Item."No.", Item.Description);
end;
"Correct Purch. Inv. Error Type"::ItemVariantBlocked:
begin
Item.SetLoadFields(Description);
Item.Get(PurchInvLine."No.");
Error(ItemVariantIsBlockedCorrectErr, PurchInvLine."Variant Code", Item."No.", Item.Description);
end;
Enum::"Correct Purch. Inv. Error Type"::ItemIsReturned:
begin
Item.Get(PurchInvLine."No.");
Error(ShippedQtyReturnedCorrectErr, Item."No.", Item.Description);
end;
Enum::"Correct Purch. Inv. Error Type"::LineFromOrder:
Error(PurchaseLineFromOrderCorrectErr, PurchInvLine."No.", PurchInvLine.Description);
Enum::"Correct Purch. Inv. Error Type"::WrongItemType:
Error(LineTypeNotAllowedCorrectErr, PurchInvLine."No.", PurchInvLine.Description, PurchInvLine.Type);
Enum::"Correct Purch. Inv. Error Type"::LineFromJob:
Error(UsedInJobCorrectErr, PurchInvLine."No.", PurchInvLine.Description);
Enum::"Correct Purch. Inv. Error Type"::DimCombErr:
Error(InvalidDimCombinationCorrectErr, PurchInvLine."No.", PurchInvLine.Description);
end;
end;
local procedure ErrorHelperAccount(AccountErrorType: Enum "Correct Purch. Inv. Error Type"; AccountNo: Code[20]; AccountCaption: Text; No: Code[20]; Name: Text)
begin
if CancellingOnly then
case AccountErrorType of
Enum::"Correct Purch. Inv. Error Type"::AccountBlocked:
Error(AccountIsBlockedCancelErr, AccountCaption, AccountNo);
Enum::"Correct Purch. Inv. Error Type"::DimErr:
Error(InvalidDimCodeCancelErr, AccountCaption, AccountNo, No, Name);
end
else
case AccountErrorType of
Enum::"Correct Purch. Inv. Error Type"::AccountBlocked:
Error(AccountIsBlockedCorrectErr, AccountCaption, AccountNo);
Enum::"Correct Purch. Inv. Error Type"::DimErr:
Error(InvalidDimCodeCorrectErr, AccountCaption, AccountNo, No, Name);
end;
end;
local procedure UpdatePurchaseOrderLinesFromCancelledInvoice(PurchInvHeaderNo: Code[20])
var
TempItemLedgerEntry: Record "Item Ledger Entry" temporary;
PurchaseLine: Record "Purchase Line";
PurchInvLine: Record "Purch. Inv. Line";
UndoPostingManagement: Codeunit "Undo Posting Management";
begin
PurchInvLine.SetRange("Document No.", PurchInvHeaderNo);
PurchInvLine.SetRange("Prepayment Line", false);
if PurchInvLine.FindSet() then
repeat
TempItemLedgerEntry.Reset();
TempItemLedgerEntry.DeleteAll();
PurchInvLine.GetItemLedgEntries(TempItemLedgerEntry, false);
if PurchaseLine.Get(PurchaseLine."Document Type"::Order, PurchInvLine."Order No.", PurchInvLine."Order Line No.") then begin
UpdatePurchaseOrderLineInvoicedQuantity(PurchaseLine, PurchInvLine.Quantity, PurchInvLine."Quantity (Base)");
UpdatePurchaseOrderLinePrepmtAmount(PurchInvLine);
UpdateReverseItemChargeAssignment(PurchaseLine, PurchInvLine.Quantity);
TempItemLedgerEntry.SetFilter("Item Tracking", '<>%1', TempItemLedgerEntry."Item Tracking"::None.AsInteger());
UndoPostingManagement.RevertPostedItemTracking(TempItemLedgerEntry, PurchaseLine."Expected Receipt Date", true);
end;
until PurchInvLine.Next() = 0;
end;
local procedure UpdatePurchaseOrderLineInvoicedQuantity(var PurchaseLine: Record "Purchase Line"; CancelledQuantity: Decimal; CancelledQtyBase: Decimal)
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeUpdatePurchaseOrderLineInvoicedQuantity(PurchaseLine, CancelledQuantity, CancelledQtyBase, IsHandled);
if IsHandled then
exit;
PurchaseLine."Quantity Invoiced" -= CancelledQuantity;
PurchaseLine."Qty. Invoiced (Base)" -= CancelledQtyBase;
PurchaseLine."Quantity Received" -= CancelledQuantity;
PurchaseLine."Qty. Received (Base)" -= CancelledQtyBase;
PurchaseLine.InitOutstanding();
PurchaseLine.InitQtyToReceive();
PurchaseLine.InitQtyToInvoice();
PurchaseLine.Modify();
end;
local procedure HasLineDiscountSetup(PurchInvLine: Record "Purch. Inv. Line") Result: Boolean
begin
PurchasesPayablesSetup.GetRecordOnce();
Result := PurchasesPayablesSetup."Discount Posting" in [PurchasesPayablesSetup."Discount Posting"::"Line Discounts", PurchasesPayablesSetup."Discount Posting"::"All Discounts"];
if Result then
Result := PurchInvLine."Line Discount %" <> 0;
OnHasLineDiscountSetup(PurchasesPayablesSetup, Result);
end;
local procedure IsCheckDirectCostAppliedAccount(PurchInvLine: Record "Purch. Inv. Line") Result: Boolean
var
Item: Record Item;
begin
Result := PurchInvLine.Type in [PurchInvLine.Type::"Charge (Item)", PurchInvLine.Type::"Fixed Asset", PurchInvLine.Type::Item];
if (PurchInvLine.Type = PurchInvLine.Type::Item) and Item.Get(PurchInvLine."No.") then
Result := Item.IsInventoriableType();
OnAfterIsCheckDirectCostAppliedAccount(PurchInvLine, Result);
end;
local procedure UpdateReverseItemChargeAssignment(PurchaseLine: Record "Purchase Line"; CancelledQuantity: Decimal)
var
ItemChargeAssgnt: Record "Item Charge Assignment (Purch)";
ItemChargeAssignment: Codeunit "Item Charge Assgnt. (Purch.)";
begin
if PurchaseLine.Type = PurchaseLine.Type::"Charge (Item)" then
exit;
ItemChargeAssgnt.SetLoadFields("Applies-to Doc. No.", "Applies-to Doc. Line No.", "Item No.", "Qty. Assigned");
ItemChargeAssgnt.SetRange("Applies-to Doc. No.", PurchaseLine."Document No.");
ItemChargeAssgnt.SetRange("Applies-to Doc. Line No.", PurchaseLine."Line No.");
ItemChargeAssgnt.SetRange("Item No.", PurchaseLine."No.");
ItemChargeAssgnt.SetFilter("Qty. Assigned", '<>%1', 0);
if ItemChargeAssgnt.FindFirst() then
ItemChargeAssignment.ReverseItemChargeAssgnt(ItemChargeAssgnt, CancelledQuantity);
end;
internal procedure UpdatePurchaseOrderLineIfExist(PurchaseCreditMemoNo: Code[20])
var
PurchCrMemoLine: Record "Purch. Cr. Memo Line";
begin
PurchCrMemoLine.SetLoadFields("Document No.", "No.", Quantity);
PurchCrMemoLine.SetRange("Document No.", PurchaseCreditMemoNo);
PurchCrMemoLine.SetFilter("No.", '<>%1', '');
PurchCrMemoLine.SetFilter(Quantity, '<>%1', 0);
if PurchCrMemoLine.FindSet() then
repeat
GetPurchInvLineAndUpdatePurchaseOrderLines(PurchCrMemoLine);
until PurchCrMemoLine.Next() = 0;
end;
local procedure GetPurchInvLineAndUpdatePurchaseOrderLines(PurchCrMemoLine: Record "Purch. Cr. Memo Line")
var
PurchInvLine: Record "Purch. Inv. Line";
begin
PurchCrMemoLine.GetPurchaseInvoiceLine(PurchInvLine);
if PurchInvLine."Line No." <> 0 then
UpdatePurchaseOrderLinesFromCreditMemo(PurchInvLine, PurchCrMemoLine);
end;
local procedure UpdatePurchaseOrderLinesFromCreditMemo(PurchInvLine: Record "Purch. Inv. Line"; PurchCrMemoLine: Record "Purch. Cr. Memo Line")
var
PurchaseLine: Record "Purchase Line";
TempItemLedgerEntry: Record "Item Ledger Entry" temporary;
UndoPostingManagement: Codeunit "Undo Posting Management";
begin
if not PurchaseLine.Get(PurchaseLine."Document Type"::Order, PurchInvLine."Order No.", PurchInvLine."Order Line No.") then
exit;
if PurchInvLine.Type = PurchInvLine.Type::Item then
PurchInvLine.GetItemLedgEntries(TempItemLedgerEntry, false);
UpdatePurchaseOrderLineInvoicedQuantity(PurchaseLine, PurchCrMemoLine.Quantity, PurchCrMemoLine."Quantity (Base)");
UpdatePurchaseOrderLinePrepmtAmount(PurchInvLine);
if PurchInvLine.Type = PurchInvLine.Type::Item then begin
if PurchaseLine."Qty. to Receive" = 0 then
UpdateWhseRequest(Database::"Purchase Line", PurchaseLine."Document Type".AsInteger(), PurchaseLine."Document No.", PurchaseLine."Location Code");
TempItemLedgerEntry.SetFilter("Item Tracking", '<>%1', TempItemLedgerEntry."Item Tracking"::None.AsInteger());
UndoPostingManagement.RevertPostedItemTracking(TempItemLedgerEntry, PurchInvLine."Posting Date", true);
end;
end;
local procedure UpdatePurchaseOrderLinePrepmtAmount(PurchInvLine: Record "Purch. Inv. Line")
var
PurchaseHeader: Record "Purchase Header";
PurchaseLine: Record "Purchase Line";
Currency: Record Currency;
begin
if not PurchaseLine.Get(
PurchaseLine."Document Type"::Order,
PurchInvLine."Order No.",
PurchInvLine."Order Line No.")
then
exit;
if (PurchaseLine."Prepayment Amount" = 0) or PurchInvLine."Prepayment Line" then
exit;
PurchaseHeader.Get(PurchaseLine."Document Type"::Order, PurchaseLine."Document No.");
Currency.Initialize(PurchaseHeader."Currency Code", true);
if PurchaseHeader."Currency Code" <> '' then
ValidatePrepmtAmountsWithCurrency(PurchaseLine, PurchaseHeader, PurchInvLine, Currency)
else
ValidatePrepmtAmountsFromPurchInv(PurchaseLine, PurchInvLine, Currency);
PurchaseLine.Validate(
"Prepmt Amt Deducted",
PurchaseLine."Prepmt Amt Deducted" -
Round(
PurchInvLine.Quantity * (PurchaseLine."Prepmt. Line Amount" / PurchaseLine.Quantity),
Currency."Amount Rounding Precision"));
PurchaseLine.Validate(
"Prepmt Amt to Deduct",
PurchaseLine."Prepmt Amt to Deduct" +
Round(
PurchInvLine.Quantity * (PurchaseLine."Prepmt. Line Amount" / PurchaseLine.Quantity),
Currency."Amount Rounding Precision"));
PurchaseLine.Modify(true);
end;
local procedure ValidatePrepmtAmountsWithCurrency(var PurchaseLine: Record "Purchase Line"; PurchaseHeader: Record "Purchase Header"; PurchInvLine: Record "Purch. Inv. Line"; Currency: Record Currency)
var
CurrExchRate: Record "Currency Exchange Rate";
begin
PurchaseLine.Validate(
"Prepmt. Amount Inv. (LCY)",
PurchaseLine."Prepmt. Amount Inv. (LCY)" +
Round(
CurrExchRate.ExchangeAmtFCYToLCY(
PurchaseHeader."Posting Date",
PurchaseHeader."Currency Code",
Round(
PurchInvLine.Quantity * (PurchaseLine."Prepayment Amount" / PurchaseLine.Quantity),
Currency."Amount Rounding Precision"),
PurchaseHeader."Currency Factor"),
Currency."Amount Rounding Precision"));
PurchaseLine.Validate(
"Prepmt. VAT Amount Inv. (LCY)",
PurchaseLine."Prepmt. VAT Amount Inv. (LCY)" +
Round(
CurrExchRate.ExchangeAmtFCYToLCY(
PurchaseHeader."Posting Date",
PurchaseHeader."Currency Code",
Round(
PurchInvLine.Quantity * ((PurchaseLine."Prepmt. Amt. Incl. VAT" - PurchaseLine."Prepmt. VAT Base Amt.") / PurchaseLine.Quantity),
Currency."Amount Rounding Precision"),
PurchaseHeader."Currency Factor"),
Currency."Amount Rounding Precision"));
end;
local procedure ValidatePrepmtAmountsFromPurchInv(var PurchaseLine: Record "Purchase Line"; PurchInvLine: Record "Purch. Inv. Line"; Currency: Record Currency)
begin
PurchaseLine.Validate(
"Prepmt. Amount Inv. (LCY)",
PurchaseLine."Prepmt. Amount Inv. (LCY)" +
Round(
PurchInvLine.Quantity * (PurchaseLine."Prepayment Amount" / PurchaseLine.Quantity),
Currency."Amount Rounding Precision"));
PurchaseLine.Validate(
"Prepmt. VAT Amount Inv. (LCY)",
PurchaseLine."Prepmt. VAT Amount Inv. (LCY)" +
Round(
PurchInvLine.Quantity * ((PurchaseLine."Prepmt. Amt. Incl. VAT" - PurchaseLine."Prepmt. VAT Base Amt.") / PurchaseLine.Quantity),
Currency."Amount Rounding Precision"));
end;
local procedure UpdateWhseRequest(SourceType: Integer; SourceSubType: Integer; SourceNo: Code[20]; LocationCode: Code[10])
var
WarehouseRequest: Record "Warehouse Request";
begin
WarehouseRequest.SetCurrentKey("Source Type", "Source Subtype", "Source No.");
WarehouseRequest.SetSourceFilter(SourceType, SourceSubType, SourceNo);
WarehouseRequest.SetRange("Location Code", LocationCode);
if WarehouseRequest.FindFirst() and WarehouseRequest."Completely Handled" then begin
WarehouseRequest."Completely Handled" := false;
WarehouseRequest.Modify();
end;
end;
local procedure ResetIncomingDocumentForCancelledInvoice(PurchInvoiceHeaderNo: Code[20])
var
PurchInvLine: Record "Purch. Inv. Line";
PurchaseHeader: Record "Purchase Header";
IncomingDocument: Record "Incoming Document";
IncomingDocumentAttachment: Record "Incoming Document Attachment";
DummyRecordID: RecordID;
begin
PurchInvLine.SetLoadFields("Order No.");
PurchInvLine.SetRange("Document No.", PurchInvoiceHeaderNo);
PurchInvLine.SetFilter("Order No.", '<>%1', '');
if not PurchInvLine.FindFirst() then
exit;
if not PurchaseHeader.Get(PurchaseHeader."Document Type"::Order, PurchInvLine."Order No.") then
exit;
if PurchaseHeader."Incoming Document Entry No." = 0 then
exit;
if not IncomingDocument.Get(PurchaseHeader."Incoming Document Entry No.") then
exit;
if not IncomingDocument.Posted then
exit;
IncomingDocument.Posted := false;
IncomingDocument.Processed := false;
IncomingDocument.Status := IncomingDocument.Status::Released;
IncomingDocument."Posted Date-Time" := 0DT;
IncomingDocument."Related Record ID" := DummyRecordID;
IncomingDocument."Document No." := '';
IncomingDocument."Document Type" := IncomingDocument."Document Type"::" ";
IncomingDocument."Posting Date" := 0D;
IncomingDocument.Modify(true);
IncomingDocumentAttachment.SetRange("Incoming Document Entry No.", IncomingDocument."Entry No.");
IncomingDocumentAttachment.ModifyAll("Document No.", '');
IncomingDocumentAttachment.ModifyAll("Posting Date", 0D);
end;
local procedure CheckPurchaseOrderLinesCanAbsorbCancellation(PurchInvHeaderNo: Code[20])
var
PurchaseLine: Record "Purchase Line";
PurchInvLine: Record "Purch. Inv. Line";
begin
PurchaseLine.SetLoadFields("Quantity Invoiced", "Qty. Invoiced (Base)", "Quantity Received", "Qty. Received (Base)");
PurchInvLine.SetLoadFields("Order No.", "Order Line No.", Quantity, "Quantity (Base)");
PurchInvLine.SetRange("Document No.", PurchInvHeaderNo);
PurchInvLine.SetRange("Prepayment Line", false);
if PurchInvLine.FindSet() then
repeat
if PurchaseLine.Get(PurchaseLine."Document Type"::Order, PurchInvLine."Order No.", PurchInvLine."Order Line No.") then
CheckCancelledQuantityWithinOrderLine(PurchaseLine, PurchInvLine.Quantity, PurchInvLine."Quantity (Base)");
until PurchInvLine.Next() = 0;
end;
local procedure CheckCancelledQuantityWithinOrderLine(PurchaseLine: Record "Purchase Line"; CancelledQuantity: Decimal; CancelledQtyBase: Decimal)
begin
if (Abs(CancelledQuantity) > Abs(PurchaseLine."Quantity Invoiced")) or
(Abs(CancelledQtyBase) > Abs(PurchaseLine."Qty. Invoiced (Base)")) or
(Abs(CancelledQuantity) > Abs(PurchaseLine."Quantity Received")) or
(Abs(CancelledQtyBase) > Abs(PurchaseLine."Qty. Received (Base)"))
then
Error(CancelledQtyExceedsOrderErr, PurchaseLine."Document No.", PurchaseLine."Line No.");
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCreateCorrectivePurchCrMemo(PurchInvHeader: Record "Purch. Inv. Header"; var PurchaseHeader: Record "Purchase Header"; var CancellingOnly: Boolean; var SuppressCommit: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterTestCorrectInvoiceIsAllowed(var PurchInvHeader: Record "Purch. Inv. Header"; Cancelling: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCreateCopyDocument(var PurchInvHeader: Record "Purch. Inv. Header"; var PurchaseHeader: Record "Purchase Header"; DocumentType: Enum "Purchase Document Type"; SkipCopyFromDescription: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTestIfInvoiceIsPaid(var PurchInvHeader: Record "Purch. Inv. Header"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTestIfAnyFreeNumberSeries(var PurchInvHeader: Record "Purch. Inv. Header"; CancellingOnly: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforePurchaseHeaderInsert(var PurchaseHeader: Record "Purchase Header"; PurchInvHeader: Record "Purch. Inv. Header")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeUnAppyCostApplication(InvNo: Code[20]; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeUpdatePurchaseOrderLineInvoicedQuantity(var PurchaseLine: Record "Purchase Line"; CancelledQuantity: Decimal; CancelledQtyBase: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTestInventoryPostingSetup(PurchInvLine: Record "Purch. Inv. Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnHasLineDiscountSetup(PurchasesPayablesSetup: Record "Purchases & Payables Setup"; var Result: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnRunOnAfterUpdatePurchaseOrderLinesFromCancelledInvoice(var PurchInvHeader: Record "Purch. Inv. Header"; var PurchaseHeader: Record "Purchase Header")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnRunOnBeforeCreateCopyDocument(var PurchInvHeader: Record "Purch. Inv. Header")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnTestPurchaseLinesOnAfterCalcThrowItemReturnedError(PurchInvHeader: Record "Purch. Inv. Header"; PurchInvLine: Record "Purch. Inv. Line"; var ThrowItemReturnedError: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterIsCheckDirectCostAppliedAccount(PurchInvLine: Record "Purch. Inv. Line"; var Result: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCreateCopyDocument(var PurchaseHeader: Record "Purchase Header"; SkipCopyFromDescription: Boolean; PurchInvHeader: Record "Purch. Inv. Header")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeShowPostedPurchCreditMemo(var PurchCrMemoHdr: Record "Purch. Cr. Memo Hdr."; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeShowPurchaseCreditMemo(var PurchaseHeader: Record "Purchase Header"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCreateCreditMemoOnBeforeConfirmPostingCreditMemoFailedOpen(var PurchaseHeader: Record "Purchase Header"; var IsHandled: Boolean);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCancelPostedInvoiceStartNewInvoiceOnAfterCreateCorrPurchaseInvoice(var PurchaseHeader: Record "Purchase Header"; var PurchInvHeader: Record "Purch. Inv. Header")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterIsCommentLine(PurchInvLine: Record "Purch. Inv. Line"; var Result: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSetTrackInfoForCancellation(var PurchInvHeader: Record "Purch. Inv. Header"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTestVATPostingSetup(PurchInvLine: Record "Purch. Inv. Line"; var IsHandled: Boolean)
begin
end;
#pragma warning disable AS0018
#pragma warning restore AS0018
}