diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/QltyInspecGenRuleMgmt.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/QltyInspecGenRuleMgmt.Codeunit.al
index 634798ed01..0a42630edd 100644
--- a/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/QltyInspecGenRuleMgmt.Codeunit.al
+++ b/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/QltyInspecGenRuleMgmt.Codeunit.al
@@ -16,7 +16,7 @@ using Microsoft.QualityManagement.Utilities;
codeunit 20405 "Qlty. Inspec. Gen. Rule Mgmt."
{
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
QltyTraversal: Codeunit "Qlty. Traversal";
UnexpectedAndNoDetailsErr: Label 'Something unexpected went wrong trying to find a matching quality inspection generation rule. Please review your Quality Inspection source table configuration.';
CouldNotFindGenerationRuleErr: Label 'Could not find any compatible inspection generation rules for the template %1. Navigate to Quality Inspection Generation Rules and create a generation rule for the template %1', Comment = '%1=the template';
@@ -122,7 +122,7 @@ codeunit 20405 "Qlty. Inspec. Gen. Rule Mgmt."
Error(UnexpectedUnableWithADetailErr, Format(TargetRecordRef.RecordId()));
Found := FindFirstGenerationRuleAndRecordBasedOnRecursive(
- QltyMiscHelpers.GetArbitraryMaximumRecursion(),
+ QltyConfigurationHelpers.GetArbitraryMaximumRecursion(),
false,
RaiseErrorIfNoRuleIsFound,
TargetRecordRef,
@@ -153,7 +153,7 @@ codeunit 20405 "Qlty. Inspec. Gen. Rule Mgmt."
Error(NoGenRuleErr, Format(TargetRecordRef.RecordId()));
Found := FindFirstGenerationRuleAndRecordBasedOnRecursive(
- QltyMiscHelpers.GetArbitraryMaximumRecursion(),
+ QltyConfigurationHelpers.GetArbitraryMaximumRecursion(),
true,
IsManualCreation,
TargetRecordRef,
diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al
index 7543ce3ce1..04a6cfdba6 100644
--- a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al
+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al
@@ -18,6 +18,7 @@ codeunit 20410 "Qlty. Result Evaluation"
TableNo = "Qlty. Inspection Line";
var
+ QltyLocalization: Codeunit "Qlty. Localization";
IsDefaultNumberTok: Label '<>0', Locked = true;
IsDefaultTextTok: Label '<>''''', Locked = true;
InvalidDataTypeErr: Label 'The value "%1" is not allowed for %2, it is not a %3.', Comment = '%1=the value, %2=field name,%3=field type.';
@@ -378,16 +379,13 @@ codeunit 20410 "Qlty. Result Evaluation"
QltyTestValueType::"Value Type Boolean":
begin
if not (IsBlankOrEmptyCondition(AllowableValues) and (TextToValidate = '')) then
- if QltyMiscHelpers.GetBooleanFor(TextToValidate) then
- TextToValidate := QltyMiscHelpers.GetTranslatedYes250()
- else
- TextToValidate := QltyMiscHelpers.GetTranslatedNo250();
+ TextToValidate := QltyLocalization.FormatForUser(QltyMiscHelpers.GetBooleanFor(TextToValidate));
if (AllowableValues <> '') and (QltyMiscHelpers.CanTextBeInterpretedAsBooleanIsh(AllowableValues)) then begin
if not QltyMiscHelpers.GetBooleanFor(TextToValidate) = QltyMiscHelpers.GetBooleanFor(AllowableValues) then
Error(NotInAllowableValuesErr, TextToValidate, NumberOrNameOfTestNameForError, AllowableValues);
end else
- if not (TextToValidate in [QltyMiscHelpers.GetTranslatedYes250(), QltyMiscHelpers.GetTranslatedNo250(), '']) then
+ if not (TextToValidate in [QltyLocalization.GetTranslatedYes(), QltyLocalization.GetTranslatedNo(), '']) then
Error(NotInAllowableValuesErr, TextToValidate, NumberOrNameOfTestNameForError, AllowableValues);
end;
QltyTestValueType::"Value Type Text":
diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/SourceConfiguration/QltyTraversal.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/SourceConfiguration/QltyTraversal.Codeunit.al
index 31f6c33f42..c244212cb6 100644
--- a/src/Apps/W1/Quality Management/app/src/Configuration/SourceConfiguration/QltyTraversal.Codeunit.al
+++ b/src/Apps/W1/Quality Management/app/src/Configuration/SourceConfiguration/QltyTraversal.Codeunit.al
@@ -20,6 +20,7 @@ using System.Reflection;
codeunit 20408 "Qlty. Traversal"
{
var
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
ControlInfoToVisibility: Dictionary of [Text, Boolean];
ControlInfoToCaptionClass: Dictionary of [Text, Text];
@@ -122,7 +123,7 @@ codeunit 20408 "Qlty. Traversal"
/// True if at least one possible target configuration was found; False otherwise
internal procedure FindPossibleTargetsBasedOnConfigRecursive(InputTable: Integer; var TempAvailableQltyInspectSourceConfig: Record "Qlty. Inspect. Source Config." temporary): Boolean
begin
- exit(FindPossibleTargetsBasedOnConfigRecursiveWithList(QltyMiscHelpers.GetArbitraryMaximumRecursion(), InputTable, TempAvailableQltyInspectSourceConfig));
+ exit(FindPossibleTargetsBasedOnConfigRecursiveWithList(QltyConfigurationHelpers.GetArbitraryMaximumRecursion(), InputTable, TempAvailableQltyInspectSourceConfig));
end;
local procedure FindPossibleTargetsBasedOnConfigRecursiveWithList(CurrentRecursionDepth: Integer; InputTable: Integer; var TempAvailableQltyInspectSourceConfig: Record "Qlty. Inspect. Source Config." temporary) Found: Boolean
@@ -215,7 +216,7 @@ codeunit 20408 "Qlty. Traversal"
if TemporaryInspectionMatchRecordRef.Insert(false) then;
QltyInspectionHeader.SetIsCreating(true);
CouldApply := ApplySourceRecursive(
- QltyMiscHelpers.GetArbitraryMaximumRecursion(),
+ QltyConfigurationHelpers.GetArbitraryMaximumRecursion(),
TemporaryInspectionMatchRecordRef,
TempAvailableQltyInspectSourceConfig,
QltyInspectionHeader,
@@ -476,7 +477,7 @@ codeunit 20408 "Qlty. Traversal"
OFFromTableIds.Add(InputQltyInspectionHeader."Source RecordId 4".TableNo());
foreach FromTableIterator in OFFromTableIds do begin
- TestText := GetSourceFieldInfoFromChain(ListOfConsideredSourceRecords, QltyMiscHelpers.GetArbitraryMaximumRecursion(), FromTableIterator, InputTable, SourceField."No.", BackupFieldCaption);
+ TestText := GetSourceFieldInfoFromChain(ListOfConsideredSourceRecords, QltyConfigurationHelpers.GetArbitraryMaximumRecursion(), FromTableIterator, InputTable, SourceField."No.", BackupFieldCaption);
if TestText <> '' then
break;
end;
diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestExprCardPart.Page.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestExprCardPart.Page.al
index 83e953499d..fd8fc1e2e6 100644
--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestExprCardPart.Page.al
+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestExprCardPart.Page.al
@@ -443,7 +443,7 @@ page 20467 "Qlty. Test Expr. Card Part"
var
QltyTest: Record "Qlty. Test";
QltyResultConditionMgmt: Codeunit "Qlty. Result Condition Mgmt.";
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyValueParsing: Codeunit "Qlty. Value Parsing";
MatrixSourceRecordId: array[10] of RecordId;
Visible1: Boolean;
Visible2: Boolean;
@@ -523,7 +523,7 @@ page 20467 "Qlty. Test Expr. Card Part"
QltyResultConditionMgmt.GetPromotedResultsForTest(QltyTest, MatrixSourceRecordId, MatrixArrayConditionCellData, MatrixArrayConditionDescriptionCellData, MatrixArrayCaptionSet, MatrixVisibleState);
for Iterator := 1 to ArrayLen(MatrixArrayConditionCellData) do
- QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax(MatrixArrayConditionCellData[Iterator], MatrixMinValue[Iterator], MatrixMaxValue[Iterator]);
+ QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax(MatrixArrayConditionCellData[Iterator], MatrixMinValue[Iterator], MatrixMaxValue[Iterator]);
Visible1 := MatrixVisibleState[1];
Visible2 := MatrixVisibleState[2];
@@ -543,7 +543,7 @@ page 20467 "Qlty. Test Expr. Card Part"
begin
QltyIResultConditConf.Get(MatrixSourceRecordId[MatrixField]);
QltyIResultConditConf.Validate(Condition, MatrixArrayConditionCellData[MatrixField]);
- QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax(QltyIResultConditConf.Condition, MatrixMinValue[MatrixField], MatrixMaxValue[MatrixField]);
+ QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax(QltyIResultConditConf.Condition, MatrixMinValue[MatrixField], MatrixMaxValue[MatrixField]);
QltyIResultConditConf.Modify(true);
LoadExistingTest(QltyTest.Code, true);
CurrPage.Update(false);
diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestNumberCardPart.Page.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestNumberCardPart.Page.al
index 8aa671c37c..8505b8159f 100644
--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestNumberCardPart.Page.al
+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestNumberCardPart.Page.al
@@ -985,7 +985,7 @@ page 20434 "Qlty. Test Number Card Part"
var
QltyTest: Record "Qlty. Test";
QltyResultConditionMgmt: Codeunit "Qlty. Result Condition Mgmt.";
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyValueParsing: Codeunit "Qlty. Value Parsing";
MatrixSourceRecordId: array[10] of RecordId;
Visible1: Boolean;
Visible2: Boolean;
@@ -1096,7 +1096,7 @@ page 20434 "Qlty. Test Number Card Part"
if QltyTest."Wizard Internal" = QltyTest."Wizard Internal"::"In Progress" then
AdvancedRange := DefaultRangeTok;
- if QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax(AdvancedRange, MinAllowed, MaxAllowed) then begin
+ if QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax(AdvancedRange, MinAllowed, MaxAllowed) then begin
if not QltyTestIds.Contains(QltyTest.Code) then
RangeNumberType := RangeNumberType::"A range of numbers";
end else
@@ -1225,7 +1225,7 @@ page 20434 "Qlty. Test Number Card Part"
QltyResultConditionMgmt.GetPromotedResultsForTest(QltyTest, MatrixSourceRecordId, MatrixArrayConditionCellData, MatrixArrayConditionDescriptionCellData, MatrixArrayCaptionSet, MatrixVisibleState);
for Iterator := 1 to ArrayLen(MatrixArrayConditionCellData) do
- QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax(MatrixArrayConditionCellData[Iterator], MatrixMinValue[Iterator], MatrixMaxValue[Iterator]);
+ QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax(MatrixArrayConditionCellData[Iterator], MatrixMinValue[Iterator], MatrixMaxValue[Iterator]);
Visible1 := MatrixVisibleState[1];
Visible2 := MatrixVisibleState[2];
@@ -1245,7 +1245,7 @@ page 20434 "Qlty. Test Number Card Part"
begin
QltyIResultConditConf.Get(MatrixSourceRecordId[Matrix]);
QltyIResultConditConf.Validate(Condition, MatrixArrayConditionCellData[Matrix]);
- QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax(QltyIResultConditConf.Condition, MatrixMinValue[Matrix], MatrixMaxValue[Matrix]);
+ QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax(QltyIResultConditConf.Condition, MatrixMinValue[Matrix], MatrixMaxValue[Matrix]);
QltyIResultConditConf.Modify(true);
LoadExistingTest(QltyTest.Code);
CurrPage.Update(false);
diff --git a/src/Apps/W1/Quality Management/app/src/Document/QltyMostRecentPicture.Page.al b/src/Apps/W1/Quality Management/app/src/Document/QltyMostRecentPicture.Page.al
index 8e1a0cf75f..965a05d27c 100644
--- a/src/Apps/W1/Quality Management/app/src/Document/QltyMostRecentPicture.Page.al
+++ b/src/Apps/W1/Quality Management/app/src/Document/QltyMostRecentPicture.Page.al
@@ -53,14 +53,14 @@ page 20431 "Qlty. Most Recent Picture"
trigger OnAction()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyFileImport: Codeunit "Qlty. File Import";
InStream: InStream;
begin
if Rec."Most Recent Picture".HasValue() then
if not Confirm(OverrideImageQst) then
exit;
Clear(Rec."Most Recent Picture");
- if QltyMiscHelpers.PromptAndImportIntoInStream(FileFilterTok, InStream) then begin
+ if QltyFileImport.PromptAndImportIntoInStream(FileFilterTok, InStream) then begin
Rec."Most Recent Picture".ImportStream(InStream, ImageTok);
Rec.Modify();
end;
diff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyConfigurationHelpers.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyConfigurationHelpers.Codeunit.al
new file mode 100644
index 0000000000..96c62df18a
--- /dev/null
+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyConfigurationHelpers.Codeunit.al
@@ -0,0 +1,62 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace Microsoft.QualityManagement.Utilities;
+
+using Microsoft.QualityManagement.Setup;
+
+codeunit 20597 "Qlty. Configuration Helpers"
+{
+ ///
+ /// The maximum recursion to use when creating inspections.
+ /// Used for traversal on source table configuration when finding applicable generation rules, and also when populating source fields.
+ ///
+ /// This limit prevents infinite loops in complex configuration hierarchies and ensures reasonable performance
+ /// when traversing multi-level table relationships.
+ ///
+ /// The maximum recursion depth allowed (currently 20 levels)
+ procedure GetArbitraryMaximumRecursion(): Integer
+ begin
+ exit(20);
+ end;
+
+ ///
+ /// Returns the maximum number of rows to show in field lookup dialogs.
+ /// Uses setup configuration if defined, otherwise defaults to 100.
+ ///
+ /// Lookup order:
+ /// 1. OnBeforeGetDefaultMaximumRowsToShowInLookup event (if handled)
+ /// 2. Qlty. Management Setup."Max Rows Field Lookups" (if > 0)
+ /// 3. Default value of 100
+ ///
+ /// Maximum number of rows for field lookups
+ procedure GetDefaultMaximumRowsFieldLookup() ResultRowsCount: Integer
+ var
+ QltyManagementSetup: Record "Qlty. Management Setup";
+ Handled: Boolean;
+ begin
+ ResultRowsCount := 100;
+ OnBeforeGetDefaultMaximumRowsToShowInLookup(ResultRowsCount, Handled);
+ if Handled then
+ exit;
+
+ if not QltyManagementSetup.GetSetupRecord() then
+ exit;
+
+ if QltyManagementSetup."Max Rows Field Lookups" > 0 then
+ ResultRowsCount := QltyManagementSetup."Max Rows Field Lookups";
+ end;
+
+ ///
+ /// Provides an opportunity for customizations to alter the default maximum rows shown
+ /// for a table lookup in a quality inspector field.
+ /// Changing the default to a larger number can introduce performance issues.
+ ///
+ /// The number of rows to show
+ /// Set to true if the event was handled
+ [IntegrationEvent(false, false)]
+ local procedure OnBeforeGetDefaultMaximumRowsToShowInLookup(var Rows: Integer; var Handled: Boolean)
+ begin
+ end;
+}
diff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyFileImport.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyFileImport.Codeunit.al
new file mode 100644
index 0000000000..f93a8eb1ce
--- /dev/null
+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyFileImport.Codeunit.al
@@ -0,0 +1,27 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace Microsoft.QualityManagement.Utilities;
+
+codeunit 20596 "Qlty. File Import"
+{
+ var
+ ImportFromLbl: Label 'Import From File';
+
+ ///
+ /// Prompts the user to select a file and imports its contents into an InStream for processing.
+ /// Displays a file upload dialog with optional file type filtering.
+ ///
+ /// Common usage: Importing configuration files, test data, or external quality inspection results.
+ ///
+ /// File type filter for the upload dialog (e.g., "*.xml|*.txt")
+ /// Output: InStream containing the uploaded file contents
+ /// True if file was successfully selected and uploaded; False if user cancelled or upload failed
+ procedure PromptAndImportIntoInStream(FilterString: Text; var InStream: InStream): Boolean
+ var
+ ServerFile: Text;
+ begin
+ exit(UploadIntoStream(ImportFromLbl, '', FilterString, ServerFile, InStream));
+ end;
+}
diff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyLocalization.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyLocalization.Codeunit.al
new file mode 100644
index 0000000000..96d02cf80b
--- /dev/null
+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyLocalization.Codeunit.al
@@ -0,0 +1,44 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace Microsoft.QualityManagement.Utilities;
+
+codeunit 20598 "Qlty. Localization"
+{
+ var
+ TranslatableYesLbl: Label 'Yes';
+ TranslatableNoLbl: Label 'No';
+
+ ///
+ /// Returns the translatable "Yes" label with maximum length of 250 characters.
+ /// Used for UI display and user-facing text where localization is required.
+ ///
+ /// The localized "Yes" text (up to 250 characters)
+ procedure GetTranslatedYes(): Text[250]
+ begin
+ exit(TranslatableYesLbl);
+ end;
+
+ ///
+ /// Returns the translatable "No" label with maximum length of 250 characters.
+ /// Used for UI display and user-facing text where localization is required.
+ ///
+ /// The localized "No" text (up to 250 characters)
+ procedure GetTranslatedNo(): Text[250]
+ begin
+ exit(TranslatableNoLbl);
+ end;
+
+ ///
+ /// Formats a boolean value for user display using localized Yes/No text.
+ ///
+ /// The boolean value to format
+ /// Localized "Yes" for true, "No" for false
+ procedure FormatForUser(Value: Boolean): Text[250]
+ begin
+ if Value then
+ exit(TranslatableYesLbl);
+ exit(TranslatableNoLbl);
+ end;
+}
diff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al
index 57d6b9627a..8b594577b5 100644
--- a/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al
+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al
@@ -12,7 +12,6 @@ using Microsoft.Inventory.Tracking;
using Microsoft.Projects.Resources.Resource;
using Microsoft.QualityManagement.Configuration.Template.Test;
using Microsoft.QualityManagement.Document;
-using Microsoft.QualityManagement.Setup;
using Microsoft.Utilities;
using System.IO;
using System.Reflection;
@@ -22,11 +21,8 @@ using System.Security.User;
codeunit 20599 "Qlty. Misc Helpers"
{
var
- TranslatableYesLbl: Label 'Yes';
- TranslatableNoLbl: Label 'No';
LockedYesLbl: Label 'Yes', Locked = true;
LockedNoLbl: Label 'No', Locked = true;
- ImportFromLbl: Label 'Import From File';
DateKeywordTxt: Label 'Date';
YesNoKeyword1Txt: Label 'Does the';
YesNoKeyword2Txt: Label 'Do the';
@@ -42,108 +38,6 @@ codeunit 20599 "Qlty. Misc Helpers"
BadTableTok: Label '?table?', Locked = true;
BadFieldTok: Label '?t:%1?f:%2?', Locked = true, Comment = '%1=the table, %2=the requested field';
- ///
- /// Returns the translatable "Yes" label with maximum length of 250 characters.
- /// Used for UI display and user-facing text where localization is required.
- ///
- /// The localized "Yes" text (up to 250 characters)
- procedure GetTranslatedYes250(): Text[250]
- begin
- exit(TranslatableYesLbl);
- end;
-
- ///
- /// Returns the translatable "No" label with maximum length of 250 characters.
- /// Used for UI display and user-facing text where localization is required.
- ///
- /// The localized "No" text (up to 250 characters)
- procedure GetTranslatedNo250(): Text[250]
- begin
- exit(TranslatableNoLbl);
- end;
-
- ///
- /// The maximum recursion to use when creating inspections.
- /// Used for traversal on source table configuration when finding applicable generation rules, and also when populating source fields.
- ///
- /// This limit prevents infinite loops in complex configuration hierarchies and ensures reasonable performance
- /// when traversing multi-level table relationships.
- ///
- /// The maximum recursion depth allowed (currently 20 levels)
- internal procedure GetArbitraryMaximumRecursion(): Integer
- begin
- exit(20);
- end;
-
- internal procedure GetDefaultMaximumRowsFieldLookup() ResultRowsCount: Integer
- var
- QltyManagementSetup: Record "Qlty. Management Setup";
- Handled: Boolean;
- begin
- ResultRowsCount := 100;
- OnBeforeGetDefaultMaximumRowsToShowInLookup(ResultRowsCount, Handled);
- if Handled then
- exit;
-
- if not QltyManagementSetup.GetSetupRecord() then
- exit;
-
- if QltyManagementSetup."Max Rows Field Lookups" > 0 then
- ResultRowsCount := QltyManagementSetup."Max Rows Field Lookups";
- end;
-
- ///
- /// Prompts the user to select a file and imports its contents into an InStream for processing.
- /// Displays a file upload dialog with optional file type filtering.
- ///
- /// Common usage: Importing configuration files, test data, or external quality inspection results.
- ///
- /// File type filter for the upload dialog (e.g., "*.xml|*.txt")
- /// Output: InStream containing the uploaded file contents
- /// True if file was successfully selected and uploaded; False if user cancelled or upload failed
- procedure PromptAndImportIntoInStream(FilterString: Text; var InStream: InStream) Worked: Boolean
- var
- ServerFile: Text;
- begin
- Worked := UploadIntoStream(ImportFromLbl, '', FilterString, ServerFile, InStream);
- end;
-
- ///
- /// Attempts to parse simple range notation (min..max) into separate minimum and maximum decimal values.
- /// Handles the common 90% use case of range specifications in quality inspections.
- ///
- /// Examples:
- /// - "10..20" → OutMin=10, OutMax=20, returns true
- /// - "5.5..10.5" → OutMin=5.5, OutMax=10.5, returns true
- /// - "Invalid" → returns false
- /// - "10" → returns false (not a range)
- ///
- /// The text containing a range in format "minValue..maxValue"
- /// Output: The minimum value from the range
- /// Output: The maximum value from the range
- /// True if successfully parsed as a simple range; False if input doesn't match simple range pattern
- procedure AttemptSplitSimpleRangeIntoMinMax(InputText: Text; var MinValueInRange: Decimal; var MaxValueInRange: Decimal): Boolean
- var
- OfParts: List of [Text];
- Temp: Text;
- begin
- Clear(MaxValueInRange);
- Clear(MinValueInRange);
-
- if InputText.Contains('..') then
- if InputText.IndexOf('..') > 0 then begin
- OfParts := InputText.Split('..');
- if OfParts.Count() = 2 then begin
- OfParts.Get(1, Temp);
- if Evaluate(MinValueInRange, Temp) then begin
- OfParts.Get(2, Temp);
- if Evaluate(MaxValueInRange, Temp) then
- exit(true);
- end;
- end;
- end;
- end;
-
///
/// Retrieves available record values for a table lookup field configured on an inspection line, returned as CSV.
/// Evaluates expressions and applies filters configured in the field definition to generate the list.
@@ -220,12 +114,13 @@ codeunit 20599 "Qlty. Misc Helpers"
/// Output: Temporary buffer populated with lookup values
procedure GetRecordsForTableField(var QltyTest: Record "Qlty. Test"; var OptionalContextQltyInspectionHeader: Record "Qlty. Inspection Header"; var OptionalContextQltyInspectionLine: Record "Qlty. Inspection Line"; var TempBufferQltyLookupCode: Record "Qlty. Lookup Code" temporary)
var
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
QltyExpressionMgmt: Codeunit "Qlty. Expression Mgmt.";
ReasonableMaximum: Integer;
DummyText: Text;
TableFilter: Text;
begin
- ReasonableMaximum := GetDefaultMaximumRowsFieldLookup();
+ ReasonableMaximum := QltyConfigurationHelpers.GetDefaultMaximumRowsFieldLookup();
TableFilter := QltyExpressionMgmt.EvaluateTextExpression(QltyTest."Lookup Table Filter", OptionalContextQltyInspectionHeader, OptionalContextQltyInspectionLine);
@@ -269,8 +164,9 @@ codeunit 20599 "Qlty. Misc Helpers"
internal procedure GetCSVOfValuesFromRecord(CurrentTable: Integer; ChoiceField: Integer; TableFilter: Text) ResultText: Text
var
TempBufferQltyLookupCode: Record "Qlty. Lookup Code" temporary;
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
begin
- GetRecordsForTableField(CurrentTable, ChoiceField, 0, TableFilter, GetArbitraryMaximumRecursion(), TempBufferQltyLookupCode, ResultText);
+ GetRecordsForTableField(CurrentTable, ChoiceField, 0, TableFilter, QltyConfigurationHelpers.GetArbitraryMaximumRecursion(), TempBufferQltyLookupCode, ResultText);
end;
///
@@ -287,6 +183,7 @@ codeunit 20599 "Qlty. Misc Helpers"
///
local procedure GetRecordsForTableField(CurrentTable: Integer; ChoiceField: Integer; DescriptionField: Integer; TableFilter: Text; MaxCountRecords: Integer; var TempBufferQltyLookupCode: Record "Qlty. Lookup Code" temporary; var CSVSimpleText: Text)
var
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
RecordRefToFetch: RecordRef;
FieldRefToChoiceField: FieldRef;
FieldRefToDescriptionField: FieldRef;
@@ -300,7 +197,7 @@ codeunit 20599 "Qlty. Misc Helpers"
exit;
if MaxCountRecords <= 0 then begin
- MaxCountRecords := GetDefaultMaximumRowsFieldLookup();
+ MaxCountRecords := QltyConfigurationHelpers.GetDefaultMaximumRowsFieldLookup();
if MaxCountRecords <= 0 then
MaxCountRecords := 1;
if MaxCountRecords > 1000 then
@@ -361,13 +258,15 @@ codeunit 20599 "Qlty. Misc Helpers"
/// The text value to convert to boolean
/// True if input matches any positive boolean representation; False otherwise
procedure GetBooleanFor(Input: Text) IsTrue: Boolean
+ var
+ QltyLocalization: Codeunit "Qlty. Localization";
begin
if Input <> '' then begin
if not Evaluate(IsTrue, Input) then
exit(IsTextValuePositiveBoolean(Input));
case UpperCase(Input) of
- UpperCase(TranslatableYesLbl), UpperCase(LockedYesLbl),
+ UpperCase(QltyLocalization.GetTranslatedYes()), UpperCase(LockedYesLbl),
'Y', 'YES', 'T', 'TRUE', '1', 'POSITIVE', 'ENABLED', 'CHECK', 'CHECKED',
'GOOD', 'PASS', 'ACCEPTABLE', 'PASSED', 'OK', 'ON',
'V', ':SELECTED:':
@@ -391,6 +290,7 @@ codeunit 20599 "Qlty. Misc Helpers"
/// True if the value represents a positive/affirmative boolean; False otherwise
procedure IsTextValuePositiveBoolean(ValueToCheckIfPositiveBoolean: Text): Boolean
var
+ QltyLocalization: Codeunit "Qlty. Localization";
ConvertedBoolean: Boolean;
begin
ValueToCheckIfPositiveBoolean := ValueToCheckIfPositiveBoolean.Trim();
@@ -400,7 +300,7 @@ codeunit 20599 "Qlty. Misc Helpers"
exit(true);
case UpperCase(ValueToCheckIfPositiveBoolean) of
- UpperCase(TranslatableYesLbl),
+ UpperCase(QltyLocalization.GetTranslatedYes()),
UpperCase(LockedYesLbl),
'Y',
'YES',
@@ -442,6 +342,7 @@ codeunit 20599 "Qlty. Misc Helpers"
/// True if text represents a negative boolean value; False otherwise (including positive values)
procedure IsTextValueNegativeBoolean(ValueToCheckIfNegativeBoolean: Text): Boolean
var
+ QltyLocalization: Codeunit "Qlty. Localization";
ConvertedBoolean: Boolean;
begin
ValueToCheckIfNegativeBoolean := ValueToCheckIfNegativeBoolean.Trim();
@@ -451,7 +352,7 @@ codeunit 20599 "Qlty. Misc Helpers"
exit(true);
case UpperCase(ValueToCheckIfNegativeBoolean) of
- UpperCase(TranslatableNoLbl),
+ UpperCase(QltyLocalization.GetTranslatedNo()),
UpperCase(LockedNoLbl),
'N',
'NO',
@@ -928,16 +829,4 @@ codeunit 20599 "Qlty. Misc Helpers"
local procedure OnBeforeNavigateToSourceDocument(var QltyInspectionHeader: Record "Qlty. Inspection Header"; var Handled: Boolean)
begin
end;
-
- ///
- /// Provides an opportunity for customizations to alter the default maximum rows shown
- /// for a table lookup in a quality inspector field.
- /// Changing the default to a larger number can introduce performance issues.
- ///
- ///
- ///
- [IntegrationEvent(false, false)]
- local procedure OnBeforeGetDefaultMaximumRowsToShowInLookup(var Rows: Integer; var Handled: Boolean)
- begin
- end;
}
diff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyValueParsing.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyValueParsing.Codeunit.al
new file mode 100644
index 0000000000..c8e4034cf5
--- /dev/null
+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyValueParsing.Codeunit.al
@@ -0,0 +1,44 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace Microsoft.QualityManagement.Utilities;
+
+codeunit 20595 "Qlty. Value Parsing"
+{
+ ///
+ /// Attempts to parse simple range notation (min..max) into separate minimum and maximum decimal values.
+ /// Handles the common 90% use case of range specifications in quality inspections.
+ ///
+ /// Examples:
+ /// - "10..20" → OutMin=10, OutMax=20, returns true
+ /// - "5.5..10.5" → OutMin=5.5, OutMax=10.5, returns true
+ /// - "Invalid" → returns false
+ /// - "10" → returns false (not a range)
+ ///
+ /// The text containing a range in format "minValue..maxValue"
+ /// Output: The minimum value from the range
+ /// Output: The maximum value from the range
+ /// True if successfully parsed as a simple range; False if input doesn't match simple range pattern
+ procedure AttemptSplitSimpleRangeIntoMinMax(InputText: Text; var MinValueInRange: Decimal; var MaxValueInRange: Decimal): Boolean
+ var
+ OfParts: List of [Text];
+ Temp: Text;
+ begin
+ Clear(MaxValueInRange);
+ Clear(MinValueInRange);
+
+ if InputText.Contains('..') then
+ if InputText.IndexOf('..') > 0 then begin
+ OfParts := InputText.Split('..');
+ if OfParts.Count() = 2 then begin
+ OfParts.Get(1, Temp);
+ if Evaluate(MinValueInRange, Temp) then begin
+ OfParts.Get(2, Temp);
+ if Evaluate(MaxValueInRange, Temp) then
+ exit(true);
+ end;
+ end;
+ end;
+ end;
+}
diff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsMisc.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsMisc.Codeunit.al
index ee5ca55240..480ea1017a 100644
--- a/src/Apps/W1/Quality Management/test/src/QltyTestsMisc.Codeunit.al
+++ b/src/Apps/W1/Quality Management/test/src/QltyTestsMisc.Codeunit.al
@@ -75,7 +75,7 @@ codeunit 139964 "Qlty. Tests - Misc."
[Test]
procedure AttemptSplitSimpleRangeIntoMinMax_IntegerSimple()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyValueParsing: Codeunit "Qlty. Value Parsing";
Min: Decimal;
Max: Decimal;
begin
@@ -86,7 +86,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] AttemptSplitSimpleRangeIntoMinMax is called with the range string
// [THEN] The function returns true and sets Min to 1 and Max to 2
Initialize();
- LibraryAssert.AreEqual(true, QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax('1..2', Min, Max), 'simple conversion');
+ LibraryAssert.AreEqual(true, QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax('1..2', Min, Max), 'simple conversion');
LibraryAssert.AreEqual(1, Min, 'simple integer min');
LibraryAssert.AreEqual(2, Max, 'simple integer max');
end;
@@ -94,7 +94,7 @@ codeunit 139964 "Qlty. Tests - Misc."
[Test]
procedure AttemptSplitSimpleRangeIntoMinMax_IntegerNegativeValues()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyValueParsing: Codeunit "Qlty. Value Parsing";
Min: Decimal;
Max: Decimal;
begin
@@ -105,7 +105,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] AttemptSplitSimpleRangeIntoMinMax is called with the negative range
// [THEN] The function returns true and sets Min to -5 and Max to -1
Initialize();
- LibraryAssert.AreEqual(true, QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax('-5..-1', Min, Max), 'negative');
+ LibraryAssert.AreEqual(true, QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax('-5..-1', Min, Max), 'negative');
LibraryAssert.AreEqual(-5, Min, 'simple integer min');
LibraryAssert.AreEqual(-1, Max, 'simple integer max');
end;
@@ -113,7 +113,7 @@ codeunit 139964 "Qlty. Tests - Misc."
[Test]
procedure AttemptSplitSimpleRangeIntoMinMax_DecimalSimple()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyValueParsing: Codeunit "Qlty. Value Parsing";
Min: Decimal;
Max: Decimal;
begin
@@ -124,7 +124,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] AttemptSplitSimpleRangeIntoMinMax is called with the decimal range
// [THEN] The function returns true and sets Min to 1.00000001 and Max to 2.999999999999
Initialize();
- LibraryAssert.AreEqual(true, QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax('1.00000001..2.999999999999', Min, Max), 'simple conversion');
+ LibraryAssert.AreEqual(true, QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax('1.00000001..2.999999999999', Min, Max), 'simple conversion');
LibraryAssert.AreEqual(1.00000001, Min, 'simple decimal min');
LibraryAssert.AreEqual(2.999999999999, Max, 'simple decimal max');
end;
@@ -132,7 +132,7 @@ codeunit 139964 "Qlty. Tests - Misc."
[Test]
procedure AttemptSplitSimpleRangeIntoMinMax_DecimalThousands()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyValueParsing: Codeunit "Qlty. Value Parsing";
Min: Decimal;
Max: Decimal;
begin
@@ -143,7 +143,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] AttemptSplitSimpleRangeIntoMinMax is called with the formatted range
// [THEN] The function returns true and correctly parses Min and Max values
Initialize();
- LibraryAssert.AreEqual(true, QltyMiscHelpers.AttemptSplitSimpleRangeIntoMinMax('1.00000001..1,234,567,890.99', Min, Max), 'simple conversion');
+ LibraryAssert.AreEqual(true, QltyValueParsing.AttemptSplitSimpleRangeIntoMinMax('1.00000001..1,234,567,890.99', Min, Max), 'simple conversion');
LibraryAssert.AreEqual(1.00000001, Min, 'thousands separator decimal min');
LibraryAssert.AreEqual(1234567890.99, Max, 'thousands separator decimal max');
end;
@@ -151,7 +151,7 @@ codeunit 139964 "Qlty. Tests - Misc."
[Test]
procedure GetArbitraryMaximumRecursion()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
begin
// [SCENARIO] Verify the maximum recursion depth limit
@@ -160,7 +160,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] GetArbitraryMaximumRecursion is called
// [THEN] The function returns 20 as the maximum recursion depth
Initialize();
- LibraryAssert.AreEqual(20, QltyMiscHelpers.GetArbitraryMaximumRecursion(), '20 levels of recursion maximum are expected');
+ LibraryAssert.AreEqual(20, QltyConfigurationHelpers.GetArbitraryMaximumRecursion(), '20 levels of recursion maximum are expected');
end;
[Test]
@@ -741,7 +741,7 @@ codeunit 139964 "Qlty. Tests - Misc."
procedure GetDefaultMaximumRowsFieldLookup_Defined()
var
QltyManagementSetup: Record "Qlty. Management Setup";
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
QltyInspectionUtility: Codeunit "Qlty. Inspection Utility";
begin
// [SCENARIO] Get maximum rows for field lookup when configured
@@ -757,14 +757,14 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] GetDefaultMaximumRowsFieldLookup is called
// [THEN] The function returns the configured value of 2
- LibraryAssert.AreEqual(2, QltyMiscHelpers.GetDefaultMaximumRowsFieldLookup(), 'simple maximum');
+ LibraryAssert.AreEqual(2, QltyConfigurationHelpers.GetDefaultMaximumRowsFieldLookup(), 'simple maximum');
end;
[Test]
procedure GetDefaultMaximumRowsFieldLookup_Undefined()
var
QltyManagementSetup: Record "Qlty. Management Setup";
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyConfigurationHelpers: Codeunit "Qlty. Configuration Helpers";
QltyInspectionUtility: Codeunit "Qlty. Inspection Utility";
begin
// [SCENARIO] Get maximum rows for field lookup when not configured
@@ -780,7 +780,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [WHEN] GetDefaultMaximumRowsFieldLookup is called
// [THEN] The function returns the default value of 100
- LibraryAssert.AreEqual(100, QltyMiscHelpers.GetDefaultMaximumRowsFieldLookup(), 'simple maximum');
+ LibraryAssert.AreEqual(100, QltyConfigurationHelpers.GetDefaultMaximumRowsFieldLookup(), 'simple maximum');
end;
[Test]
@@ -1265,31 +1265,31 @@ codeunit 139964 "Qlty. Tests - Misc."
end;
[Test]
- procedure GetTranslatedYes250()
+ procedure GetTranslatedYes()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyLocalization: Codeunit "Qlty. Localization";
begin
// [SCENARIO] Get translated "Yes" text value
Initialize();
- // [WHEN] GetTranslatedYes250 is called
+ // [WHEN] GetTranslatedYes is called
// [THEN] The function returns the translated string "Yes"
- LibraryAssert.AreEqual('Yes', QltyMiscHelpers.GetTranslatedYes250(), 'locked yes.');
+ LibraryAssert.AreEqual('Yes', QltyLocalization.GetTranslatedYes(), 'locked yes.');
end;
[Test]
- procedure GetTranslatedNo250()
+ procedure GetTranslatedNo()
var
- QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyLocalization: Codeunit "Qlty. Localization";
begin
// [SCENARIO] Get translated "No" text value
Initialize();
- // [WHEN] GetTranslatedNo250 is called
+ // [WHEN] GetTranslatedNo is called
// [THEN] The function returns the translated string "No"
- LibraryAssert.AreEqual('No', QltyMiscHelpers.GetTranslatedNo250(), 'locked no.');
+ LibraryAssert.AreEqual('No', QltyLocalization.GetTranslatedNo(), 'locked no.');
end;
[Test]
@@ -1324,6 +1324,7 @@ codeunit 139964 "Qlty. Tests - Misc."
procedure GuessDataTypeFromDescriptionAndValue_Values()
var
QltyMiscHelpers: Codeunit "Qlty. Misc Helpers";
+ QltyLocalization: Codeunit "Qlty. Localization";
QltyTestValueType: Enum "Qlty. Test Value Type";
begin
// [SCENARIO] Guess data type from actual values
@@ -1333,7 +1334,7 @@ codeunit 139964 "Qlty. Tests - Misc."
// [GIVEN] Various sample values (boolean, numeric, date, text)
// [WHEN] GuessDataTypeFromDescriptionAndValue is called with value (empty description)
// [THEN] The function infers the correct data type from value patterns
- LibraryAssert.AreEqual('No', QltyMiscHelpers.GetTranslatedNo250(), 'locked no.');
+ LibraryAssert.AreEqual('No', QltyLocalization.GetTranslatedNo(), 'locked no.');
LibraryAssert.AreEqual(QltyTestValueType::"Value Type Boolean", QltyMiscHelpers.GuessDataTypeFromDescriptionAndValue('', 'true'), 'bool test 1');
LibraryAssert.AreEqual(QltyTestValueType::"Value Type Boolean", QltyMiscHelpers.GuessDataTypeFromDescriptionAndValue('', 'false'), 'bool test 2');