[Subcontracting] Block Get Order/Receipt Lines and item charges on undone subcontracting receipts#8704
Conversation
…done subcontracting receipts Fixes ADO bugs 632785 and 637503. 632785 - subcontracting lines must not be invoiced through a separate document: - Exclude subcontracting receipt lines (Prod. Order No. set) from Get Receipt Lines and block copying them, in SubcPurchPostExt (Purch.-Get Receipt subscribers). - Exclude subcontracting purchase order lines from Get Order Lines, via the new Matched Order Line Mgmt. filter event. 637503 - item charges against undone subcontracting receipts create orphaned capacity cost: - Block assigning an item charge to an undone (Correction) subcontracting receipt line in SubcItemChargeAssPurchExt. - Block posting an item charge assigned to an undone subcontracting receipt line in SubcPurchPostExt. Tests: lightweight mock-based tests in SubcSubcontractingTest covering all three blocks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| ItemChargeAssignmentPurch2.SetRange("Document Line No.", ItemChargeAssignmentPurch."Document Line No."); | ||
| ItemChargeAssignmentPurch2.SetRange("Applies-to Doc. Type", "Purchase Applies-to Document Type"::Receipt); | ||
| repeat | ||
| if (FromPurchRcptLine."Prod. Order No." <> '') and FromPurchRcptLine.Correction then |
There was a problem hiding this comment.
Wrong identifier field for subcontracting check
The undone-receipt guard uses "Prod. Order No." (the standard BC field) to identify a subcontracting line, but the event handler above (line 30) uses "Subc. Prod. Order No." (the extension field) as the definitive subcontracting identifier. A real subcontracting receipt line may have "Subc. Prod. Order No." <> '' while "Prod. Order No." = '', which would allow assigning item charges to an undone line without raising an error.
Recommendation:
- Replace
FromPurchRcptLine."Prod. Order No." <> ''withFromPurchRcptLine."Subc. Prod. Order No." <> ''to be consistent with the rest of the handler and correctly identify subcontracting lines.
| if (FromPurchRcptLine."Prod. Order No." <> '') and FromPurchRcptLine.Correction then | |
| if (FromPurchRcptLine."Subc. Prod. Order No." <> '') and FromPurchRcptLine.Correction then | |
| Error(AssignToUndoneRcptErr, FromPurchRcptLine."Document No.", FromPurchRcptLine."Line No."); |
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
| PurchRcptLine."Document No." := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(PurchRcptLine."Document No.")); | ||
| PurchRcptLine."Line No." := 10000; | ||
| PurchRcptLine.Type := PurchRcptLine.Type::Item; | ||
| PurchRcptLine."No." := Item."No."; |
There was a problem hiding this comment.
Mock missing "Subc. Prod. Order No." — test never reaches new guard
MockSubcontractingPurchRcptLine sets "Prod. Order No." but not "Subc. Prod. Order No.". The event handler OnBeforeCreateRcptChargeAssgnt exits early at if FromPurchRcptLine."Subc. Prod. Order No." = '' then exit (line 30 of the production codeunit), so CreateRcptChargeAssgnt is never called and AssignToUndoneRcptErr is never raised. The asserterror in AssignItemChargeToUndoneSubcontractingReceiptIsBlocked will therefore fail with "there was no error".
Recommendation:
- Add
PurchRcptLine."Subc. Prod. Order No." := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(PurchRcptLine."Subc. Prod. Order No."));toMockSubcontractingPurchRcptLineso the handler proceeds past the early-exit check and reaches the new undone guard.
| PurchRcptLine."No." := Item."No."; | |
| PurchRcptLine."Prod. Order No." := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(PurchRcptLine."Prod. Order No.")); | |
| PurchRcptLine."Subc. Prod. Order No." := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(PurchRcptLine."Subc. Prod. Order No.")); | |
| PurchRcptLine."Routing No." := CopyStr(LibraryUtility.GenerateGUID(), 1, MaxStrLen(PurchRcptLine."Routing No.")); |
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
| PurchRcptLine.SetRange("Prod. Order No.", ''); | ||
| end; | ||
|
|
||
| [EventSubscriber(ObjectType::Codeunit, Codeunit::"Purch.-Get Receipt", OnCreateInvLinesOnBeforeInsertLineIteration, '', false, false)] |
There was a problem hiding this comment.
Duplicate subscribers may suppress expected error in test
ExcludeSubcontractingLinesOnAfterPurchRcptLineSetFilters adds SetRange("Prod. Order No.", '') to the iteration record, silently filtering out subcontracting lines before the loop runs. If this event fires on the same record instance that CreateInvLines iterates, BlockSubcontractingLinesOnCreateInvLinesOnBeforeInsertLineIteration (which throws GetSubcontractingRcptNotSupportedErr) will never be reached, and GetReceiptLinesBlocksSubcontractingReceiptLine's asserterror would fail because no error is thrown.
Recommendation:
- Verify (via a debug run or base-codeunit inspection) that
OnAfterPurchRcptLineSetFiltersoperates on a different record instance than the one iterated inOnCreateInvLinesOnBeforeInsertLineIteration. If both events touch the same record, remove the filter subscriber and rely solely on the error-throwing subscriber, or adjust the test to assert no lines are returned instead of asserting an error.
👍 useful · ❤️ especially valuable · 👎 wrong - reply with why
Fixes AB#632785 and AB#637503 by blocking subcontracting scenarios that aren't supported and corrupt cost.
632785 - subcontracting lines must not be invoiced through a separate document:
637503 - item charges against undone subcontracting receipts create orphaned capacity cost:
Tests: lightweight mock-based tests in SubcSubcontractingTest covering all three blocks.
Recreated from #8678 on a clean branch off latest main (resolves the folder-rename conflict).