From 4799a0d6e5dde6177b242f3c4bcbb392572ddd2a Mon Sep 17 00:00:00 2001 From: Franco111000 Date: Sun, 5 Jul 2026 17:26:28 +0200 Subject: [PATCH] Add missing var modifier to OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry The event passed the open inbound item ledger entry record by value, so filters applied by subscribers were discarded before the FindSet call in CalculatePreciseCostAmounts and the event could not fulfill its purpose. The record is now passed by reference in the W1, RU, and APAC copies of codeunit ItemCostManagement, matching the sibling events in the same procedure. Adds a regression test with a bound subscriber that filters the open inbound entries and verifies the average cost reflects the filter. Fixes #7611 --- .../Costing/ItemCostManagement.Codeunit.al | 2 +- .../CZ/Tests/SCM/SCMAvgCostCalc.Codeunit.al | 60 +++++++++++++++++++ .../Costing/ItemCostManagement.Codeunit.al | 2 +- .../Costing/ItemCostManagement.Codeunit.al | 2 +- .../W1/Tests/SCM/SCMAvgCostCalc.Codeunit.al | 60 +++++++++++++++++++ 5 files changed, 123 insertions(+), 3 deletions(-) diff --git a/src/Layers/APAC/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al b/src/Layers/APAC/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al index 5ab329edd1..61444b2a08 100644 --- a/src/Layers/APAC/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al +++ b/src/Layers/APAC/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al @@ -831,7 +831,7 @@ codeunit 5804 ItemCostManagement end; [IntegrationEvent(false, false)] - local procedure OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry(OpenInbndItemLedgerEntry: Record "Item Ledger Entry"; var Item: Record Item) + local procedure OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry(var OpenInbndItemLedgerEntry: Record "Item Ledger Entry"; var Item: Record Item) begin end; diff --git a/src/Layers/CZ/Tests/SCM/SCMAvgCostCalc.Codeunit.al b/src/Layers/CZ/Tests/SCM/SCMAvgCostCalc.Codeunit.al index 10a88b61ad..354fd45af5 100644 --- a/src/Layers/CZ/Tests/SCM/SCMAvgCostCalc.Codeunit.al +++ b/src/Layers/CZ/Tests/SCM/SCMAvgCostCalc.Codeunit.al @@ -2,6 +2,7 @@ codeunit 137070 "SCM Avg. Cost Calc." { Subtype = Test; TestPermissions = Disabled; + EventSubscriberInstance = Manual; trigger OnRun() begin @@ -22,6 +23,7 @@ codeunit 137070 "SCM Avg. Cost Calc." LibraryUtility: Codeunit "Library - Utility"; LibraryRandom: Codeunit "Library - Random"; IsInitialized: Boolean; + OpenInboundEntryNoFilter: Integer; IncorrectAverageCostErr: Label 'Average Cost is incorrect.'; IncorrectAverageCostACYErr: Label 'Average Cost (ACY) is incorrect.'; @@ -662,6 +664,52 @@ codeunit 137070 "SCM Avg. Cost Calc." Assert.AreNearlyEqual(24.01 / 8.003, AverageCost, LibraryERM.GetUnitAmountRoundingPrecision(), IncorrectAverageCostErr); end; + [Test] + [Scope('OnPrem')] + procedure PreciseAvgCostRespectsSubscriberFilterOnOpenInboundEntries() + var + GeneralLedgerSetup: Record "General Ledger Setup"; + Item: Record Item; + FilteredItemLedgerEntry: Record "Item Ledger Entry"; + PosItemLedgerEntry: Record "Item Ledger Entry"; + NegItemLedgerEntry: Record "Item Ledger Entry"; + ItemCostManagement: Codeunit ItemCostManagement; + SCMAvgCostCalc: Codeunit "SCM Avg. Cost Calc."; + AverageCost: Decimal; + AverageCostACY: Decimal; + begin + // [FEATURE] [Unit Cost] [UT] + // [SCENARIO 7611] A subscriber to OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry can add filters on the open inbound item ledger entries included in the precise cost calculation. + Initialize(); + GeneralLedgerSetup.Get(); + + LibraryInventory.CreateItem(Item); + + // [GIVEN] Open positive item entry "E1". Quantity = 2; Remaining Quantity = 1; Cost Amount = 6.00. + // [GIVEN] Open positive item entry "E2". Quantity = 2; Remaining Quantity = 1; Cost Amount = 10.00 + rounding precision of the local currency. + // [GIVEN] Closed negative item entry "E3". Quantity = -2; Cost Amount = -16.00. "E3" is applied to "E1" and "E2". + // [GIVEN] Sum of Cost Amount for the item is thereby equal to the rounding precision, which triggers the precise cost calculation. + MockItemLedgerEntry(FilteredItemLedgerEntry, Item."No.", 2, 1, 6.0, 0); + MockItemLedgerEntry(PosItemLedgerEntry, Item."No.", 2, 1, 10.0 + GeneralLedgerSetup."Amount Rounding Precision", 0); + MockItemLedgerEntry(NegItemLedgerEntry, Item."No.", -2, 0, -16.0, 0); + MockItemApplicationEntry(NegItemLedgerEntry."Entry No.", FilteredItemLedgerEntry."Entry No.", NegItemLedgerEntry."Entry No.", -1); + MockItemApplicationEntry(NegItemLedgerEntry."Entry No.", PosItemLedgerEntry."Entry No.", NegItemLedgerEntry."Entry No.", -1); + + // [GIVEN] A bound subscriber that filters the open inbound entries down to "E1". + SCMAvgCostCalc.SetOpenInboundEntryNoFilter(FilteredItemLedgerEntry."Entry No."); + BindSubscription(SCMAvgCostCalc); + + // [WHEN] Calculate unit cost of the item. + ItemCostManagement.SetProperties(true, 0); + ItemCostManagement.CalculateAverageCost(Item, AverageCost, AverageCostACY); + UnbindSubscription(SCMAvgCostCalc); + + // [THEN] The precise remaining cost is calculated from "E1" only. + // [THEN] Average Cost = 6.00 / 2 * 1 / 2 = 1.5, that is the unit cost of "E1" multiplied by its remaining quantity and divided by the remaining quantity on inventory. + Assert.AreNearlyEqual( + 6.0 / 2 * 1 / 2, AverageCost, LibraryERM.GetUnitAmountRoundingPrecision(), IncorrectAverageCostErr); + end; + local procedure Initialize() var LibraryERMCountryData: Codeunit "Library - ERM Country Data"; @@ -1068,5 +1116,17 @@ codeunit 137070 "SCM Avg. Cost Calc." begin EnterQuantitytoCreate.OK().Invoke(); end; + + procedure SetOpenInboundEntryNoFilter(EntryNo: Integer) + begin + OpenInboundEntryNoFilter := EntryNo; + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::ItemCostManagement, 'OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry', '', false, false)] + local procedure FilterOpenInboundEntriesOnCalculatePreciseCostAmounts(var OpenInbndItemLedgerEntry: Record "Item Ledger Entry") + begin + if OpenInboundEntryNoFilter <> 0 then + OpenInbndItemLedgerEntry.SetRange("Entry No.", OpenInboundEntryNoFilter); + end; } diff --git a/src/Layers/RU/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al b/src/Layers/RU/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al index e64193bc59..cf4a1d856c 100644 --- a/src/Layers/RU/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al +++ b/src/Layers/RU/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al @@ -786,7 +786,7 @@ codeunit 5804 ItemCostManagement end; [IntegrationEvent(false, false)] - local procedure OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry(OpenInbndItemLedgerEntry: Record "Item Ledger Entry"; var Item: Record Item) + local procedure OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry(var OpenInbndItemLedgerEntry: Record "Item Ledger Entry"; var Item: Record Item) begin end; diff --git a/src/Layers/W1/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al b/src/Layers/W1/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al index bebdeca738..8943e3e85c 100644 --- a/src/Layers/W1/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al +++ b/src/Layers/W1/BaseApp/Inventory/Costing/ItemCostManagement.Codeunit.al @@ -764,7 +764,7 @@ codeunit 5804 ItemCostManagement end; [IntegrationEvent(false, false)] - local procedure OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry(OpenInbndItemLedgerEntry: Record "Item Ledger Entry"; var Item: Record Item) + local procedure OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry(var OpenInbndItemLedgerEntry: Record "Item Ledger Entry"; var Item: Record Item) begin end; diff --git a/src/Layers/W1/Tests/SCM/SCMAvgCostCalc.Codeunit.al b/src/Layers/W1/Tests/SCM/SCMAvgCostCalc.Codeunit.al index 37f0f0b16c..38e55b56ea 100644 --- a/src/Layers/W1/Tests/SCM/SCMAvgCostCalc.Codeunit.al +++ b/src/Layers/W1/Tests/SCM/SCMAvgCostCalc.Codeunit.al @@ -2,6 +2,7 @@ codeunit 137070 "SCM Avg. Cost Calc." { Subtype = Test; TestPermissions = Disabled; + EventSubscriberInstance = Manual; trigger OnRun() begin @@ -22,6 +23,7 @@ codeunit 137070 "SCM Avg. Cost Calc." LibraryUtility: Codeunit "Library - Utility"; LibraryRandom: Codeunit "Library - Random"; IsInitialized: Boolean; + OpenInboundEntryNoFilter: Integer; IncorrectAverageCostErr: Label 'Average Cost is incorrect.'; IncorrectAverageCostACYErr: Label 'Average Cost (ACY) is incorrect.'; @@ -662,6 +664,52 @@ codeunit 137070 "SCM Avg. Cost Calc." Assert.AreNearlyEqual(24.01 / 8.003, AverageCost, LibraryERM.GetUnitAmountRoundingPrecision(), IncorrectAverageCostErr); end; + [Test] + [Scope('OnPrem')] + procedure PreciseAvgCostRespectsSubscriberFilterOnOpenInboundEntries() + var + GeneralLedgerSetup: Record "General Ledger Setup"; + Item: Record Item; + FilteredItemLedgerEntry: Record "Item Ledger Entry"; + PosItemLedgerEntry: Record "Item Ledger Entry"; + NegItemLedgerEntry: Record "Item Ledger Entry"; + ItemCostManagement: Codeunit ItemCostManagement; + SCMAvgCostCalc: Codeunit "SCM Avg. Cost Calc."; + AverageCost: Decimal; + AverageCostACY: Decimal; + begin + // [FEATURE] [Unit Cost] [UT] + // [SCENARIO 7611] A subscriber to OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry can add filters on the open inbound item ledger entries included in the precise cost calculation. + Initialize(); + GeneralLedgerSetup.Get(); + + LibraryInventory.CreateItem(Item); + + // [GIVEN] Open positive item entry "E1". Quantity = 2; Remaining Quantity = 1; Cost Amount = 6.00. + // [GIVEN] Open positive item entry "E2". Quantity = 2; Remaining Quantity = 1; Cost Amount = 10.00 + rounding precision of the local currency. + // [GIVEN] Closed negative item entry "E3". Quantity = -2; Cost Amount = -16.00. "E3" is applied to "E1" and "E2". + // [GIVEN] Sum of Cost Amount for the item is thereby equal to the rounding precision, which triggers the precise cost calculation. + MockItemLedgerEntry(FilteredItemLedgerEntry, Item."No.", 2, 1, 6.0, 0); + MockItemLedgerEntry(PosItemLedgerEntry, Item."No.", 2, 1, 10.0 + GeneralLedgerSetup."Amount Rounding Precision", 0); + MockItemLedgerEntry(NegItemLedgerEntry, Item."No.", -2, 0, -16.0, 0); + MockItemApplicationEntry(NegItemLedgerEntry."Entry No.", FilteredItemLedgerEntry."Entry No.", NegItemLedgerEntry."Entry No.", -1); + MockItemApplicationEntry(NegItemLedgerEntry."Entry No.", PosItemLedgerEntry."Entry No.", NegItemLedgerEntry."Entry No.", -1); + + // [GIVEN] A bound subscriber that filters the open inbound entries down to "E1". + SCMAvgCostCalc.SetOpenInboundEntryNoFilter(FilteredItemLedgerEntry."Entry No."); + BindSubscription(SCMAvgCostCalc); + + // [WHEN] Calculate unit cost of the item. + ItemCostManagement.SetProperties(true, 0); + ItemCostManagement.CalculateAverageCost(Item, AverageCost, AverageCostACY); + UnbindSubscription(SCMAvgCostCalc); + + // [THEN] The precise remaining cost is calculated from "E1" only. + // [THEN] Average Cost = 6.00 / 2 * 1 / 2 = 1.5, that is the unit cost of "E1" multiplied by its remaining quantity and divided by the remaining quantity on inventory. + Assert.AreNearlyEqual( + 6.0 / 2 * 1 / 2, AverageCost, LibraryERM.GetUnitAmountRoundingPrecision(), IncorrectAverageCostErr); + end; + local procedure Initialize() var LibraryERMCountryData: Codeunit "Library - ERM Country Data"; @@ -1067,5 +1115,17 @@ codeunit 137070 "SCM Avg. Cost Calc." begin EnterQuantitytoCreate.OK().Invoke(); end; + + procedure SetOpenInboundEntryNoFilter(EntryNo: Integer) + begin + OpenInboundEntryNoFilter := EntryNo; + end; + + [EventSubscriber(ObjectType::Codeunit, Codeunit::ItemCostManagement, 'OnCalculatePreciseCostAmountsOnAfterFilterOpenInboundItemLedgerEntry', '', false, false)] + local procedure FilterOpenInboundEntriesOnCalculatePreciseCostAmounts(var OpenInbndItemLedgerEntry: Record "Item Ledger Entry") + begin + if OpenInboundEntryNoFilter <> 0 then + OpenInbndItemLedgerEntry.SetRange("Entry No.", OpenInboundEntryNoFilter); + end; }