// ------------------------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. // ------------------------------------------------------------------------------------------------ namespace Microsoft.Inventory.Costing; using Microsoft.Inventory.Item; using Microsoft.Inventory.Ledger; using Microsoft.Inventory.Setup; using System.Text; table 5811 "Post Value Entry to G/L" { Caption = 'Post Value Entry to G/L'; DataClassification = CustomerContent; DrillDownPageId = "Post Value Entries to G/L"; LookupPageId = "Post Value Entries to G/L"; fields { field(1; "Value Entry No."; Integer) { Caption = 'Value Entry No.'; ToolTip = 'Specifies the number of the value entry whose cost is waiting to be posted to the general ledger.'; TableRelation = "Value Entry"; } field(2; "Item No."; Code[20]) { Caption = 'Item No.'; ToolTip = 'Specifies the number of the item that the value entry is for.'; TableRelation = Item; } field(3; "Posting Date"; Date) { Caption = 'Posting Date'; ToolTip = 'Specifies the posting date of the value entry.'; } } keys { key(Key1; "Value Entry No.") { Clustered = true; } key(Key2; "Item No.", "Posting Date") { } key(Key3; "Item No.") { } } fieldgroups { } /// /// Checks whether the value entry referenced by this record has no remaining cost that report "Post Inventory Cost to G/L" can post. /// This is the case when the value entry no longer exists, or when its actual cost (and its expected cost, if expected cost posting to G/L is enabled) /// has been fully posted to the general ledger in both local and additional reporting currency. /// /// True if the record is no longer needed to post inventory cost to the general ledger. internal procedure HasNothingToPostToGL(): Boolean var ValueEntry: Record "Value Entry"; InventorySetup: Record "Inventory Setup"; begin // Read committed data only, so that posted amounts of an uncommitted posting are not taken into account. ValueEntry.ReadIsolation := IsolationLevel::ReadCommitted; ValueEntry.SetLoadFields( "Cost Amount (Actual)", "Cost Posted to G/L", "Cost Amount (Actual) (ACY)", "Cost Posted to G/L (ACY)", "Cost Amount (Expected)", "Expected Cost Posted to G/L", "Cost Amount (Expected) (ACY)", "Exp. Cost Posted to G/L (ACY)"); if not ValueEntry.Get("Value Entry No.") then exit(true); InventorySetup.GetRecordOnce(); exit(IsFullyPostedToGL(ValueEntry, InventorySetup."Expected Cost Posting to G/L")); end; /// /// Checks whether the cost of a value entry has been fully posted to the general ledger, using the same amounts as report "Post Inventory Cost to G/L". /// /// The value entry to check. /// Specifies whether expected cost is posted to the general ledger. /// True if no actual cost, and no expected cost when expected cost posting is enabled, remains to be posted. internal procedure IsFullyPostedToGL(ValueEntry: Record "Value Entry"; ExpectedCostPostingToGL: Boolean) Result: Boolean begin Result := (ValueEntry."Cost Amount (Actual)" = ValueEntry."Cost Posted to G/L") and (ValueEntry."Cost Amount (Actual) (ACY)" = ValueEntry."Cost Posted to G/L (ACY)"); if Result and ExpectedCostPostingToGL then Result := (ValueEntry."Cost Amount (Expected)" = ValueEntry."Expected Cost Posted to G/L") and (ValueEntry."Cost Amount (Expected) (ACY)" = ValueEntry."Exp. Cost Posted to G/L (ACY)"); OnAfterIsFullyPostedToGL(ValueEntry, ExpectedCostPostingToGL, Result); end; [IntegrationEvent(false, false)] local procedure OnAfterIsFullyPostedToGL(ValueEntry: Record "Value Entry"; ExpectedCostPostingToGL: Boolean; var Result: Boolean) begin end; /// /// Builds filters on "Value Entry No." that select exactly the entries in the given list, to delete them by filter instead of using marks. /// /// The list of value entry numbers. The list is not changed. /// The filters, in ascending order of value entry numbers. internal procedure GetValueEntryNoFilters(var TempPostValueEntryToGL: Record "Post Value Entry to G/L" temporary; var ValueEntryNoFilters: List of [Text]) var SelectionFilterManagement: Codeunit SelectionFilterManagement; ValueEntryNoFilter: TextBuilder; FromValueEntryNo: Integer; ToValueEntryNo: Integer; NoOfFilterParameters: Integer; MaxNoOfFilterParameters: Integer; begin // A range in a filter only contains consecutive numbers that are all in the list. Gaps are never bridged, because entry numbers come from // a sequence and an entry in a gap may be committed later by another session. // A single number takes one SQL parameter and a range takes two, so each filter is kept within the maximum number of parameters in a SQL query. Clear(ValueEntryNoFilters); if not TempPostValueEntryToGL.FindSet() then exit; MaxNoOfFilterParameters := SelectionFilterManagement.GetMaximumNumberOfParametersInSQLQuery(); FromValueEntryNo := TempPostValueEntryToGL."Value Entry No."; ToValueEntryNo := FromValueEntryNo; while TempPostValueEntryToGL.Next() <> 0 do if TempPostValueEntryToGL."Value Entry No." = ToValueEntryNo + 1 then ToValueEntryNo := TempPostValueEntryToGL."Value Entry No." else begin AddRangeToValueEntryNoFilter(ValueEntryNoFilters, ValueEntryNoFilter, NoOfFilterParameters, MaxNoOfFilterParameters, FromValueEntryNo, ToValueEntryNo); FromValueEntryNo := TempPostValueEntryToGL."Value Entry No."; ToValueEntryNo := FromValueEntryNo; end; AddRangeToValueEntryNoFilter(ValueEntryNoFilters, ValueEntryNoFilter, NoOfFilterParameters, MaxNoOfFilterParameters, FromValueEntryNo, ToValueEntryNo); ValueEntryNoFilters.Add(ValueEntryNoFilter.ToText()); end; local procedure AddRangeToValueEntryNoFilter(var ValueEntryNoFilters: List of [Text]; var ValueEntryNoFilter: TextBuilder; var NoOfFilterParameters: Integer; MaxNoOfFilterParameters: Integer; FromValueEntryNo: Integer; ToValueEntryNo: Integer) var NoOfRangeParameters: Integer; begin NoOfRangeParameters := 1; if ToValueEntryNo <> FromValueEntryNo then NoOfRangeParameters := 2; if NoOfFilterParameters + NoOfRangeParameters > MaxNoOfFilterParameters then begin ValueEntryNoFilters.Add(ValueEntryNoFilter.ToText()); ValueEntryNoFilter.Clear(); NoOfFilterParameters := 0; end; if ValueEntryNoFilter.Length() > 0 then ValueEntryNoFilter.Append('|'); ValueEntryNoFilter.Append(Format(FromValueEntryNo, 0, 9)); if ToValueEntryNo <> FromValueEntryNo then ValueEntryNoFilter.Append('..' + Format(ToValueEntryNo, 0, 9)); NoOfFilterParameters += NoOfRangeParameters; end; }