Skip to content

Commit

Permalink
Add actionable errors for errors in the new No. Series module (#543)
Browse files Browse the repository at this point in the history
In case that the user gets an error, we want to provide an easy way for
the customer to fix those issues whenever possible. Hence adding some
actionable errors to quickly resolve the issue.

Fixes
[AB#476365](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/476365)
  • Loading branch information
AndreasMoth authored Feb 9, 2024
1 parent 016cf46 commit a51be6c
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ tableextension 309 NoSeriesLineObsolete extends "No. Series Line"
var
NoSeriesSequenceImpl: Codeunit "No. Series - Sequence Impl.";
begin
exit(NoSeriesSequenceImpl.ExtractNoFromCode(NumberCode));
exit(NoSeriesSequenceImpl.ExtractNoFromCode(NumberCode, Rec."Series Code"));
end;

[Obsolete('This functionality will be removed without public replacement.', '24.0')]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ codeunit 396 NoSeriesManagement
if LastNoSeriesLine."Series Code" <> '' then begin
if (LastNoSeriesLine.Implementation = "No. Series Implementation"::Sequence) then
if (LastNoSeriesLine."Last No. Used" <> '') and (LastNoSeriesLine."Last No. Used" > NoSeries.GetLastNoUsed(LastNoSeriesLine)) then
RestartSequence(LastNoSeriesLine, NoSeriesSequenceImpl.ExtractNoFromCode(LastNoSeriesLine."Last No. Used"));
RestartSequence(LastNoSeriesLine, NoSeriesSequenceImpl.ExtractNoFromCode(LastNoSeriesLine."Last No. Used", LastNoSeriesLine."Series Code"));
if not (LastNoSeriesLine.Implementation = "No. Series Implementation"::Sequence) or UpdateLastUsedDate then
ModifyNoSeriesLine(LastNoSeriesLine);
end;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// ------------------------------------------------------------------------------------------------
// 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;

codeunit 323 "No. Series - Errors Impl."
{
Access = Internal;
InherentEntitlements = X;
InherentPermissions = X;

var
OpenNoSeriesRelationshipsTxt: Label 'Open No. Series Relationships';
OpenNoSeriesLinesTxt: Label 'Open No. Series Lines';
OpenNoSeriesTxt: Label 'Open No. Series';
NoSeriesCodeTok: Label 'NoSeriesCode', Locked = true;

procedure Throw(ErrorMessage: Text; NoSeriesLine: Record "No. Series Line"; ActionDictionary: Dictionary of [Text, Text])
var
ErrorInfo: ErrorInfo;
begin
if UserCanEditNoSeries() then
AddAction(ErrorInfo, NoSeriesLine.RecordId(), ActionDictionary);

ErrorInfo.Message := ErrorMessage;
Error(ErrorInfo);
end;

procedure Throw(ErrorMessage: Text; NoSeriesCode: Code[20]; ActionDictionary: Dictionary of [Text, Text])
var
ErrorInfo: ErrorInfo;
begin
if UserCanEditNoSeries() then
AddAction(ErrorInfo, NoSeriesCode, ActionDictionary);

ErrorInfo.Message := ErrorMessage;
Error(ErrorInfo);
end;

procedure OpenNoSeriesAction() ActionDictionary: Dictionary of [Text, Text]
begin
ActionDictionary.Add('Caption', OpenNoSeriesTxt);
ActionDictionary.Add('Codeunit', format(Codeunit::"No. Series - Errors Impl."));
ActionDictionary.Add('MethodName', 'OpenNoSeries');
end;

procedure OpenNoSeriesLinesAction() ActionDictionary: Dictionary of [Text, Text]
begin
ActionDictionary.Add('Caption', OpenNoSeriesLinesTxt);
ActionDictionary.Add('Codeunit', format(Codeunit::"No. Series - Errors Impl."));
ActionDictionary.Add('MethodName', 'OpenNoSeriesLines');
end;

procedure OpenNoSeriesRelationshipsAction() ActionDictionary: Dictionary of [Text, Text]
begin
ActionDictionary.Add('Caption', OpenNoSeriesRelationshipsTxt);
ActionDictionary.Add('Codeunit', format(Codeunit::"No. Series - Errors Impl."));
ActionDictionary.Add('MethodName', 'OpenNoSeriesRelationships');
end;

local procedure AddAction(var ErrorInfo: ErrorInfo; RecordId: RecordId; ActionDictionary: Dictionary of [Text, Text])
var
CodeunitId: Integer;
begin
ErrorInfo.RecordId := RecordId;
Evaluate(CodeunitId, ActionDictionary.Get('Codeunit'));
ErrorInfo.AddAction(ActionDictionary.Get('Caption'), CodeunitId, ActionDictionary.Get('MethodName'));
end;

local procedure AddAction(var ErrorInfo: ErrorInfo; NoSeriesCode: Code[20]; ActionDictionary: Dictionary of [Text, Text])
var
CodeunitId: Integer;
begin
ErrorInfo.CustomDimensions.Add(NoSeriesCodeTok, NoSeriesCode);
Evaluate(CodeunitId, ActionDictionary.Get('Codeunit'));
ErrorInfo.AddAction(ActionDictionary.Get('Caption'), CodeunitId, ActionDictionary.Get('MethodName'));
end;

procedure OpenNoSeriesRelationships(ErrorInfo: ErrorInfo)
var
NoSeriesLines: Record "No. Series Line";
begin
NoSeriesLines.SetRange("Series Code", ErrorInfo.CustomDimensions.Get(NoSeriesCodeTok));
Page.Run(Page::"No. Series Relationships", NoSeriesLines);
end;

procedure OpenNoSeries(ErrorInfo: ErrorInfo)
var
NoSeries: Record "No. Series";
begin
if ErrorInfo.CustomDimensions.Get(NoSeriesCodeTok) <> '' then
NoSeries.SetRange(Code, ErrorInfo.CustomDimensions.Get(NoSeriesCodeTok));
Page.Run(Page::"No. Series", NoSeries);
end;

procedure OpenNoSeriesLines(ErrorInfo: ErrorInfo)
var
NoSeriesLines: Record "No. Series Line";
begin
if ErrorInfo.CustomDimensions.ContainsKey(NoSeriesCodeTok) then
NoSeriesLines.SetRange("Series Code", ErrorInfo.CustomDimensions.Get(NoSeriesCodeTok))
else
if ErrorInfo.RecordId().TableNo = Database::"No. Series Line" then begin
NoSeriesLines.Get(ErrorInfo.RecordId());
NoSeriesLines.SetRange("Series Code", NoSeriesLines."Series Code");
end;

Page.Run(Page::"No. Series Lines", NoSeriesLines);
end;

local procedure UserCanEditNoSeries(): Boolean
var
NoSeries: Record "No. Series";
begin
exit(NoSeries.WritePermission());
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ page 457 "No. Series Lines"
{
Caption = 'Starting No.';
ToolTip = 'Specifies the first number in the series.';
ShowMandatory = true;
}
field("Ending No."; Rec."Ending No.")
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ codeunit 299 "No. Series - Setup"
end;

/// <summary>
/// Increments the given No. by the sepcified Increment.
/// Increments the given No. by the specified Increment.
/// </summary>
/// <param name="No">The number, as a code string to increment</param>
/// <param name="Increment">Indicates by how much to increment the No.</param>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ codeunit 305 "No. Series - Setup Impl."
#if not CLEAN24
#pragma warning disable AL0432
NoSeriesManagement: Codeunit NoSeriesManagement;
#pragma warning restore AL0432
#endif
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
#if not CLEAN24
#pragma warning disable AL0432
IsHandled: Boolean;
#pragma warning restore AL0432
#endif
Expand All @@ -210,7 +215,7 @@ codeunit 305 "No. Series - Setup Impl."
#endif
if NewNo <> '' then begin
if IncStr(NewNo) = '' then
Error(UnIncrementableStringErr, NewFieldCaption);
NoSeriesErrorsImpl.Throw(StrSubstNo(UnIncrementableStringErr, NewFieldCaption), NoSeriesLine, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
NoSeriesLine2 := NoSeriesLine;
if NewNo = GetNoText(NewNo) then
Length := 0
Expand All @@ -228,9 +233,7 @@ codeunit 305 "No. Series - Setup Impl."
if (NewFieldCaption <> NoSeriesLine.FieldCaption("Last No. Used")) and
(NoSeriesLine."Last No. Used" <> NoSeriesLine2."Last No. Used")
then
Error(
NumberFormatErr,
NewFieldCaption, NoSeriesLine.FieldCaption("Last No. Used"));
NoSeriesErrorsImpl.Throw(StrSubstNo(NumberFormatErr, NewFieldCaption, NoSeriesLine.FieldCaption("Last No. Used")), NoSeriesLine, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
end;
end;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,14 @@ codeunit 304 "No. Series - Impl."
TestManualInternal(NoSeriesCode, StrSubstNo(PostErr, DocumentNo));
end;

local procedure TestManualInternal(NoSeriesCode: Code[20]; ErrorText: Text);
local procedure TestManualInternal(NoSeriesCode: Code[20]; ErrorText: Text)
var
NoSeries: Record "No. Series";
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
begin
NoSeries.Get(NoSeriesCode);
if not NoSeries."Manual Nos." then
Error(ErrorText);
NoSeriesErrorsImpl.Throw(ErrorText, NoSeriesCode, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
end;

procedure IsManual(NoSeriesCode: Code[20]): Boolean
Expand Down Expand Up @@ -150,6 +151,7 @@ codeunit 304 "No. Series - Impl."
var
NoSeriesRec: Record "No. Series";
NoSeries: Codeunit "No. Series";
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
LineFound: Boolean;
begin
if UsageDate = 0D then
Expand Down Expand Up @@ -186,10 +188,11 @@ codeunit 304 "No. Series - Impl."
// Throw an error depending on the reason we couldn't find a date
if HideErrorsAndWarnings then
exit(false);

NoSeriesLine.SetRange("Starting Date");
if not NoSeriesLine.IsEmpty() then
Error(CannotAssignNewOnDateErr, NoSeriesCode, UsageDate);
Error(CannotAssignNewErr, NoSeriesCode);
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignNewOnDateErr, NoSeriesCode, UsageDate), NoSeriesCode, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignNewErr, NoSeriesCode), NoSeriesCode, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
end;

// If Date Order is required for this No. Series, make sure the usage date is not before the last date used
Expand All @@ -198,7 +201,7 @@ codeunit 304 "No. Series - Impl."
if NoSeriesRec."Date Order" and (UsageDate < NoSeriesLine."Last Date Used") then begin
if HideErrorsAndWarnings then
exit(false);
Error(CannotAssignNewBeforeDateErr, NoSeriesRec.Code, NoSeriesLine."Last Date Used");
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignNewBeforeDateErr, NoSeriesRec.Code, NoSeriesLine."Last Date Used"), NoSeriesLine, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
end;
exit(true);
end;
Expand Down Expand Up @@ -257,9 +260,19 @@ codeunit 304 "No. Series - Impl."
end;

procedure TestAreRelated(DefaultNoSeriesCode: Code[20]; RelatedNoSeriesCode: Code[20])
var
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
begin
if not AreRelated(DefaultNoSeriesCode, RelatedNoSeriesCode) then
Error(SeriesNotRelatedErr, DefaultNoSeriesCode, RelatedNoSeriesCode);
NoSeriesErrorsImpl.Throw(StrSubstNo(SeriesNotRelatedErr, DefaultNoSeriesCode, RelatedNoSeriesCode), DefaultNoSeriesCode, NoSeriesErrorsImpl.OpenNoSeriesRelationshipsAction());
end;

procedure OpenNoSeriesRelationships(ErrorInfo: ErrorInfo)
var
NoSeriesLines: Record "No. Series Line";
begin
NoSeriesLines.SetRange("Series Code", ErrorInfo.CustomDimensions.Get('DefaultNoSeriesCode'));
Page.Run(Page::"No. Series Relationships", NoSeriesLines);
end;

procedure AreRelated(DefaultNoSeriesCode: Code[20]; RelatedNoSeriesCode: Code[20]): Boolean
Expand All @@ -270,8 +283,7 @@ codeunit 304 "No. Series - Impl."
if not NoSeries.Get(DefaultNoSeriesCode) then
exit(false);

if not NoSeries."Default Nos." then
Error(CannotAssignAutomaticallyErr, NoSeries.FieldCaption("Default Nos."), NoSeries.TableCaption(), NoSeries.Code);
TestAutomatic(NoSeries);

if DefaultNoSeriesCode = RelatedNoSeriesCode then
exit(true);
Expand All @@ -291,9 +303,20 @@ codeunit 304 "No. Series - Impl."
procedure TestAutomatic(NoSeriesCode: Code[20])
var
NoSeries: Record "No. Series";
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
begin
if not IsAutomaticNoSeries(NoSeriesCode) then
Error(CannotAssignAutomaticallyErr, NoSeries.FieldCaption("Default Nos."), NoSeries.TableCaption(), NoSeries.Code);
if not NoSeries.Get(NoSeriesCode) then
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignAutomaticallyErr, NoSeries.FieldCaption("Default Nos."), NoSeries.TableCaption(), NoSeriesCode), '', NoSeriesErrorsImpl.OpenNoSeriesAction());

TestAutomatic(NoSeries);
end;

local procedure TestAutomatic(NoSeries: Record "No. Series")
var
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
begin
if not NoSeries."Default Nos." then
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignAutomaticallyErr, NoSeries.FieldCaption("Default Nos."), NoSeries.TableCaption(), NoSeries.Code), NoSeries.Code, NoSeriesErrorsImpl.OpenNoSeriesAction());
end;

procedure SelectRelatedNoSeries(OriginalNoSeriesCode: Code[20]; DefaultHighlightedNoSeriesCode: Code[20]; var NewNoSeriesCode: Code[20]): Boolean
Expand Down Expand Up @@ -332,12 +355,14 @@ codeunit 304 "No. Series - Impl."
end;

local procedure ValidateCanGetNextNo(var NoSeriesLine: Record "No. Series Line"; SeriesDate: Date; HideErrorsAndWarnings: Boolean): Boolean
var
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
begin
if SeriesDate < NoSeriesLine."Starting Date" then
if HideErrorsAndWarnings then
exit(false)
else
Error(CannotAssignNewBeforeDateErr, NoSeriesLine."Series Code", NoSeriesLine."Starting Date");
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignNewBeforeDateErr, NoSeriesLine."Series Code", NoSeriesLine."Starting Date"), NoSeriesLine, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());

exit(true);
end;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ codeunit 307 "No. Series - Sequence Impl." implements "No. Series - Single"
exit(NumberCode);
end;

internal procedure ExtractNoFromCode(NumberCode: Code[20]): BigInteger
procedure ExtractNoFromCode(NumberCode: Code[20]; NoSeriesCode: Code[20]): BigInteger
var
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
i: Integer;
j: Integer;
Number: BigInteger;
Expand All @@ -166,7 +167,7 @@ codeunit 307 "No. Series - Sequence Impl." implements "No. Series - Single"
i -= 1;
NoCodeSnip := CopyStr(CopyStr(NumberCode, i + 1, j - i), 1, MaxStrLen(NoCodeSnip));
if StrLen(NoCodeSnip) > 18 then
Error(NoOverFlowErr, NumberCode, StrLen(NoCodeSnip));
NoSeriesErrorsImpl.Throw(StrSubstNo(NoOverFlowErr, NoCodeSnip, StrLen(NoCodeSnip)), NoSeriesCode, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
Evaluate(Number, NoCodeSnip);
exit(Number);
end;
Expand Down Expand Up @@ -198,7 +199,7 @@ codeunit 307 "No. Series - Sequence Impl." implements "No. Series - Single"
if Rec.Implementation <> "No. Series Implementation"::Sequence then
exit;

Rec."Starting Sequence No." := ExtractNoFromCode(Rec."Starting No.");
Rec."Starting Sequence No." := ExtractNoFromCode(Rec."Starting No.", Rec."Series Code");
end;

[EventSubscriber(ObjectType::Table, Database::"No. Series Line", 'OnBeforeValidateEvent', 'Increment-by No.', false, false)]
Expand All @@ -212,7 +213,7 @@ codeunit 307 "No. Series - Sequence Impl." implements "No. Series - Single"
// Make sure to keep the last used No. if the No. Series is already in use
LastNoUsed := GetLastNoUsed(Rec);
if LastNoUsed <> '' then
RecreateNoSeriesWithLastUsedNo(Rec, ExtractNoFromCode(LastNoUsed))
RecreateNoSeriesWithLastUsedNo(Rec, ExtractNoFromCode(LastNoUsed, Rec."Series Code"))
else
RecreateNoSeries(Rec, Rec."Starting Sequence No.");
end;
Expand All @@ -228,7 +229,7 @@ codeunit 307 "No. Series - Sequence Impl." implements "No. Series - Single"
if Rec."Last No. Used" = '' then
exit;

SequenceNumber := ExtractNoFromCode(Rec."Last No. Used");
SequenceNumber := ExtractNoFromCode(Rec."Last No. Used", Rec."Series Code");
Rec."Last No. Used" := '';
RecreateNoSeriesWithLastUsedNo(Rec, SequenceNumber);
end;
Expand All @@ -245,9 +246,9 @@ codeunit 307 "No. Series - Sequence Impl." implements "No. Series - Single"
if Rec.Implementation = "No. Series Implementation"::Sequence then begin
LastNoUsed := NoSeries.GetLastNoUsed(xRec);
if LastNoUsed <> '' then
RecreateNoSeriesWithLastUsedNo(Rec, ExtractNoFromCode(LastNoUsed))
RecreateNoSeriesWithLastUsedNo(Rec, ExtractNoFromCode(LastNoUsed, Rec."Series Code"))
else
RecreateNoSeries(Rec, ExtractNoFromCode(Rec."Starting No."));
RecreateNoSeries(Rec, ExtractNoFromCode(Rec."Starting No.", Rec."Series Code"));
Rec."Last No. Used" := '';
end else
if xRec.Implementation = "No. Series Implementation"::Sequence then begin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,13 @@ codeunit 306 "No. Series - Stateless Impl." implements "No. Series - Single"
end;

procedure EnsureLastNoUsedIsWithinValidRange(NoSeriesLine: Record "No. Series Line"; NoErrorsOrWarnings: Boolean): Boolean
var
NoSeriesErrorsImpl: Codeunit "No. Series - Errors Impl.";
begin
if not NoIsWithinValidRange(NoSeriesLine."Last No. Used", NoSeriesLine."Starting No.", NoSeriesLine."Ending No.") then begin
if NoErrorsOrWarnings then
exit(false);
Error(CannotAssignNumbersGreaterThanErr, NoSeriesLine."Ending No.", NoSeriesLine."Series Code", NoSeriesLine."Last No. Used");
NoSeriesErrorsImpl.Throw(StrSubstNo(CannotAssignNumbersGreaterThanErr, NoSeriesLine."Ending No.", NoSeriesLine."Series Code", NoSeriesLine."Last No. Used"), NoSeriesLine, NoSeriesErrorsImpl.OpenNoSeriesLinesAction());
end;

if (NoSeriesLine."Ending No." <> '') and (NoSeriesLine."Warning No." <> '') and (NoSeriesLine."Last No. Used" >= NoSeriesLine."Warning No.") then begin
Expand Down
16 changes: 16 additions & 0 deletions src/BusinessFoundation.code-workspace
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"folders": [
{
"name": "Business Foundation",
"path": "Business Foundation/App"
},
{
"name": "Business Foundation Test Library",
"path": "Business Foundation/Test Library"
},
{
"name": "Business Foundation Tests",
"path": "Business Foundation/Test"
}
]
}
Loading

0 comments on commit a51be6c

Please sign in to comment.