Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ codeunit 6117 "E-Doc. Create Purchase Invoice" implements IEDocumentFinishDraft,
IEDocumentFinishPurchaseDraft: Interface IEDocumentCreatePurchaseInvoice;
YourMatchedLinesAreNotValidErr: Label 'The purchase invoice cannot be created because one or more of its matched lines are not valid matches. Review if your configuration allows for receiving at invoice.';
SomeLinesNotYetReceivedErr: Label 'Some of the matched purchase order lines have not yet been received, you need to either receive the lines or remove the matches.';
MissingInformationForMatchErr: Label 'Some of the draft lines that were matched to purchase order lines are missing unit of measure information. Please specify the unit of measure for those lines and try again.';
begin
EDocumentPurchaseHeader.GetFromEDocument(EDocument);

Expand All @@ -50,9 +51,12 @@ codeunit 6117 "E-Doc. Create Purchase Invoice" implements IEDocumentFinishDraft,

EDocPOMatching.SuggestReceiptsForMatchedOrderLines(EDocumentPurchaseHeader);
EDocPOMatching.CalculatePOMatchWarnings(EDocumentPurchaseHeader, TempPOMatchWarnings);
TempPOMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::NotYetReceived);
TempPOMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::ExceedsInvoiceableQty);
if not TempPOMatchWarnings.IsEmpty() then
Error(SomeLinesNotYetReceivedErr);
TempPOMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::MissingInformationForMatch);
if not TempPOMatchWarnings.IsEmpty() then
Error(MissingInformationForMatchErr);
Comment on lines +54 to +59
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The newly added MissingInformationForMatch finalization check (lines 57-59) blocks invoice creation when draft lines are missing unit of measure information. While the warning calculation itself is tested in EDocPOMatchingUnitTests, there's no test verifying that finalization is actually blocked when this warning is present. Consider adding a test that sets up a draft with a line missing UoM, matches it to a PO line, and verifies that ApplyDraftToBC raises the MissingInformationForMatchErr error. The existing ExceedsInvoiceableQty check (lines 54-56) similarly lacks a finalization-level test.

Copilot uses AI. Check for mistakes.

IEDocumentFinishPurchaseDraft := EDocImportParameters."Processing Customizations";
if EDocImportParameters."Existing Doc. RecordId" <> EmptyRecordId then begin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ page 6183 "E-Doc. Purchase Draft Subform"
Visible = HasEDocumentOrderMatchWarnings;
StyleExpr = MatchWarningsStyleExpr;
ToolTip = 'Specifies any warnings related to matching this line to a purchase order line.';

trigger OnDrillDown()
begin
ShowMatchWarningDetails();
end;
}
field("Line Type"; Rec."[BC] Purchase Line Type")
{
Expand Down Expand Up @@ -348,11 +353,6 @@ page 6183 "E-Doc. Purchase Draft Subform"
end;

trigger OnAfterGetRecord()
var
MissingInfoLbl: Label 'Missing information for match';
NotYetReceivedLbl: Label 'Not yet received';
QuantityMismatchLbl: Label 'Quantity mismatch';
NoWarningsLbl: Label 'No warnings';
begin
if EDocumentPurchaseLine.Get(Rec."E-Document Entry No.", Rec."Line No.") then;
AdditionalColumns := Rec.AdditionalColumnsDisplayText();
Expand All @@ -361,21 +361,7 @@ page 6183 "E-Doc. Purchase Draft Subform"
IsLineMatchedToOrderLine := EDocPOMatching.IsEDocumentLineMatchedToAnyPOLine(EDocumentPurchaseLine);
IsLineMatchedToReceiptLine := EDocPOMatching.IsEDocumentLineMatchedToAnyReceiptLine(EDocumentPurchaseLine);
OrderMatchedCaption := IsLineMatchedToOrderLine ? GetSummaryOfMatchedOrders() : '';
MatchWarningsStyleExpr := 'None';
EDocumentPOMatchWarnings.SetRange("E-Doc. Purchase Line SystemId", Rec.SystemId);
if EDocumentPOMatchWarnings.FindFirst() then begin
case EDocumentPOMatchWarnings."Warning Type" of
Enum::"E-Doc PO Match Warning"::MissingInformationForMatch:
MatchWarningsCaption := MissingInfoLbl;
Enum::"E-Doc PO Match Warning"::NotYetReceived:
MatchWarningsCaption := NotYetReceivedLbl;
Enum::"E-Doc PO Match Warning"::QuantityMismatch:
MatchWarningsCaption := QuantityMismatchLbl;
end;
MatchWarningsStyleExpr := 'Ambiguous';
end
else
MatchWarningsCaption := NoWarningsLbl;
UpdateMatchWarnings();
end;

internal procedure SetEDocumentPurchaseHeader(EDocPurchHeader: Record "E-Document Purchase Header")
Expand Down Expand Up @@ -498,4 +484,85 @@ page 6183 "E-Doc. Purchase Draft Subform"
exit(StrSubstNo(MatchedToSingleOrderMultipleLinesLbl, MatchedPO));
end;

local procedure UpdateMatchWarnings()
var
MissingInfoLbl: Label 'Unit of measure information is missing';
ExceedsInvoiceableQtyLbl: Label 'Exceeds quantity received';
ExceedsRemainingToInvoiceLbl: Label 'Exceeds remaining to invoice';
OverReceiptLbl: Label 'Over-receipt';
NoWarningsLbl: Label 'No warnings';
MultipleWarningsLbl: Label 'Multiple warnings';
MostSevereStyle: Text;
SeverityLevel: Integer;
CurrentSeverity: Integer;
begin
MatchWarningsCaption := NoWarningsLbl;
MatchWarningsStyleExpr := 'None';

EDocumentPOMatchWarnings.SetRange("E-Doc. Purchase Line SystemId", Rec.SystemId);

// Severity: Unfavorable (critical) > Ambiguous (warning) > Subordinate (info)
SeverityLevel := 0;
if EDocumentPOMatchWarnings.FindSet() then
repeat
case EDocumentPOMatchWarnings."Warning Type" of
Enum::"E-Doc PO Match Warning"::ExceedsInvoiceableQty:
begin
CurrentSeverity := 3;
MatchWarningsCaption := ExceedsInvoiceableQtyLbl;
MostSevereStyle := 'Unfavorable';
end;
Enum::"E-Doc PO Match Warning"::MissingInformationForMatch:
begin
CurrentSeverity := 3;
MatchWarningsCaption := MissingInfoLbl;
MostSevereStyle := 'Unfavorable';
end;
Enum::"E-Doc PO Match Warning"::ExceedsRemainingToInvoice:
begin
CurrentSeverity := 2;
MatchWarningsCaption := ExceedsRemainingToInvoiceLbl;
MostSevereStyle := 'Ambiguous';
end;
Enum::"E-Doc PO Match Warning"::OverReceipt:
begin
CurrentSeverity := 1;
MatchWarningsCaption := OverReceiptLbl;
MostSevereStyle := 'Subordinate';
end;
end;
if CurrentSeverity > SeverityLevel then begin
SeverityLevel := CurrentSeverity;
MatchWarningsStyleExpr := MostSevereStyle;
end;
until EDocumentPOMatchWarnings.Next() = 0;

if EDocumentPOMatchWarnings.Count() > 1 then
MatchWarningsCaption := MultipleWarningsLbl;
end;

local procedure ShowMatchWarningDetails()
var
WarningDetails: TextBuilder;
MissingInfoDetailLbl: Label 'Quantity information for this line is missing to complete the match. Verify that the draft line has a unit of measure assigned for this item.';
begin
EDocumentPOMatchWarnings.SetRange("E-Doc. Purchase Line SystemId", Rec.SystemId);
if not EDocumentPOMatchWarnings.FindSet() then
exit;

repeat
case EDocumentPOMatchWarnings."Warning Type" of
Enum::"E-Doc PO Match Warning"::MissingInformationForMatch:
WarningDetails.AppendLine('• ' + MissingInfoDetailLbl);
Enum::"E-Doc PO Match Warning"::ExceedsInvoiceableQty,
Enum::"E-Doc PO Match Warning"::ExceedsRemainingToInvoice,
Enum::"E-Doc PO Match Warning"::OverReceipt:
WarningDetails.AppendLine('• ' + EDocumentPOMatchWarnings."Warning Message");
end;
until EDocumentPOMatchWarnings.Next() = 0;

if WarningDetails.Length() > 0 then
Message(WarningDetails.ToText());
end;

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,13 @@ enum 6111 "E-Doc PO Match Warning"
value(2; MissingInformationForMatch)
{
}
value(3; ExceedsInvoiceableQty)
{
}
value(4; ExceedsRemainingToInvoice)
{
}
value(5; OverReceipt)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ table 6115 "E-Doc PO Match Warning"
Caption = 'Warning Type';
Editable = false;
}
field(3; "Warning Message"; Text[250])
{
DataClassification = SystemMetadata;
Caption = 'Warning Message';
Editable = false;
}
}
keys
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,10 @@ codeunit 6196 "E-Doc. PO Matching"
TempPurchaseLine: Record "Purchase Line" temporary;
EDocLineQuantity: Decimal;
PurchaseLinesQuantity, PurchaseLinesQuantityInvoiced, PurchaseLinesQuantityReceived : Decimal;
RemainingToInvoice, InvoiceableQty : Decimal;
ExceedsInvoiceableQtyLbl: Label 'Invoice quantity (%1) exceeds what can be invoiced according to what has been received (%2) by %3. The order line has to be received before invoicing.', Comment = '%1 = Invoice qty, %2 = Invoiceable qty, %3 = Difference';
ExceedsRemainingToInvoiceLbl: Label 'Invoice quantity (%1) exceeds what is missing to invoice from the order (%2) by %3.', Comment = '%1 = Invoice qty, %2 = Remaining to invoice, %3 = Difference';
OverReceiptLbl: Label 'Invoice will close out order but there is an over-receipt of %1 units.', Comment = '%1 = Over-receipt quantity';
begin
LoadPOLinesMatchedToEDocumentLine(EDocumentPurchaseLine, TempPurchaseLine);
PurchaseLinesQuantityInvoiced := 0;
Expand All @@ -232,17 +236,37 @@ codeunit 6196 "E-Doc. PO Matching"
POMatchWarnings.Insert();
exit;
end;
if EDocLineQuantity <> PurchaseLinesQuantity - PurchaseLinesQuantityInvoiced then begin
POMatchWarnings."E-Doc. Purchase Line SystemId" := EDocumentPurchaseLine.SystemId;
POMatchWarnings."Warning Type" := "E-Doc PO Match Warning"::QuantityMismatch;
POMatchWarnings.Insert();
end;
if (EDocLineQuantity + PurchaseLinesQuantityInvoiced) > PurchaseLinesQuantityReceived then

// I = Invoice quantity (from the e-document line)
// R = Remaining to invoice on the PO (Ordered - Previously Invoiced)
// J = Invoiceable quantity (Received - Previously Invoiced)
RemainingToInvoice := PurchaseLinesQuantity - PurchaseLinesQuantityInvoiced;
InvoiceableQty := PurchaseLinesQuantityReceived - PurchaseLinesQuantityInvoiced;

// I > J: Invoice exceeds what has been received and not yet invoiced
if EDocLineQuantity > InvoiceableQty then
if ShouldWarnIfNotYetReceived(EDocumentPurchaseLine.GetBCVendor()."No.") then begin
POMatchWarnings."E-Doc. Purchase Line SystemId" := EDocumentPurchaseLine.SystemId;
POMatchWarnings."Warning Type" := "E-Doc PO Match Warning"::NotYetReceived;
POMatchWarnings."Warning Type" := "E-Doc PO Match Warning"::ExceedsInvoiceableQty;
POMatchWarnings."Warning Message" := CopyStr(StrSubstNo(ExceedsInvoiceableQtyLbl, EDocLineQuantity, InvoiceableQty, EDocLineQuantity - InvoiceableQty), 1, MaxStrLen(POMatchWarnings."Warning Message"));
POMatchWarnings.Insert();
end;

// I > R: Invoice exceeds what remains on the order
if EDocLineQuantity > RemainingToInvoice then begin
POMatchWarnings."E-Doc. Purchase Line SystemId" := EDocumentPurchaseLine.SystemId;
POMatchWarnings."Warning Type" := "E-Doc PO Match Warning"::ExceedsRemainingToInvoice;
POMatchWarnings."Warning Message" := CopyStr(StrSubstNo(ExceedsRemainingToInvoiceLbl, EDocLineQuantity, RemainingToInvoice, EDocLineQuantity - RemainingToInvoice), 1, MaxStrLen(POMatchWarnings."Warning Message"));
POMatchWarnings.Insert();
end;

// I = R and I < J: Order will be closed but there is an over-receipt
if (EDocLineQuantity = RemainingToInvoice) and (EDocLineQuantity < InvoiceableQty) then begin
POMatchWarnings."E-Doc. Purchase Line SystemId" := EDocumentPurchaseLine.SystemId;
POMatchWarnings."Warning Type" := "E-Doc PO Match Warning"::OverReceipt;
POMatchWarnings."Warning Message" := CopyStr(StrSubstNo(OverReceiptLbl, InvoiceableQty - RemainingToInvoice), 1, MaxStrLen(POMatchWarnings."Warning Message"));
POMatchWarnings.Insert();
end;
end;

/// <summary>
Expand Down Expand Up @@ -475,7 +499,7 @@ codeunit 6196 "E-Doc. PO Matching"
EDocumentPurchaseLine."[BC] Unit of Measure" := MatchedUnitOfMeasure;
EDocumentPurchaseLine.Modify();
AppendPOMatchWarnings(EDocumentPurchaseLine, TempMatchWarnings);
TempMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::NotYetReceived);
TempMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::ExceedsInvoiceableQty);
if (not TempMatchWarnings.IsEmpty) and (not CanMatchInvoiceLineToPOLineWithoutReceipt(EDocumentPurchaseLine, PurchaseLine)) then
Error(NotYetReceivedErr);
end;
Expand Down Expand Up @@ -763,8 +787,8 @@ codeunit 6196 "E-Doc. PO Matching"
TempPOMatchWarnings: Record "E-Doc PO Match Warning" temporary;
begin
CalculatePOMatchWarnings(EDocumentPurchaseHeader, TempPOMatchWarnings);
TempPOMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::NotYetReceived);
// For each line that has a Not Yet Received warning, we check if it can be matched without receipt
TempPOMatchWarnings.SetRange("Warning Type", "E-Doc PO Match Warning"::ExceedsInvoiceableQty);
// For each line that exceeds invoiceable qty, we check if it can be matched without receipt
if TempPOMatchWarnings.FindSet() then
repeat
EDocumentPurchaseLine.GetBySystemId(TempPOMatchWarnings."E-Doc. Purchase Line SystemId");
Expand Down
Loading
Loading