From 92995ae0b94eab08b5afe5176f60dc3d15906673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joshua=20Mart=C3=ADnez=20Pineda?= Date: Thu, 12 Mar 2026 15:18:39 +0100 Subject: [PATCH] initial proposal to integrate new baseapp's po matching to edocs --- .../EDocCreatePurchaseInvoice.Codeunit.al | 44 +---- .../EDocLineByReceipt.Query.al | 49 ------ .../EDocPOMatching.Codeunit.al | 152 +++++++---------- .../EDocPOMatchingUnitTests.Codeunit.al | 154 ------------------ 4 files changed, 61 insertions(+), 338 deletions(-) delete mode 100644 src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocLineByReceipt.Query.al diff --git a/src/Apps/W1/EDocument/App/src/Processing/Import/FinishDraft/EDocCreatePurchaseInvoice.Codeunit.al b/src/Apps/W1/EDocument/App/src/Processing/Import/FinishDraft/EDocCreatePurchaseInvoice.Codeunit.al index e26ff50213..c6e4158b08 100644 --- a/src/Apps/W1/EDocument/App/src/Processing/Import/FinishDraft/EDocCreatePurchaseInvoice.Codeunit.al +++ b/src/Apps/W1/EDocument/App/src/Processing/Import/FinishDraft/EDocCreatePurchaseInvoice.Codeunit.al @@ -48,7 +48,6 @@ codeunit 6117 "E-Doc. Create Purchase Invoice" implements IEDocumentFinishDraft, if not EDocPOMatching.VerifyEDocumentMatchedLinesAreValidMatches(EDocumentPurchaseHeader) then Error(YourMatchedLinesAreNotValidErr); - EDocPOMatching.SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader); EDocPOMatching.CalculatePOMatchWarnings(EDocumentPurchaseHeader, TempPOMatchWarnings); TempPOMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::NotYetReceived); if not TempPOMatchWarnings.IsEmpty() then @@ -106,16 +105,11 @@ codeunit 6117 "E-Doc. Create Purchase Invoice" implements IEDocumentFinishDraft, VendorLedgerEntry: Record "Vendor Ledger Entry"; EDocumentPurchaseHeader: Record "E-Document Purchase Header"; EDocumentPurchaseLine: Record "E-Document Purchase Line"; - PurchaseLine: Record "Purchase Line"; EDocRecordLink: Record "E-Doc. Record Link"; PurchCalcDiscByType: Codeunit "Purch - Calc Disc. By Type"; - EDocLineByReceipt: Query "E-Doc. Line by Receipt"; - LastReceiptNo: Code[20]; PurchaseLineNo: Integer; StopCreatingPurchaseInvoice: Boolean; VendorInvoiceNo: Code[35]; - ReceiptNoLbl: Label 'Receipt No. %1:', Comment = '%1 = Receipt No.'; - NullGuid: Guid; begin EDocumentPurchaseHeader.GetFromEDocument(EDocument); if not AllDraftLinesHaveTypeAndNumberSpecificed(EDocumentPurchaseHeader) then begin @@ -155,39 +149,13 @@ codeunit 6117 "E-Doc. Create Purchase Invoice" implements IEDocumentFinishDraft, end; EDocRecordLink.InsertEDocumentHeaderLink(EDocumentPurchaseHeader, PurchaseHeader); - PurchaseLineNo := GetLastLineNumberOnPurchaseInvoice(PurchaseHeader."No."); // We get the last line number, even if this is a new document since recurrent lines get inserted on the header's creation - // We create first the lines without any PO matches - EDocLineByReceipt.SetRange(EDocumentEntryNo, EDocument."Entry No"); - EDocLineByReceipt.SetRange(ReceiptNo, ''); - EDocLineByReceipt.SetRange(PurchaseLineSystemId, NullGuid); - EDocLineByReceipt.Open(); - while EDocLineByReceipt.Read() do begin - EDocumentPurchaseLine.GetBySystemId(EDocLineByReceipt.SystemId); - CreatePurchaseInvoiceLine(PurchaseHeader, EDocumentPurchaseLine, EDocumentPurchaseHeader."Total Discount" > 0, PurchaseLineNo); - end; - EDocLineByReceipt.Close(); + PurchaseLineNo := GetLastLineNumberOnPurchaseInvoice(PurchaseHeader."No."); + EDocumentPurchaseLine.SetRange("E-Document Entry No.", EDocument."Entry No"); + if EDocumentPurchaseLine.FindSet() then + repeat + CreatePurchaseInvoiceLine(PurchaseHeader, EDocumentPurchaseLine, EDocumentPurchaseHeader."Total Discount" > 0, PurchaseLineNo); + until EDocumentPurchaseLine.Next() = 0; - // Then we create the lines with receipt no., adding comment lines for each receipt no. - LastReceiptNo := ''; - EDocLineByReceipt.SetFilter(ReceiptNo, '<> %1', ''); - EDocLineByReceipt.SetRange(PurchaseLineSystemId); - EDocLineByReceipt.Open(); - while EDocLineByReceipt.Read() do begin - if LastReceiptNo <> EDocLineByReceipt.ReceiptNo then begin // A receipt no. for which we have not created a header comment line yet - Clear(PurchaseLine); - PurchaseLine."Document Type" := PurchaseHeader."Document Type"; - PurchaseLine."Document No." := PurchaseHeader."No."; - PurchaseLineNo += 10000; - PurchaseLine."Line No." := PurchaseLineNo; - PurchaseLine.Type := PurchaseLine.Type::" "; - PurchaseLine.Description := StrSubstNo(ReceiptNoLbl, EDocLineByReceipt.ReceiptNo); - PurchaseLine.Insert(); - end; - EDocumentPurchaseLine.GetBySystemId(EDocLineByReceipt.SystemId); - CreatePurchaseInvoiceLine(PurchaseHeader, EDocumentPurchaseLine, EDocumentPurchaseHeader."Total Discount" > 0, PurchaseLineNo); - LastReceiptNo := EDocLineByReceipt.ReceiptNo; - end; - EDocLineByReceipt.Close(); PurchaseHeader.Modify(); PurchCalcDiscByType.ApplyInvDiscBasedOnAmt(EDocumentPurchaseHeader."Total Discount", PurchaseHeader); exit(PurchaseHeader); diff --git a/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocLineByReceipt.Query.al b/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocLineByReceipt.Query.al deleted file mode 100644 index d3ed8bc1d6..0000000000 --- a/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocLineByReceipt.Query.al +++ /dev/null @@ -1,49 +0,0 @@ -// ------------------------------------------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// ------------------------------------------------------------------------------------------------ -namespace Microsoft.eServices.EDocument.Processing.Import.Purchase; - -using Microsoft.Purchases.History; - -/// -/// Query to get the e-document lines sorted by the receipt number that they have assigned -/// -query 6100 "E-Doc. Line by Receipt" -{ - Access = Internal; - OrderBy = ascending(ReceiptNo); - InherentEntitlements = X; - InherentPermissions = X; - - elements - { - dataitem(EDocumentPurchaseLine; "E-Document Purchase Line") - { - column(SystemId; SystemId) - { - } - column(EDocumentEntryNo; "E-Document Entry No.") - { - } - dataitem(EDocPurchaseLinePOMatch; "E-Doc. Purchase Line PO Match") - { - DataItemLink = "E-Doc. Purchase Line SystemId" = EDocumentPurchaseLine.SystemId; - SqlJoinType = LeftOuterJoin; - column(PurchaseLineSystemId; "Purchase Line SystemId") - { - } - column(ReceiptLineSystemId; "Receipt Line SystemId") - { - } - dataitem(PurchRcptLine; "Purch. Rcpt. Line") - { - DataItemLink = SystemId = EDocPurchaseLinePOMatch."Receipt Line SystemId"; - column(ReceiptNo; "Document No.") - { - } - } - } - } - } -} \ No newline at end of file diff --git a/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocPOMatching.Codeunit.al b/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocPOMatching.Codeunit.al index 250f44236d..6f05b20d71 100644 --- a/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocPOMatching.Codeunit.al +++ b/src/Apps/W1/EDocument/App/src/Processing/Import/Purchase/PurchaseOrderMatching/EDocPOMatching.Codeunit.al @@ -6,9 +6,11 @@ namespace Microsoft.eServices.EDocument.Processing.Import.Purchase; using Microsoft.eServices.EDocument; using Microsoft.Inventory.Item; +using Microsoft.Inventory.Tracking; using Microsoft.Purchases.Document; using Microsoft.Purchases.History; using Microsoft.Purchases.Vendor; +using System.Utilities; codeunit 6196 "E-Doc. PO Matching" { @@ -408,7 +410,6 @@ codeunit 6196 "E-Doc. PO Matching" Vendor: Record Vendor; EDocPurchaseLinePOMatch: Record "E-Doc. Purchase Line PO Match"; TempMatchWarnings: Record "E-Doc PO Match Warning" temporary; - MatchesToMultiplePOLinesNotSupportedErr: Label 'Matching an e-document line to multiple purchase order lines is not currently supported.'; NotLinkedToVendorErr: Label 'The selected purchase order line is not linked to the same vendor as the e-document line.'; AlreadyMatchedErr: Label 'A selected purchase order line is already matched to another e-document line. E-Document: %1, Purchase document: %2 %3.', Comment = '%1 - E-Document No., %2 - Purchase Document Type, %3 - Purchase Document No.'; OrderLineAndEDocFromDifferentVendorsErr: Label 'All selected purchase order lines must belong to orders for the same vendor as the e-document line.'; @@ -421,8 +422,6 @@ codeunit 6196 "E-Doc. PO Matching" begin if SelectedPOLines.IsEmpty() then exit; - if SelectedPOLines.Count() > 1 then - Error(MatchesToMultiplePOLinesNotSupportedErr); RemoveAllMatchesForEDocumentLine(EDocumentPurchaseLine); FirstOfLinesBeingMatched := true; MatchedPOLineVendorNo := ''; @@ -483,8 +482,7 @@ codeunit 6196 "E-Doc. PO Matching" /// /// Matches the specified purchase receipt lines to the specified E-Document line. /// Each receipt line must be matched to a purchase order line that is matched to the specified E-Document line. - /// Existing matches are removed. - /// If the receipt lines can't cover the full quantity of the E-Document line, the procedure raises an error. + /// Existing receipt matches are removed before creating new ones. /// /// /// @@ -494,14 +492,9 @@ codeunit 6196 "E-Doc. PO Matching" TempMatchedPurchaseLines: Record "Purchase Line" temporary; NullGuid: Guid; ReceiptLineNotMatchedErr: Label 'A selected receipt line is not matched to any of the purchase order lines matched to the e-document line.'; - ReceiptLinesDontCoverErr: Label 'The selected receipt lines do not cover the full quantity of the e-document line.'; - MatchesToMultipleReceiptLinesNotSupportedErr: Label 'Matching an e-document line to multiple receipt lines is not currently supported.'; - QuantityCovered: Decimal; begin if SelectedReceiptLines.IsEmpty() then exit; - if SelectedReceiptLines.Count() > 1 then - Error(MatchesToMultipleReceiptLinesNotSupportedErr); // Remove existing receipt line matches EDocPurchaseLinePOMatch.SetRange("E-Doc. Purchase Line SystemId", EDocumentPurchaseLine.SystemId); @@ -521,10 +514,7 @@ codeunit 6196 "E-Doc. PO Matching" EDocPurchaseLinePOMatch."Purchase Line SystemId" := TempMatchedPurchaseLines.SystemId; EDocPurchaseLinePOMatch."Receipt Line SystemId" := SelectedReceiptLines.SystemId; EDocPurchaseLinePOMatch.Insert(); - QuantityCovered += SelectedReceiptLines.Quantity; until SelectedReceiptLines.Next() = 0; - if QuantityCovered < EDocumentPurchaseLine.Quantity then - Error(ReceiptLinesDontCoverErr); end; procedure ConfigureDefaultPOMatchingSettings() @@ -587,55 +577,6 @@ codeunit 6196 "E-Doc. PO Matching" end; end; - /// - /// If the E-Document has been matched to an order line without specifying receipts, we match with receipt lines for that order line that can cover the E-Document line quantity. - /// - /// - procedure SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader: Record "E-Document Purchase Header") - var - EDocumentPurchaseLine: Record "E-Document Purchase Line"; - EDocPurchaseLinePOMatch: Record "E-Doc. Purchase Line PO Match"; - PurchaseOrderLine: Record "Purchase Line"; - PurchaseReceiptLine: Record "Purch. Rcpt. Line"; - TempPurchaseReceiptLine: Record "Purch. Rcpt. Line" temporary; - EDocLineQuantity: Decimal; - NullGuid: Guid; - begin - EDocumentPurchaseLine.SetRange("E-Document Entry No.", EDocumentPurchaseHeader."E-Document Entry No."); - if EDocumentPurchaseLine.FindSet() then - repeat - Clear(EDocPurchaseLinePOMatch); - EDocPurchaseLinePOMatch.SetRange("E-Doc. Purchase Line SystemId", EDocumentPurchaseLine.SystemId); - EDocPurchaseLinePOMatch.SetRange("Receipt Line SystemId", NullGuid); - if not EDocPurchaseLinePOMatch.FindFirst() then - continue; // No PO lines matched, so no receipt can be suggested - if not PurchaseOrderLine.GetBySystemId(EDocPurchaseLinePOMatch."Purchase Line SystemId") then - continue; // Should not happen, but we skip in case it does, this procedure doesn't error out - EDocPurchaseLinePOMatch.SetRange("Purchase Line SystemId", PurchaseOrderLine.SystemId); - EDocPurchaseLinePOMatch.SetFilter("Receipt Line SystemId", '<> %1', NullGuid); - if not EDocPurchaseLinePOMatch.IsEmpty() then - continue; // There's already at least one receipt line matched, so no suggestion is needed - Session.LogMessage('0000QQI', 'Suggesting receipt line for draft line matched to PO line', Verbosity::Verbose, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', 'E-Document'); - PurchaseReceiptLine.SetRange("Order No.", PurchaseOrderLine."Document No."); - PurchaseReceiptLine.SetRange("Order Line No.", PurchaseOrderLine."Line No."); - PurchaseReceiptLine.SetFilter(Quantity, '> 0'); - if PurchaseReceiptLine.FindSet() then - repeat - if GetEDocumentLineQuantityInBaseUoM(EDocumentPurchaseLine, EDocLineQuantity) then - if PurchaseReceiptLine.Quantity >= EDocLineQuantity then begin - // We suggest the first receipt line that can cover the full quantity of the E-Document line - Session.LogMessage('0000QQJ', 'Suggested covering receipt line for draft line matched to PO line', Verbosity::Verbose, DataClassification::SystemMetadata, TelemetryScope::All, 'Category', 'E-Document'); - Clear(TempPurchaseReceiptLine); - TempPurchaseReceiptLine.DeleteAll(); - TempPurchaseReceiptLine.Copy(PurchaseReceiptLine); - TempPurchaseReceiptLine.Insert(); - MatchReceiptLinesToEDocumentLine(TempPurchaseReceiptLine, EDocumentPurchaseLine); - break; // We only suggest a single receipt line - end; - until PurchaseReceiptLine.Next() = 0; - until EDocumentPurchaseLine.Next() = 0; - end; - local procedure GetEDocumentLineQuantityInBaseUoM(EDocumentPurchaseLine: Record "E-Document Purchase Line"; var Quantity: Decimal): Boolean var Item: Record Item; @@ -664,21 +605,50 @@ codeunit 6196 "E-Doc. PO Matching" procedure TransferPOMatchesFromEDocumentToInvoice(EDocument: Record "E-Document") var EDocumentPurchaseLine: Record "E-Document Purchase Line"; + EDocPurchaseLinePOMatch: Record "E-Doc. Purchase Line PO Match"; PurchaseLine: Record "Purchase Line"; - TempPurchaseReceiptLine: Record "Purch. Rcpt. Line" temporary; + PurchaseOrderLine: Record "Purchase Line"; + PurchRcptLine: Record "Purch. Rcpt. Line"; + Math: Codeunit Math; + PurchaseOrderMatching: Codeunit "Purchase Order Matching"; + NullGuid: Guid; + RemainingQty, RemainingQtyBase, AllocatedQty, AllocatedQtyBase : Decimal; begin EDocumentPurchaseLine.SetRange("E-Document Entry No.", EDocument."Entry No"); if EDocumentPurchaseLine.FindSet() then repeat - LoadReceiptLinesMatchedToEDocumentLine(EDocumentPurchaseLine, TempPurchaseReceiptLine); - if not TempPurchaseReceiptLine.FindFirst() then // We only support a single receipt line match in BaseApp - continue; PurchaseLine := EDocumentPurchaseLine.GetLinkedPurchaseLine(); if IsNullGuid(PurchaseLine.SystemId) then continue; - PurchaseLine."Receipt No." := TempPurchaseReceiptLine."Document No."; - PurchaseLine."Receipt Line No." := TempPurchaseReceiptLine."Line No."; - PurchaseLine.Modify(); + + EDocPurchaseLinePOMatch.SetRange("E-Doc. Purchase Line SystemId", EDocumentPurchaseLine.SystemId); + EDocPurchaseLinePOMatch.SetFilter("Receipt Line SystemId", '<>%1', NullGuid); + if EDocPurchaseLinePOMatch.IsEmpty() then + continue; + + RemainingQty := PurchaseLine.Quantity; + RemainingQtyBase := PurchaseLine."Quantity (Base)"; + EDocPurchaseLinePOMatch.FindSet(); + repeat + if not PurchaseOrderLine.GetBySystemId(EDocPurchaseLinePOMatch."Purchase Line SystemId") then + continue; + if not PurchRcptLine.GetBySystemId(EDocPurchaseLinePOMatch."Receipt Line SystemId") then + continue; + + AllocatedQty := Math.Min(RemainingQty, PurchRcptLine.Quantity); + AllocatedQtyBase := Math.Min(RemainingQtyBase, PurchRcptLine."Quantity (Base)"); + if AllocatedQty <= 0 then + continue; + + PurchaseOrderMatching.CreateReceiptMatch( + PurchaseLine, PurchaseOrderLine, PurchRcptLine, + AllocatedQty, AllocatedQtyBase, + not ShouldWarnIfNotYetReceived(EDocumentPurchaseLine.GetBCVendor()."No.")); + + RemainingQty -= AllocatedQty; + RemainingQtyBase -= AllocatedQtyBase; + until EDocPurchaseLinePOMatch.Next() = 0; + RemoveAllMatchesForEDocumentLine(EDocumentPurchaseLine); until EDocumentPurchaseLine.Next() = 0; end; @@ -691,39 +661,27 @@ codeunit 6196 "E-Doc. PO Matching" var EDocumentPurchaseLine: Record "E-Document Purchase Line"; PurchaseInvoiceLine: Record "Purchase Line"; - PurchaseOrderLine: Record "Purchase Line"; - PurchaseReceiptLine: Record "Purch. Rcpt. Line"; TempPOLineToMatch: Record "Purchase Line" temporary; TempReceiptLineToMatch: Record "Purch. Rcpt. Line" temporary; + PurchaseOrderMatching: Codeunit "Purchase Order Matching"; begin PurchaseInvoiceLine.SetRange("Document Type", PurchaseHeader."Document Type"); PurchaseInvoiceLine.SetRange("Document No.", PurchaseHeader."No."); - PurchaseInvoiceLine.SetFilter("Receipt No.", '<>%1', ''); - PurchaseInvoiceLine.SetFilter("Receipt Line No.", '<>%1', 0); - if PurchaseInvoiceLine.IsEmpty() then - exit; - PurchaseInvoiceLine.FindSet(); - repeat - if not EDocumentPurchaseLine.GetFromLinkedPurchaseLine(PurchaseInvoiceLine) then - continue; - if not PurchaseReceiptLine.Get(PurchaseInvoiceLine."Receipt No.", PurchaseInvoiceLine."Receipt Line No.") then - continue; - if not PurchaseOrderLine.Get(Enum::"Purchase Document Type"::Order, PurchaseReceiptLine."Order No.", PurchaseReceiptLine."Order Line No.") then - continue; - TempPOLineToMatch.DeleteAll(); - TempPOLineToMatch.Copy(PurchaseOrderLine); - TempPOLineToMatch.Insert(); - MatchPOLinesToEDocumentLine(TempPOLineToMatch, EDocumentPurchaseLine); - - TempReceiptLineToMatch.DeleteAll(); - TempReceiptLineToMatch.Copy(PurchaseReceiptLine); - TempReceiptLineToMatch.Insert(); - MatchReceiptLinesToEDocumentLine(TempReceiptLineToMatch, EDocumentPurchaseLine); - until PurchaseInvoiceLine.Next() = 0; - PurchaseInvoiceLine.SetRange("Receipt No."); - PurchaseInvoiceLine.SetRange("Receipt Line No."); - PurchaseInvoiceLine.ModifyAll("Receipt No.", ''); - PurchaseInvoiceLine.ModifyAll("Receipt Line No.", 0); + if PurchaseInvoiceLine.FindSet() then + repeat + if not EDocumentPurchaseLine.GetFromLinkedPurchaseLine(PurchaseInvoiceLine) then + continue; + + PurchaseOrderMatching.LoadMatchedOrderLines(PurchaseInvoiceLine, TempPOLineToMatch); + if not TempPOLineToMatch.IsEmpty() then + MatchPOLinesToEDocumentLine(TempPOLineToMatch, EDocumentPurchaseLine); + + PurchaseOrderMatching.LoadMatchedReceiptLines(PurchaseInvoiceLine, TempReceiptLineToMatch); + if not TempReceiptLineToMatch.IsEmpty() then + MatchReceiptLinesToEDocumentLine(TempReceiptLineToMatch, EDocumentPurchaseLine); + + PurchaseOrderMatching.DeleteMatchesForInvoiceLine(PurchaseInvoiceLine); + until PurchaseInvoiceLine.Next() = 0; end; /// diff --git a/src/Apps/W1/EDocument/Test/src/Matching/EDocPOMatchingUnitTests.Codeunit.al b/src/Apps/W1/EDocument/Test/src/Matching/EDocPOMatchingUnitTests.Codeunit.al index 4133a2fb53..6f9db7cb7f 100644 --- a/src/Apps/W1/EDocument/Test/src/Matching/EDocPOMatchingUnitTests.Codeunit.al +++ b/src/Apps/W1/EDocument/Test/src/Matching/EDocPOMatchingUnitTests.Codeunit.al @@ -2172,160 +2172,6 @@ codeunit 133508 "E-Doc. PO Matching Unit Tests" Assert.IsTrue(TempPOMatchWarnings.IsEmpty(), 'Expected no NotYetReceived warning for non-specified vendor'); end; - [Test] - procedure SuggestReceiptsForMatchedOrderLinesDoesNotSuggestWhenEDocLineAlreadyHasReceiptMatch() - var - EDocument: Record "E-Document"; - EDocumentPurchaseHeader: Record "E-Document Purchase Header"; - EDocumentPurchaseLine: Record "E-Document Purchase Line"; - PurchaseHeader: Record "Purchase Header"; - PurchaseLine: Record "Purchase Line"; - PurchaseReceiptHeader: Record "Purch. Rcpt. Header"; - PurchaseReceiptLine: Record "Purch. Rcpt. Line"; - Item: Record Item; - begin - Initialize(); - // [SCENARIO] SuggestReceiptsForMatchedOrderLines suggests no receipts when E-Document line already has a receipt match - // [GIVEN] An E-Document line matched to a receipt line and an additional receipt line that could be suggested - CreateMockEDocumentDraftWithLine(EDocument, EDocumentPurchaseHeader, EDocumentPurchaseLine, 10); - LibraryInventory.CreateItem(Item); - LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor."No."); - LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, Item."No.", 10); - - // Match E-Document line to PO line - MatchEDocumentLineToPOLine(EDocumentPurchaseLine, PurchaseLine); - - // Create receipt with 2 lines that could be suggested, match the last one to an E-Document line - CreateMockReceiptHeader(PurchaseReceiptHeader, Vendor."No."); - CreateMockReceiptLine(PurchaseReceiptLine, PurchaseReceiptHeader, Item."No.", 10, PurchaseLine); - CreateMockReceiptLine(PurchaseReceiptLine, PurchaseReceiptHeader, Item."No.", 10, PurchaseLine); - MatchEDocumentLineToReceiptLine(EDocumentPurchaseLine, PurchaseReceiptLine); - - // [WHEN] SuggestReceiptsForMatchedOrderLines is called - EDocPOMatching.SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader); - - // [THEN] No additional receipt lines are matched (still just the one) - Assert.IsTrue(EDocPOMatching.IsReceiptLineMatchedToEDocumentLine(PurchaseReceiptLine, EDocumentPurchaseLine), 'Expected the original receipt match to remain'); - Assert.AreEqual(1, CountReceiptMatchesForEDocumentLine(EDocumentPurchaseLine), 'Expected exactly one receipt match'); - end; - - [Test] - procedure SuggestReceiptsForMatchedOrderLinesSuggestsReceiptWhenPOLineHasSingleReceiptCoveringFullQuantity() - var - EDocument: Record "E-Document"; - EDocumentPurchaseHeader: Record "E-Document Purchase Header"; - EDocumentPurchaseLine: Record "E-Document Purchase Line"; - PurchaseHeader: Record "Purchase Header"; - PurchaseLine: Record "Purchase Line"; - PurchaseReceiptHeader: Record "Purch. Rcpt. Header"; - PurchaseReceiptLine: Record "Purch. Rcpt. Line"; - Item: Record Item; - begin - Initialize(); - // [SCENARIO] SuggestReceiptsForMatchedOrderLines suggests receipt when PO line has a single receipt that covers full quantity - // [GIVEN] An E-Document line matched to a purchase order line with quantity 10 - CreateMockEDocumentDraftWithLine(EDocument, EDocumentPurchaseHeader, EDocumentPurchaseLine, 10); - - // [GIVEN] The purchase order line has one receipt line with quantity 10 - LibraryInventory.CreateItem(Item); - LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor."No."); - LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, Item."No.", 10); - EDocumentPurchaseLine."[BC] Unit of Measure" := PurchaseLine."Unit of Measure Code"; - EDocumentPurchaseLine.Modify(); - MatchEDocumentLineToPOLine(EDocumentPurchaseLine, PurchaseLine); - - CreateMockReceiptHeader(PurchaseReceiptHeader, Vendor."No."); - CreateMockReceiptLine(PurchaseReceiptLine, PurchaseReceiptHeader, Item."No.", 10, PurchaseLine); - - // [WHEN] SuggestReceiptsForMatchedOrderLines is called - EDocPOMatching.SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader); - - // [THEN] The receipt line is matched to the E-Document line - Assert.IsTrue(EDocPOMatching.IsReceiptLineMatchedToEDocumentLine(PurchaseReceiptLine, EDocumentPurchaseLine), 'Expected receipt line to be matched to E-Document line'); - end; - - [Test] - procedure SuggestReceiptsForMatchedOrderLinesSuggestsNoReceiptWhenAllReceiptsHaveInsufficientQuantity() - var - EDocument: Record "E-Document"; - EDocumentPurchaseHeader: Record "E-Document Purchase Header"; - EDocumentPurchaseLine: Record "E-Document Purchase Line"; - PurchaseHeader: Record "Purchase Header"; - PurchaseLine: Record "Purchase Line"; - PurchaseReceiptHeader: Record "Purch. Rcpt. Header"; - PurchaseReceiptLine1, PurchaseReceiptLine2 : Record "Purch. Rcpt. Line"; - Item: Record Item; - begin - Initialize(); - // [SCENARIO] SuggestReceiptsForMatchedOrderLines suggests no receipt when all receipts have insufficient quantity - // [GIVEN] An E-Document line matched to a purchase order line with quantity 10 - CreateMockEDocumentDraftWithLine(EDocument, EDocumentPurchaseHeader, EDocumentPurchaseLine, 10); - - // [GIVEN] The purchase order line has two receipt lines with quantities 5 and 7 - LibraryInventory.CreateItem(Item); - LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader."Document Type"::Order, Vendor."No."); - LibraryPurchase.CreatePurchaseLine(PurchaseLine, PurchaseHeader, PurchaseLine.Type::Item, Item."No.", 10); - MatchEDocumentLineToPOLine(EDocumentPurchaseLine, PurchaseLine); - - CreateMockReceiptHeader(PurchaseReceiptHeader, Vendor."No."); - CreateMockReceiptLine(PurchaseReceiptLine1, PurchaseReceiptHeader, Item."No.", 5, PurchaseLine); - CreateMockReceiptLine(PurchaseReceiptLine2, PurchaseReceiptHeader, Item."No.", 7, PurchaseLine); - - // [WHEN] SuggestReceiptsForMatchedOrderLines is called - EDocPOMatching.SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader); - - // [THEN] No receipt lines are matched to the E-Document line - Assert.IsFalse(EDocPOMatching.IsEDocumentLineMatchedToAnyReceiptLine(EDocumentPurchaseLine), 'Expected no receipt lines to be matched'); - end; - - [Test] - procedure SuggestReceiptsForMatchedOrderLinesProcessesMultipleEDocumentLinesIndependently() - var - EDocument: Record "E-Document"; - EDocumentPurchaseHeader: Record "E-Document Purchase Header"; - EDocumentPurchaseLine1, EDocumentPurchaseLine2 : Record "E-Document Purchase Line"; - PurchaseHeader1, PurchaseHeader2 : Record "Purchase Header"; - PurchaseLine1, PurchaseLine2 : Record "Purchase Line"; - PurchaseReceiptHeader1, PurchaseReceiptHeader2 : Record "Purch. Rcpt. Header"; - PurchaseReceiptLine1, PurchaseReceiptLine2 : Record "Purch. Rcpt. Line"; - Item1, Item2 : Record Item; - begin - Initialize(); - // [SCENARIO] SuggestReceiptsForMatchedOrderLines processes multiple E-Document lines independently - // [GIVEN] An E-Document with two lines matched to different purchase order lines - CreateMockEDocumentDraftWithLine(EDocument, EDocumentPurchaseHeader, EDocumentPurchaseLine1, 10); - // Second E-Document line - EDocumentPurchaseLine2 := LibraryEDocument.InsertPurchaseDraftLine(EDocument); - EDocumentPurchaseLine2.Quantity := 15; - EDocumentPurchaseLine2.Modify(); - - // [GIVEN] Each purchase order line has its own receipt that covers the full quantity - LibraryInventory.CreateItem(Item1); - LibraryPurchase.CreatePurchHeader(PurchaseHeader1, PurchaseHeader1."Document Type"::Order, Vendor."No."); - LibraryPurchase.CreatePurchaseLine(PurchaseLine1, PurchaseHeader1, PurchaseLine1.Type::Item, Item1."No.", 10); - EDocumentPurchaseLine1."[BC] Unit of Measure" := PurchaseLine1."Unit of Measure Code"; - EDocumentPurchaseLine1.Modify(); - MatchEDocumentLineToPOLine(EDocumentPurchaseLine1, PurchaseLine1); - CreateMockReceiptHeader(PurchaseReceiptHeader1, Vendor."No."); - CreateMockReceiptLine(PurchaseReceiptLine1, PurchaseReceiptHeader1, Item1."No.", 10, PurchaseLine1); - - LibraryInventory.CreateItem(Item2); - LibraryPurchase.CreatePurchHeader(PurchaseHeader2, PurchaseHeader2."Document Type"::Order, Vendor."No."); - LibraryPurchase.CreatePurchaseLine(PurchaseLine2, PurchaseHeader2, PurchaseLine2.Type::Item, Item2."No.", 15); - EDocumentPurchaseLine2."[BC] Unit of Measure" := PurchaseLine2."Unit of Measure Code"; - EDocumentPurchaseLine2.Modify(); - MatchEDocumentLineToPOLine(EDocumentPurchaseLine2, PurchaseLine2); - CreateMockReceiptHeader(PurchaseReceiptHeader2, Vendor."No."); - CreateMockReceiptLine(PurchaseReceiptLine2, PurchaseReceiptHeader2, Item2."No.", 15, PurchaseLine2); - - // [WHEN] SuggestReceiptsForMatchedOrderLines is called - EDocPOMatching.SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader); - - // [THEN] Each E-Document line is matched to its corresponding receipt line - Assert.IsTrue(EDocPOMatching.IsReceiptLineMatchedToEDocumentLine(PurchaseReceiptLine1, EDocumentPurchaseLine1), 'Expected first receipt line to be matched to first E-Document line'); - Assert.IsTrue(EDocPOMatching.IsReceiptLineMatchedToEDocumentLine(PurchaseReceiptLine2, EDocumentPurchaseLine2), 'Expected second receipt line to be matched to second E-Document line'); - end; - [Test] procedure TransferPOMatchesFromEDocumentToInvoiceTransfersReceiptMatchAndRemovesEDocumentMatches() var