diff --git a/src/Business Foundation/App/NoSeries/src/Setup/NoSeries.Page.al b/src/Business Foundation/App/NoSeries/src/Setup/NoSeries.Page.al index 00151c081e..2275b67c24 100644 --- a/src/Business Foundation/App/NoSeries/src/Setup/NoSeries.Page.al +++ b/src/Business Foundation/App/NoSeries/src/Setup/NoSeries.Page.al @@ -238,6 +238,20 @@ page 456 "No. Series" ToolTip = 'View or edit relationships between number series.'; Scope = Repeater; } + action("Where-Used List") + { + ApplicationArea = Basic, Suite; + Caption = 'Where-Used List'; + Image = Track; + ToolTip = 'View setup tables where a number series is used.'; + + trigger OnAction() + var + CalcNoSeriesWhereUsed: Codeunit "Calc. No. Series Where-Used"; + begin + CalcNoSeriesWhereUsed.CheckNoSeriesCode(Rec.Code); + end; + } } } area(Processing) diff --git a/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesCalcWhereUsed.Codeunit.al b/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesCalcWhereUsed.Codeunit.al new file mode 100644 index 0000000000..54d2f85435 --- /dev/null +++ b/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesCalcWhereUsed.Codeunit.al @@ -0,0 +1,205 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Foundation.NoSeries; + +using System.Reflection; +using System.Utilities; + +codeunit 1 "Calc. No. Series Where-Used" +{ + + var + TempNoSeriesWhereUsed: Record "No. Series Where-Used" temporary; + NextEntryNo: Integer; + + procedure ShowSetupForm(NoSeriesWhereUsed: Record "No. Series Where-Used") + var + // TODO: The "Find Record Management" codeunit is located in the W1 BaseApp Utilities + // TODO: We would need to implement the Find Record Management into the System Application + // PageManagement: Codeunit "Page Management"; + RecRef: RecordRef; + RecordRefVariant: Variant; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeShowSetupForm(NoSeriesWhereUsed, IsHandled); + if IsHandled then + exit; + RecRef.Open(NoSeriesWhereUsed."Table ID"); + // TODO: The "Find Record Management" codeunit is located in the W1 BaseApp Utilities + // TODO: We would need to implement the Find Record Management into the System Application + // PageManagement.PageRun(RecRef); + RecordRefVariant := RecRef; + Page.Run(Page::"No. Series Where-Used List", RecordRefVariant); + end; + + procedure CheckNoSeriesCode(NoSeriesCode: Code[20]) + begin + CheckNoSeries(NoSeriesCode); + ShowNoSeriesWhereUsed(); + end; + + local procedure ShowNoSeriesWhereUsed() + begin + OnBeforeShowNoSeriesWhereUsed(TempNoSeriesWhereUsed); + + TempNoSeriesWhereUsed.SetCurrentKey("Table Name"); + Page.RunModal(0, TempNoSeriesWhereUsed); + end; + + procedure CheckNoSeries(NoSeriesCode: Code[20]) + var + NoSeries: Record "No. Series"; + TempTableBuffer: Record "Integer" temporary; + begin + NextEntryNo := 0; + Clear(TempNoSeriesWhereUsed); + TempNoSeriesWhereUsed.DeleteAll(); + NoSeries.Get(NoSeriesCode); + TempNoSeriesWhereUsed."No. Series Code" := NoSeriesCode; + TempNoSeriesWhereUsed."No. Series Description" := NoSeries.Description; + + if FillTableBuffer(TempTableBuffer) then + repeat + CheckTable(NoSeriesCode, TempTableBuffer.Number); + until TempTableBuffer.Next() = 0; + + OnAfterCheckNoSeries(TempNoSeriesWhereUsed, NoSeriesCode); + end; + + local procedure FillTableBuffer(var TableBuffer: Record "Integer"): Boolean + var + NoSeries: Record "No. Series"; + TableRelationsMetadata: Record "Table Relations Metadata"; + begin + TableRelationsMetadata.SetLoadFields("Related Table ID", "Related Field No."); + TableRelationsMetadata.SetRange("Related Table ID", Database::"No. Series"); + TableRelationsMetadata.SetRange("Related Field No.", NoSeries.FieldNo(Code)); + if TableRelationsMetadata.FindSet() then + repeat + if not (TableRelationsMetadata."Table ID" in [Database::"No. Series", Database::"No. Series Relationship"]) then + AddTable(TableBuffer, TableRelationsMetadata."Table ID"); + until TableRelationsMetadata.Next() = 0; + + TableBuffer.Reset(); + + OnAfterFillTableBuffer(TableBuffer); + + exit(TableBuffer.FindSet()); + end; + + procedure AddTable(var TableBuffer: Record "Integer"; TableID: Integer) + begin + if not TableBuffer.Get(TableID) then begin + TableBuffer.Number := TableID; + TableBuffer.Insert(); + end; + end; + + local procedure CheckTable(NoSeriesCode: Code[20]; TableID: Integer) + var + TableRelationsMetadata: Record "Table Relations Metadata"; + Field: Record Field; + RecRef: RecordRef; + begin + RecRef.Open(TableID); + TempNoSeriesWhereUsed.Init(); + TempNoSeriesWhereUsed."Table ID" := TableID; + TempNoSeriesWhereUsed."Table Name" := RecRef.Caption; + + TableRelationsMetadata.SetRange("Table ID", TableID); + TableRelationsMetadata.SetRange("Related Table ID", Database::"No. Series"); + if TableRelationsMetadata.FindSet() then + repeat + Field.Get(TableRelationsMetadata."Table ID", TableRelationsMetadata."Field No."); + if (Field.Class = Field.Class::Normal) and (Field.ObsoleteState <> Field.ObsoleteState::Removed) then + CheckField(RecRef, TableRelationsMetadata, NoSeriesCode); + until TableRelationsMetadata.Next() = 0; + end; + + local procedure CheckField(var RecRef: RecordRef; TableRelationsMetadata: Record "Table Relations Metadata"; GLAccNo: Code[20]) + var + FieldRef: FieldRef; + begin + RecRef.Reset(); + FieldRef := RecRef.Field(TableRelationsMetadata."Field No."); + FieldRef.SetRange(GLAccNo); + SetConditionFilter(RecRef, TableRelationsMetadata); + if RecRef.FindSet() then + repeat + InsertGroupFromRecRef(RecRef, FieldRef.Caption); + until RecRef.Next() = 0; + end; + + local procedure SetConditionFilter(var RecRef: RecordRef; TableRelationsMetadata: Record "Table Relations Metadata") + var + FieldRef: FieldRef; + begin + if TableRelationsMetadata."Condition Field No." <> 0 then begin + FieldRef := RecRef.Field(TableRelationsMetadata."Condition Field No."); + FieldRef.SetFilter(TableRelationsMetadata."Condition Value"); + end; + end; + + local procedure InsertGroupFromRecRef(var RecRef: RecordRef; FieldCaption: Text[80]) + var + FieldRef: FieldRef; + KeyRef: KeyRef; + KeyFieldCount: Integer; + FieldCaptionAndValue: Text; + begin + if NextEntryNo = 0 then + NextEntryNo := TempNoSeriesWhereUsed.GetLastEntryNo() + 1; + + TempNoSeriesWhereUsed."Entry No." := NextEntryNo; + TempNoSeriesWhereUsed."Field Name" := FieldCaption; + TempNoSeriesWhereUsed.Line := ''; + KeyRef := RecRef.KeyIndex(1); + for KeyFieldCount := 1 to KeyRef.FieldCount do begin + FieldRef := KeyRef.FieldIndex(KeyFieldCount); + FieldCaptionAndValue := StrSubstNo('%1=%2', FieldRef.Caption, FieldRef.Value); + if TempNoSeriesWhereUsed.Line = '' then + TempNoSeriesWhereUsed.Line := CopyStr(FieldCaptionAndValue, 1, MaxStrLen(TempNoSeriesWhereUsed.Line)) + else + TempNoSeriesWhereUsed.Line := + CopyStr(TempNoSeriesWhereUsed.Line + ', ' + FieldCaptionAndValue, 1, MaxStrLen(TempNoSeriesWhereUsed.Line)); + + case KeyFieldCount of + 1: + TempNoSeriesWhereUsed."Key 1" := CopyStr(Format(FieldRef.Value), 1, MaxStrLen(TempNoSeriesWhereUsed."Key 1")); + 2: + TempNoSeriesWhereUsed."Key 2" := CopyStr(Format(FieldRef.Value), 1, MaxStrLen(TempNoSeriesWhereUsed."Key 2")); + 3: + TempNoSeriesWhereUsed."Key 3" := CopyStr(Format(FieldRef.Value), 1, MaxStrLen(TempNoSeriesWhereUsed."Key 3")); + 4: + TempNoSeriesWhereUsed."Key 4" := CopyStr(Format(FieldRef.Value), 1, MaxStrLen(TempNoSeriesWhereUsed."Key 4")); + end; + end; + NextEntryNo += 1; + TempNoSeriesWhereUsed.Insert(); + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterCheckNoSeries(var TempNoSeriesWhereUsed: Record "No. Series Where-Used" temporary; NoSeriesCode: Code[20]) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterFillTableBuffer(var TableBuffer: Record "Integer") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeShowNoSeriesWhereUsed(var NoSeriesWhereUsed: Record "No. Series Where-Used") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeShowSetupForm(var NoSeriesWhereUsed: Record "No. Series Where-Used"; IsHandled: Boolean) + begin + end; + +} \ No newline at end of file diff --git a/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesWhereUsed.Table.al b/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesWhereUsed.Table.al new file mode 100644 index 0000000000..235a09cb37 --- /dev/null +++ b/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesWhereUsed.Table.al @@ -0,0 +1,194 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Foundation.NoSeries; + +table 1 "No. Series Where-Used" +{ + Caption = 'No. Series Where-Used'; + LookupPageID = "No. Series Where-Used List"; + TableType = Temporary; + + fields + { + field(1; "Entry No."; Integer) + { + Caption = 'Entry No.'; + } + field(2; "Table ID"; Integer) + { + Caption = 'Table ID'; + } + field(3; "Table Name"; Text[150]) + { + Caption = 'Table Name'; + } + field(5; "Field Name"; Text[150]) + { + Caption = 'Field Name'; + } + field(6; Line; Text[250]) + { + Caption = 'Line'; + } + field(7; "No. Series Code"; Code[20]) + { + Caption = 'No. Series Code'; + } + field(8; "No. Series Description"; Text[100]) + { + Caption = 'No. Series Description'; + } + field(9; "Key 1"; Text[50]) + { + Caption = 'Key 1'; + } + field(10; "Key 2"; Text[50]) + { + Caption = 'Key 2'; + } + field(11; "Key 3"; Text[50]) + { + Caption = 'Key 3'; + } + field(12; "Key 4"; Text[50]) + { + Caption = 'Key 4'; + } + } + + keys + { + key(Key1; "Entry No.") + { + Clustered = true; + } + key(Key2; "Table Name") + { + } + } + + fieldgroups + { + } + + var + WrongParameterTypeErr: Label 'Parameter type must be Record or RecordRef.'; + + procedure Caption(): Text + begin + exit(StrSubstNo('%1 %2', "No. Series Code", "No. Series Description")); + end; + + // TODO: The "Find Record Management" codeunit is located in the W1 BaseApp Utilities + // TODO: We would need to implement the Find Record Management into the System Application + // procedure GetLastEntryNo(): Integer; + // var + // FindRecordManagement: Codeunit "Find Record Management"; + // begin + // exit(FindRecordManagement.GetLastEntryIntFieldValue(Rec, FieldNo("Entry No."))) + // end; + + procedure GetLastEntryNo(): Integer; + begin + GetLastEntryIntFieldValue(Rec, FieldNo("Entry No.")); + end; + + procedure GetLastEntryIntFieldValue(SourceRec: Variant; FieldNo: Integer): Integer; + var + IntFields: list of [Integer]; + begin + IntFields.Add(FieldNo); + GetLastEntryIntFieldValues(SourceRec, IntFields); + exit(IntFields.Get(1)); + end; + + procedure GetLastEntryIntFieldValues(SourceRec: Variant; var FieldNoValues: List of [Integer]) + var + RecRef: RecordRef; + FieldNo: Integer; + FirstIteration: Boolean; + begin + ConvertVariantToRecordRef(SourceRec, RecRef); + RecRef.Reset(); + FirstIteration := true; + foreach FieldNo in FieldNoValues do + if RecRef.FieldExist(FieldNo) then + if FirstIteration then begin + RecRef.SetLoadFields(FieldNo); + FirstIteration := false; + end else + RecRef.AddLoadFields(FieldNo); + + FindLastEntryIgnoringSecurityFilter(RecRef); + GetIntFieldValues(RecRef, FieldNoValues); + end; + + local procedure ConvertVariantToRecordRef(SourceRec: Variant; var RecRef: RecordRef) + begin + case true of + SourceRec.IsRecordRef: + RecRef := SourceRec; + SourceRec.IsRecord: + RecRef.GetTable(SourceRec); + else + Error(WrongParameterTypeErr); + end; + end; + + procedure FindLastEntryIgnoringSecurityFilter(var RecRef: RecordRef) Found: Boolean; + var + IsHandled: Boolean; + xSecurityFilter: SecurityFilter; + begin + OnBeforeFindLastEntryIgnoringSecurityFilter(RecRef, Found, IsHandled); + if IsHandled then + exit(Found); + + xSecurityFilter := RecRef.SecurityFiltering; + RecRef.SecurityFiltering(RecRef.SecurityFiltering::Ignored); + Found := RecRef.FindLast(); + if RecRef.SecurityFiltering <> xSecurityFilter then + RecRef.SecurityFiltering(xSecurityFilter) + end; + + // [Scope('OnPrem')] + procedure GetIntFieldValues(RecRef: RecordRef; var IntFields: list of [Integer]) + var + FieldNos: list of [Integer]; + FieldNo: Integer; + FieldValue: Variant; + begin + FieldNos := IntFields; + clear(IntFields); + foreach FieldNo in FieldNos do + if IsFieldValid(RecRef, FieldNo, FieldType::Integer, FieldValue) then + IntFields.Add(FieldValue) + else + IntFields.Add(0); + end; + + local procedure IsFieldValid(RecRef: RecordRef; FieldNo: Integer; ExpectedFieldType: FieldType; var Value: Variant): Boolean + var + FldRef: FieldRef; + begin + Clear(Value); + if RecRef.FieldExist(FieldNo) then begin + FldRef := RecRef.Field(FieldNo); + if FldRef.Type = ExpectedFieldType then begin + if FldRef.Class = FieldClass::FlowField then + FldRef.CalcField(); + Value := FldRef.Value(); + exit(true); + end; + end; + end; + + [IntegrationEvent(false, false)] + local procedure OnBeforeFindLastEntryIgnoringSecurityFilter(var RecRef: RecordRef; var Found: Boolean; var IsHandled: Boolean) + begin + end; + +} \ No newline at end of file diff --git a/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesWhereUsedList.Page.al b/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesWhereUsedList.Page.al new file mode 100644 index 0000000000..26fadaf9c0 --- /dev/null +++ b/src/Business Foundation/App/NoSeries/src/Setup/NoSeriesWhereUsedList.Page.al @@ -0,0 +1,93 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + +namespace Microsoft.Foundation.NoSeries; + +page 2 "No. Series Where-Used List" +{ + Caption = 'No. Series Where-Used List'; + DataCaptionExpression = Rec.Caption(); + Editable = false; + PageType = List; + SourceTable = "No. Series Where-Used"; + + layout + { + area(content) + { + repeater(records) + { + ShowCaption = false; + field("Table ID"; Rec."Table ID") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the object number of the setup table where the No. series is used.'; + Visible = false; + } + field("Table Name"; Rec."Table Name") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the Table Name of the setup table where the No. series is used.'; + } + field(Line; Rec.Line) + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies a reference to Line in the setup table, where the No. series is used.'; + } + field("Field Name"; Rec."Field Name") + { + ApplicationArea = Basic, Suite; + ToolTip = 'Specifies the name of the field in the setup table where the No. series is used.'; + } + } + } + area(factboxes) + { + systempart(Links; Links) + { + ApplicationArea = RecordLinks; + Visible = false; + } + systempart(Notes; Notes) + { + ApplicationArea = Notes; + Visible = false; + } + } + } + + actions + { + area(processing) + { + action(ShowDetails) + { + ApplicationArea = Basic, Suite; + Caption = 'Show Details'; + Image = ViewDetails; + ToolTip = 'View more details on the selected record.'; + + trigger OnAction() + var + CalcNoSeriesWhereUsed: Codeunit "Calc. No. Series Where-Used"; + begin + Clear(CalcNoSeriesWhereUsed); + CalcNoSeriesWhereUsed.ShowSetupForm(Rec); + end; + } + } + area(Promoted) + { + group(Category_Process) + { + Caption = 'Process'; + + actionref(ShowDetails_Promoted; ShowDetails) + { + } + } + } + } +} \ No newline at end of file