From 46caa46ee74a2e94679f3cd11e976b26657b9ec8 Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah Date: Tue, 12 May 2026 16:21:29 +0200 Subject: [PATCH 1/8] Fix false 'already created' warning when prod order has multiple lines sharing routing/operation (#634238) When a Released Production Order had multiple Prod. Order lines using the same Routing/Operation but different Routing Reference No., creating a Subcontracting Order from the routing of a second line incorrectly raised the 'Purchase order(s) have already been created' warning and, when confirmed, opened the unrelated PO of the first line. Root cause: the existence check in ShowExistingPurchaseOrdersForRoutingLines and the navigation in ShowCreatedPurchaseOrder filtered Purchase Lines by Prod. Order No. + Routing No. + Operation No. but not by Routing Reference No., which is the field that identifies the specific Prod. Order line. Fix: add Routing Reference No. to the existence-check filter, and propagate the current routing line's Routing Reference No. to the single-PO navigation branch via a new RoutingReferenceNo global (mirroring the existing OperationNo pattern). Test: SubcSubcontractingTest.CreateSubcontractingPOForEachProdOrderLineWhenLinesShareRoutingAndOperation --- .../SubcPurchaseOrderCreator.Codeunit.al | 14 ++++ .../SubcProdOrderRtng.PageExt.al | 2 + src/Apps/W1/Subcontracting/Test/app.json | 6 ++ .../Tests/SubcSubcontractingTest.Codeunit.al | 76 +++++++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al index e803792afa..f6af49d279 100644 --- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al +++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al @@ -31,6 +31,7 @@ codeunit 99001557 "Subc. Purchase Order Creator" HasSubManagementSetup: Boolean; HasManufacturingSetup: Boolean; OperationNo: Code[10]; + RoutingReferenceNo: Integer; PurchOrderCreatedTxt: Label '%1 Purchase Order(s) created.\\Do you want to view them?', Comment = '%1 = No of Purchase Order(s) created.'; PurchOrderAlreadyCreatedQst: Label 'Purchase order(s) have already been created.\\Do you want to view them?'; CreationOfSubcontractingOrderIsNotAllowedErr: Label 'You cannot create Subcontracting Order, because the Production Order %1 is not released.', Comment = '%1=Production Order No.'; @@ -193,6 +194,8 @@ codeunit 99001557 "Subc. Purchase Order Creator" PurchaseLine.SetLoadFields(SystemId); if (NoOfCreatedPurchOrder = 1) and (OperationNo <> '') then PurchaseLine.SetRange("Operation No.", OperationNo); + if (NoOfCreatedPurchOrder = 1) and (RoutingReferenceNo <> 0) then + PurchaseLine.SetRange("Routing Reference No.", RoutingReferenceNo); PurchaseLine.FindFirst(); PurchaseHeader.Get(PurchaseLine."Document Type", PurchaseLine."Document No."); PageManagement.PageRun(PurchaseHeader); @@ -210,6 +213,16 @@ codeunit 99001557 "Subc. Purchase Order Creator" Clear(OperationNo); end; + internal procedure SetRoutingReferenceNoForCreatedPurchaseOrder(RoutingReferenceNoToSet: Integer) + begin + RoutingReferenceNo := RoutingReferenceNoToSet; + end; + + internal procedure ClearRoutingReferenceNoForCreatedPurchaseOrder() + begin + Clear(RoutingReferenceNo); + end; + local procedure CheckProdOrderRtngLine(ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ProdOrderLine: Record "Prod. Order Line") var WorkCenter: Record "Work Center"; @@ -249,6 +262,7 @@ codeunit 99001557 "Subc. Purchase Order Creator" PurchaseLine.SetRange(Type, "Purchase Line Type"::Item); PurchaseLine.SetRange("Prod. Order No.", ProdOrderRoutingLine."Prod. Order No."); PurchaseLine.SetRange("Routing No.", ProdOrderRoutingLine."Routing No."); + PurchaseLine.SetRange("Routing Reference No.", ProdOrderRoutingLine."Routing Reference No."); PurchaseLine.SetRange("Operation No.", ProdOrderRoutingLine."Operation No."); if not PurchaseLine.IsEmpty() then ExistingPOFound := true; diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al index f3ead2e764..b1d038042b 100644 --- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al +++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al @@ -76,6 +76,8 @@ pageextension 99001503 "Subc. Prod. Order Rtng." extends "Prod. Order Routing" if NoOfCreatedPurchOrder = 1 then begin SubcPurchaseOrderCreator.ClearOperationNoForCreatedPurchaseOrder(); SubcPurchaseOrderCreator.SetOperationNoForCreatedPurchaseOrder(Rec."Operation No."); + SubcPurchaseOrderCreator.ClearRoutingReferenceNoForCreatedPurchaseOrder(); + SubcPurchaseOrderCreator.SetRoutingReferenceNoForCreatedPurchaseOrder(Rec."Routing Reference No."); end; SubcPurchaseOrderCreator.ShowCreatedPurchaseOrder(Rec."Prod. Order No.", NoOfCreatedPurchOrder); end; diff --git a/src/Apps/W1/Subcontracting/Test/app.json b/src/Apps/W1/Subcontracting/Test/app.json index b1a771ed31..806d581145 100644 --- a/src/Apps/W1/Subcontracting/Test/app.json +++ b/src/Apps/W1/Subcontracting/Test/app.json @@ -24,6 +24,12 @@ "name": "Tests-TestLibraries", "publisher": "Microsoft", "version": "29.0.0.0" + }, + { + "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", + "publisher": "Microsoft", + "name": "Library Variable Storage", + "version": "$(app_minimumVersion)" } ], "platform": "29.0.0.0", diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index e873e640d9..86ed430ba0 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -36,6 +36,7 @@ using Microsoft.Sales.Document; using Microsoft.Utilities; using Microsoft.Warehouse.Document; using Microsoft.Warehouse.Structure; +using System.TestLibraries.Utilities; codeunit 139989 "Subc. Subcontracting Test" { @@ -2366,6 +2367,76 @@ codeunit 139989 "Subc. Subcontracting Test" Assert.ExpectedError('Return from Subcontractor has already been created'); end; + [Test] + [HandlerFunctions('DoNotConfirmShowCreatedPurchOrderForSubcontracting')] + procedure CreateSubcontractingPOForEachProdOrderLineWhenLinesShareRoutingAndOperation() + var + Item: Record Item; + ProductionLocation: array[2] of Record Location; + MachineCenter: array[2] of Record "Machine Center"; + ProdOrderLine: Record "Prod. Order Line"; + ProdOrderRoutingLine: Record "Prod. Order Routing Line"; + ProductionOrder: Record "Production Order"; + WorkCenter: array[2] of Record "Work Center"; + ProdOrderRtng: TestPage "Prod. Order Routing"; + I: Integer; + ProdOrderLineNo: array[2] of Integer; + begin + // [SCENARIO 634238] When a Released Production Order has multiple Prod. Order lines sharing the same + // Routing/Operation, creating a Subcontracting Order for the second line must not raise the false + // "Purchase order(s) have already been created" warning, and must create/show its own Purchase Order. + + // [GIVEN] Subcontracting setup with direct transfer (no in-transit route) + Initialize(); + UpdateManufacturingSetupWithSubcontractingLocation(); + Subcontracting := true; + UnitCostCalculation := UnitCostCalculation::Units; + CreateAndCalculateNeededWorkAndMachineCenter(WorkCenter, MachineCenter); + UpdateVendorWithSubcontractingLocationCode(WorkCenter[2]); + CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter); + UpdateProdBomAndRoutingWithRoutingLink(Item, WorkCenter[2]."No."); + + // [GIVEN] One released production order created directly from item + LibraryManufacturing.CreateProductionOrder(ProductionOrder, "Production Order Status"::Released, ProductionOrder."Source Type"::Item, Item."No.", 0); + + // [GIVEN] Add second production order line to the same production order + ProdOrderLine.SetRange(Status, ProdOrderLine.Status::Released); + ProdOrderLine.SetRange("Prod. Order No.", ProductionOrder."No."); + Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected only one production order line initially'); + + // [GIVEN] Create two production order lines for the same item but different locations + LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[1]); + LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[2]); + LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[1].Code, LibraryRandom.RandInt(10) + 2); + ProdOrderLineNo[1] := ProdOrderLine."Line No."; + LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[2].Code, LibraryRandom.RandInt(10) + 2); + ProdOrderLineNo[2] := ProdOrderLine."Line No."; + Assert.AreNotEqual(ProdOrderLineNo[1], ProdOrderLineNo[2], 'Expected two distinct production order lines'); + + // [GIVEN] Refresh the production order to update the routing and component lines + LibraryManufacturing.RefreshProdOrder(ProductionOrder, false, false, true, true, false); + + // [GIVEN] The two production-order lines have transfer components on different locations + for I := 1 to 2 do begin + ProdOrderRoutingLine.Reset(); + ProdOrderRoutingLine.SetRange(Status, ProdOrderRoutingLine.Status::Released); + ProdOrderRoutingLine.SetRange("Prod. Order No.", ProductionOrder."No."); + ProdOrderRoutingLine.SetRange("Routing Reference No.", ProdOrderLineNo[I]); + ProdOrderRoutingLine.SetRange("Work Center No.", WorkCenter[2]."No."); + Assert.RecordCount(ProdOrderRoutingLine, 1); + + ProdOrderRoutingLine.FindFirst(); + + ProdOrderRtng.OpenView(); + ProdOrderRtng.GoToRecord(ProdOrderRoutingLine); + ProdOrderRtng.CreateSubcontracting.Invoke(); + ProdOrderRtng.Close(); + + Assert.AreEqual('1 Purchase Order(s) created.\\Do you want to view them?', LibraryVariableStorage.DequeueText(), 'Expected "created" confirmation for each prod order line, not the false "already created" warning'); + LibraryVariableStorage.AssertEmpty(); + end; + end; + [Test] [HandlerFunctions('ConfirmYesShowSubcontractingPurchOrders,HandlePurchaseOrderPage,HandlePurchaseLinesPage')] procedure ShowExistingPurchOrdersOpensListWhenAlreadyCreated() @@ -2462,6 +2533,7 @@ codeunit 139989 "Subc. Subcontracting Test" [ConfirmHandler] procedure DoNotConfirmShowCreatedPurchOrderForSubcontracting(Question: Text[1024]; var Reply: Boolean) begin + LibraryVariableStorage.Enqueue(Question); Reply := false; end; @@ -2908,6 +2980,9 @@ codeunit 139989 "Subc. Subcontracting Test" SubcontractingMgmtLibrary.Initialize(); UpdateSubMgmtSetupComponentAtLocation("Components at Location"::Purchase); + UpdateSubMgmtSetupWithReqWkshTemplate(); + LibraryVariableStorage.Clear(); + LibraryMfgManagement.Initialize(); if IsInitialized then @@ -3110,6 +3185,7 @@ codeunit 139989 "Subc. Subcontracting Test" LibraryWarehouse: Codeunit "Library - Warehouse"; LibraryMfgManagement: Codeunit "Subc. Library Mfg. Management"; SubcontractingMgmtLibrary: Codeunit "Subc. Management Library"; + LibraryVariableStorage: Codeunit "Library - Variable Storage"; SubSetupLibrary: Codeunit "Subc. Setup Library"; IsInitialized: Boolean; Subcontracting: Boolean; From e9bab7d0f87aa3d89a2a6125ce5bad8c5a8abb96 Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah <41570277+ChethanT@users.noreply.github.com> Date: Tue, 12 May 2026 22:27:30 +0200 Subject: [PATCH 2/8] Update src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index 86ed430ba0..d54b489f26 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2396,7 +2396,7 @@ codeunit 139989 "Subc. Subcontracting Test" CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter); UpdateProdBomAndRoutingWithRoutingLink(Item, WorkCenter[2]."No."); - // [GIVEN] One released production order created directly from item + // [GIVEN] Verify no production order lines exist before manual creation LibraryManufacturing.CreateProductionOrder(ProductionOrder, "Production Order Status"::Released, ProductionOrder."Source Type"::Item, Item."No.", 0); // [GIVEN] Add second production order line to the same production order From 6e89f13b932d18fd9986ce42e9e3575d1963ec34 Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah <41570277+ChethanT@users.noreply.github.com> Date: Tue, 12 May 2026 22:29:05 +0200 Subject: [PATCH 3/8] Update src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index d54b489f26..2327fb33e2 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2399,7 +2399,7 @@ codeunit 139989 "Subc. Subcontracting Test" // [GIVEN] Verify no production order lines exist before manual creation LibraryManufacturing.CreateProductionOrder(ProductionOrder, "Production Order Status"::Released, ProductionOrder."Source Type"::Item, Item."No.", 0); - // [GIVEN] Add second production order line to the same production order +Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to exist at this point'); ProdOrderLine.SetRange(Status, ProdOrderLine.Status::Released); ProdOrderLine.SetRange("Prod. Order No.", ProductionOrder."No."); Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected only one production order line initially'); From 41a1e07e3fc2a98a4970f4956193468d6ea2034f Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah <41570277+ChethanT@users.noreply.github.com> Date: Tue, 12 May 2026 22:47:00 +0200 Subject: [PATCH 4/8] Update src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index 2327fb33e2..ed2e32e0cf 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2402,7 +2402,7 @@ codeunit 139989 "Subc. Subcontracting Test" Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to exist at this point'); ProdOrderLine.SetRange(Status, ProdOrderLine.Status::Released); ProdOrderLine.SetRange("Prod. Order No.", ProductionOrder."No."); - Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected only one production order line initially'); +Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to exist before manually creating them'); // [GIVEN] Create two production order lines for the same item but different locations LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[1]); From 804ffc75f719f596749497bc14cc9f475e6947c3 Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah <41570277+ChethanT@users.noreply.github.com> Date: Wed, 13 May 2026 09:30:43 +0200 Subject: [PATCH 5/8] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Chethan Thopaiah <41570277+ChethanT@users.noreply.github.com> --- src/Apps/W1/Subcontracting/Test/app.json | 2 +- .../Tests/SubcSubcontractingTest.Codeunit.al | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Apps/W1/Subcontracting/Test/app.json b/src/Apps/W1/Subcontracting/Test/app.json index 806d581145..c5c0779f4b 100644 --- a/src/Apps/W1/Subcontracting/Test/app.json +++ b/src/Apps/W1/Subcontracting/Test/app.json @@ -29,7 +29,7 @@ "id": "5095f467-0a01-4b99-99d1-9ff1237d286f", "publisher": "Microsoft", "name": "Library Variable Storage", - "version": "$(app_minimumVersion)" + "version": "29.0.0.0" } ], "platform": "29.0.0.0", diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index ed2e32e0cf..6e923c65cd 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2412,7 +2412,19 @@ Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[2].Code, LibraryRandom.RandInt(10) + 2); ProdOrderLineNo[2] := ProdOrderLine."Line No."; Assert.AreNotEqual(ProdOrderLineNo[1], ProdOrderLineNo[2], 'Expected two distinct production order lines'); + // [WHEN] Creating a Subcontracting Purchase Order for each Prod. Order routing line + for I := 1 to 2 do begin + ProdOrderRoutingLine.Reset(); + // ... routing line filters ... + ProdOrderRtng.OpenView(); + ProdOrderRtng.GoToRecord(ProdOrderRoutingLine); + ProdOrderRtng.CreateSubcontracting.Invoke(); + ProdOrderRtng.Close(); + // [THEN] A new Purchase Order is created (not the false 'already created' warning) + Assert.AreEqual('1 Purchase Order(s) created.\\Do you want to view them?', LibraryVariableStorage.DequeueText(), 'Expected "created" confirmation for each prod order line'); + LibraryVariableStorage.AssertEmpty(); + end; // [GIVEN] Refresh the production order to update the routing and component lines LibraryManufacturing.RefreshProdOrder(ProductionOrder, false, false, true, true, false); From 7c75a81f12a6f47ac04b4d539cbea0a01bd8be8b Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah Date: Wed, 13 May 2026 15:44:18 +0200 Subject: [PATCH 6/8] Address review feedback: fix analogous filter + add navigation test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SubcProdOrderRtng.PageExt.al: add "Routing Reference No." filter to the NoOfCreatedPurchOrder = 0 existence-check branch — same root cause as the codeunit fix; without it the "No subcontracting order was created" message could be wrongly suppressed when a sibling Prod. Order line already has an unrelated PO. - SubcSubcontractingTest.Codeunit.al: revert garbled bot suggestions in CreateSubcontractingPOForEachProdOrderLineWhenLinesShareRoutingAndOperation (broken indentation, duplicated WHEN block with a placeholder comment in place of filters) and add a second test CreateSubcontractingPONavigatesToOwnPOWhenLinesShareRoutingAndOperation that confirms "view them" and asserts the opened PO is the one tied to the invoked routing line's Routing Reference No. — exercising the single-PO navigation branch that consumes the new RoutingReferenceNo global. Drops the now-redundant UpdateSubMgmtSetupWithReqWkshTemplate call (already in Initialize). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../SubcProdOrderRtng.PageExt.al | 1 + .../Tests/SubcSubcontractingTest.Codeunit.al | 91 ++++++++++++++++--- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al index b1d038042b..a3930637b4 100644 --- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al +++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcProdOrderRtng.PageExt.al @@ -69,6 +69,7 @@ pageextension 99001503 "Subc. Prod. Order Rtng." extends "Prod. Order Routing" PurchaseLine.SetRange(Type, PurchaseLine.Type::Item); PurchaseLine.SetRange("Prod. Order No.", Rec."Prod. Order No."); PurchaseLine.SetRange("Routing No.", Rec."Routing No."); + PurchaseLine.SetRange("Routing Reference No.", Rec."Routing Reference No."); PurchaseLine.SetRange("Operation No.", Rec."Operation No."); if PurchaseLine.IsEmpty() then Message(NoPurchOrderCreatedMsg, ProdOrderRoutingLine."Prod. Order No.") diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index 6e923c65cd..3548665e61 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2396,15 +2396,15 @@ codeunit 139989 "Subc. Subcontracting Test" CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter); UpdateProdBomAndRoutingWithRoutingLink(Item, WorkCenter[2]."No."); - // [GIVEN] Verify no production order lines exist before manual creation + // [GIVEN] One released production order created directly from item LibraryManufacturing.CreateProductionOrder(ProductionOrder, "Production Order Status"::Released, ProductionOrder."Source Type"::Item, Item."No.", 0); -Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to exist at this point'); + // [GIVEN] No production order lines exist yet for this order ProdOrderLine.SetRange(Status, ProdOrderLine.Status::Released); ProdOrderLine.SetRange("Prod. Order No.", ProductionOrder."No."); -Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to exist before manually creating them'); + Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to exist before manually creating them'); - // [GIVEN] Create two production order lines for the same item but different locations + // [GIVEN] Two production order lines on the same production order, on different locations LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[1]); LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[2]); LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[1].Code, LibraryRandom.RandInt(10) + 2); @@ -2412,31 +2412,80 @@ Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[2].Code, LibraryRandom.RandInt(10) + 2); ProdOrderLineNo[2] := ProdOrderLine."Line No."; Assert.AreNotEqual(ProdOrderLineNo[1], ProdOrderLineNo[2], 'Expected two distinct production order lines'); - // [WHEN] Creating a Subcontracting Purchase Order for each Prod. Order routing line + + // [GIVEN] Refresh the production order to update the routing and component lines + LibraryManufacturing.RefreshProdOrder(ProductionOrder, false, false, true, true, false); + + // [GIVEN] The two production-order lines have transfer components on different locations for I := 1 to 2 do begin ProdOrderRoutingLine.Reset(); - // ... routing line filters ... + ProdOrderRoutingLine.SetRange(Status, ProdOrderRoutingLine.Status::Released); + ProdOrderRoutingLine.SetRange("Prod. Order No.", ProductionOrder."No."); + ProdOrderRoutingLine.SetRange("Routing Reference No.", ProdOrderLineNo[I]); + ProdOrderRoutingLine.SetRange("Work Center No.", WorkCenter[2]."No."); + Assert.RecordCount(ProdOrderRoutingLine, 1); + + ProdOrderRoutingLine.FindFirst(); + ProdOrderRtng.OpenView(); ProdOrderRtng.GoToRecord(ProdOrderRoutingLine); ProdOrderRtng.CreateSubcontracting.Invoke(); ProdOrderRtng.Close(); - // [THEN] A new Purchase Order is created (not the false 'already created' warning) - Assert.AreEqual('1 Purchase Order(s) created.\\Do you want to view them?', LibraryVariableStorage.DequeueText(), 'Expected "created" confirmation for each prod order line'); + Assert.AreEqual('1 Purchase Order(s) created.\\Do you want to view them?', LibraryVariableStorage.DequeueText(), 'Expected "created" confirmation for each prod order line, not the false "already created" warning'); LibraryVariableStorage.AssertEmpty(); end; - // [GIVEN] Refresh the production order to update the routing and component lines + end; + + [Test] + [HandlerFunctions('ConfirmYesShowSubcontractingPurchOrders,CapturePurchaseOrderPageNo')] + procedure CreateSubcontractingPONavigatesToOwnPOWhenLinesShareRoutingAndOperation() + var + Item: Record Item; + ProductionLocation: array[2] of Record Location; + MachineCenter: array[2] of Record "Machine Center"; + ProdOrderLine: Record "Prod. Order Line"; + ProdOrderRoutingLine: Record "Prod. Order Routing Line"; + ProductionOrder: Record "Production Order"; + PurchaseLine: Record "Purchase Line"; + WorkCenter: array[2] of Record "Work Center"; + ProdOrderRtng: TestPage "Prod. Order Routing"; + I: Integer; + ProdOrderLineNo: array[2] of Integer; + OpenedPurchaseOrderNo: Code[20]; + begin + // [SCENARIO 634238] When a Released Production Order has multiple Prod. Order lines sharing routing/operation, + // confirming "view them" on the just-created Subcontracting Order must open the PO tied to the invoked + // routing line, not the unrelated PO of a sibling line. + + // [GIVEN] Subcontracting setup with two prod order lines sharing routing/operation but different Routing Reference No. + Initialize(); + UpdateManufacturingSetupWithSubcontractingLocation(); + Subcontracting := true; + UnitCostCalculation := UnitCostCalculation::Units; + CreateAndCalculateNeededWorkAndMachineCenter(WorkCenter, MachineCenter); + UpdateVendorWithSubcontractingLocationCode(WorkCenter[2]); + CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter); + UpdateProdBomAndRoutingWithRoutingLink(Item, WorkCenter[2]."No."); + + LibraryManufacturing.CreateProductionOrder(ProductionOrder, "Production Order Status"::Released, ProductionOrder."Source Type"::Item, Item."No.", 0); + + LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[1]); + LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation[2]); + LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[1].Code, LibraryRandom.RandInt(10) + 2); + ProdOrderLineNo[1] := ProdOrderLine."Line No."; + LibraryManufacturing.CreateProdOrderLine(ProdOrderLine, ProductionOrder.Status, ProductionOrder."No.", Item."No.", '', ProductionLocation[2].Code, LibraryRandom.RandInt(10) + 2); + ProdOrderLineNo[2] := ProdOrderLine."Line No."; + LibraryManufacturing.RefreshProdOrder(ProductionOrder, false, false, true, true, false); - // [GIVEN] The two production-order lines have transfer components on different locations + // [WHEN] Creating a Subcontracting Order from each routing line and confirming "view them" for I := 1 to 2 do begin ProdOrderRoutingLine.Reset(); ProdOrderRoutingLine.SetRange(Status, ProdOrderRoutingLine.Status::Released); ProdOrderRoutingLine.SetRange("Prod. Order No.", ProductionOrder."No."); ProdOrderRoutingLine.SetRange("Routing Reference No.", ProdOrderLineNo[I]); ProdOrderRoutingLine.SetRange("Work Center No.", WorkCenter[2]."No."); - Assert.RecordCount(ProdOrderRoutingLine, 1); - ProdOrderRoutingLine.FindFirst(); ProdOrderRtng.OpenView(); @@ -2444,7 +2493,15 @@ Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to ProdOrderRtng.CreateSubcontracting.Invoke(); ProdOrderRtng.Close(); - Assert.AreEqual('1 Purchase Order(s) created.\\Do you want to view them?', LibraryVariableStorage.DequeueText(), 'Expected "created" confirmation for each prod order line, not the false "already created" warning'); + // [THEN] The page handler opens the Purchase Order whose line carries this routing line's Routing Reference No. + OpenedPurchaseOrderNo := CopyStr(LibraryVariableStorage.DequeueText(), 1, MaxStrLen(OpenedPurchaseOrderNo)); + PurchaseLine.Reset(); + PurchaseLine.SetRange("Document Type", PurchaseLine."Document Type"::Order); + PurchaseLine.SetRange("Document No.", OpenedPurchaseOrderNo); + PurchaseLine.SetRange(Type, PurchaseLine.Type::Item); + PurchaseLine.SetRange("Prod. Order No.", ProductionOrder."No."); + PurchaseLine.SetRange("Routing Reference No.", ProdOrderLineNo[I]); + Assert.IsFalse(PurchaseLine.IsEmpty(), StrSubstNo('Opened Purchase Order %1 should contain a line tied to Routing Reference No. %2', OpenedPurchaseOrderNo, ProdOrderLineNo[I])); LibraryVariableStorage.AssertEmpty(); end; end; @@ -2469,7 +2526,6 @@ Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter); CreateAndRefreshProductionOrder( ProductionOrder, "Production Order Status"::Released, ProductionOrder."Source Type"::Item, Item."No.", LibraryRandom.RandInt(10) + 5); - UpdateSubMgmtSetupWithReqWkshTemplate(); // [WHEN] Create Subcontracting Order from the routing line for the first time PurchaseOrderPageOpened := false; @@ -2514,6 +2570,13 @@ Assert.AreEqual(0, ProdOrderLine.Count(), 'Expected no production order lines to PurchaseOrderPage.Close(); end; + [PageHandler] + procedure CapturePurchaseOrderPageNo(var PurchaseOrderPage: TestPage "Purchase Order") + begin + LibraryVariableStorage.Enqueue(PurchaseOrderPage."No.".Value); + PurchaseOrderPage.Close(); + end; + [PageHandler] procedure HandlePurchaseLinesPage(var PurchaseLinesPage: TestPage "Purchase Lines") begin From 069c2762098de1001970750ef709a1e4e61d7d6f Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah Date: Wed, 13 May 2026 23:06:08 +0200 Subject: [PATCH 7/8] minor fixes --- .../Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al | 2 +- .../src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al index 271412ea4b..24884d92f5 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al @@ -472,7 +472,7 @@ codeunit 139991 "Subc. Purch. Subcont. Test" ProductionOrder."Source Type"::Item, FinishedItem."No.", Qty, HomeLocation.Code); // [GIVEN] Requisition worksheet template for subcontracting - LibraryMfgManagement.CreateLaborReqWkshTemplateAndNameAndUpdateSetup(); + LibraryMfgManagement.CreateSubcontractingReqWkshTemplateAndNameAndUpdateSetup(); // [WHEN] Create subcontracting purchase order from Prod. Order Routing ProdOrderRtngLine.SetRange("Routing No.", RoutingHeader."No."); diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index 9551ce053b..6401ed6626 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2616,7 +2616,7 @@ codeunit 139989 "Subc. Subcontracting Test" PurchaseLine.SetRange(Type, PurchaseLine.Type::Item); PurchaseLine.SetRange("Prod. Order No.", ProductionOrder."No."); PurchaseLine.SetRange("Routing Reference No.", ProdOrderLineNo[I]); - Assert.IsFalse(PurchaseLine.IsEmpty(), StrSubstNo('Opened Purchase Order %1 should contain a line tied to Routing Reference No. %2', OpenedPurchaseOrderNo, ProdOrderLineNo[I])); + Assert.IsFalse(PurchaseLine.IsEmpty(), StrSubstNo(PurchOrderRoutingErr, OpenedPurchaseOrderNo, ProdOrderLineNo[I])); LibraryVariableStorage.AssertEmpty(); end; end; @@ -3407,5 +3407,6 @@ codeunit 139989 "Subc. Subcontracting Test" UnitCostCalculation: Option Time,Units; ConfirmDialogCalledCount: Integer; AlreadySpecifiedErr: Label 'You cannot open Tracking Specification because this component is already specified in Transfer Order %1.', Comment = '|%1 = Transfer Order No.'; + PurchOrderRoutingErr: Label 'Purchase Order %1 should contain a line tied to Routing Reference No. %2', Comment = '%1 = Purchase Order No., %2 = Routing Reference No.'; } \ No newline at end of file From 3c1415ca62783ab305ad5fa2f20d39bf5661b1aa Mon Sep 17 00:00:00 2001 From: Chethan Thopaiah <41570277+ChethanT@users.noreply.github.com> Date: Fri, 15 May 2026 15:04:31 +0200 Subject: [PATCH 8/8] test fix --- .../src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al index 26fa4c2358..f8d42a2623 100644 --- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al +++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al @@ -2548,7 +2548,7 @@ codeunit 139989 "Subc. Subcontracting Test" // [GIVEN] Subcontracting setup with direct transfer (no in-transit route) Initialize(); - UpdateManufacturingSetupWithSubcontractingLocation(); + SubcontractingMgmtLibrary.UpdateManufacturingSetupWithSubcontractingLocation(); Subcontracting := true; UnitCostCalculation := UnitCostCalculation::Units; CreateAndCalculateNeededWorkAndMachineCenter(WorkCenter, MachineCenter); @@ -2620,7 +2620,7 @@ codeunit 139989 "Subc. Subcontracting Test" // [GIVEN] Subcontracting setup with two prod order lines sharing routing/operation but different Routing Reference No. Initialize(); - UpdateManufacturingSetupWithSubcontractingLocation(); + SubcontractingMgmtLibrary.UpdateManufacturingSetupWithSubcontractingLocation(); Subcontracting := true; UnitCostCalculation := UnitCostCalculation::Units; CreateAndCalculateNeededWorkAndMachineCenter(WorkCenter, MachineCenter);