Skip to content

Commit c63a456

Browse files
authored
GetNextNo should error when line is closed, not take a number from an earlier line (#1406)
<!-- Thank you for your contribution to BCApps! For newcomers, please ensure you've read our [Pull Request Guidelines](https://github.com/microsoft/BCApps/Contributing.md). --> ### Summary This PR addresses a bug in the `GetNoSeriesLine` function where it failed to properly handle closed lines. Previously, if a line for a specific month was closed, the system would incorrectly issue a number from a prior month instead of signaling an error. This fix ensures that an error is thrown as expected in such scenarios, aligning with the intended behavior when dealing with closed series lines. ### Work Item - Fixes [AB#538011](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/538011)
1 parent c1061d9 commit c63a456

File tree

3 files changed

+141
-8
lines changed

3 files changed

+141
-8
lines changed

src/Business Foundation/App/NoSeries/src/Single/NoSeriesImpl.Codeunit.al

+6-6
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ codeunit 304 "No. Series - Impl."
168168
NoSeriesLine2.SetCurrentKey("Series Code", "Starting Date");
169169
NoSeriesLine2.SetRange("Series Code", NoSeriesCode);
170170
NoSeriesLine2.SetRange("Starting Date", 0D, UsageDate);
171-
NoSeriesLine2.SetRange(Open, true);
172171
#if not CLEAN24
173172
#pragma warning disable AL0432
174173
NoSeriesManagement.RaiseObsoleteOnNoSeriesLineFilterOnBeforeFindLast(NoSeriesLine2);
@@ -204,17 +203,18 @@ codeunit 304 "No. Series - Impl."
204203

205204
if LineFound and NoSeries.MayProduceGaps(NoSeriesLine) then begin
206205
NoSeriesLine.Validate(Open);
207-
if not NoSeriesLine.Open then begin
206+
if not NoSeriesLine.Open then
208207
NoSeriesLine.Modify(true);
209-
exit(GetNoSeriesLine(NoSeriesLine, NoSeriesCode, UsageDate, HideErrorsAndWarnings));
210-
end;
211208
end;
212209

213210
if LineFound then begin
214211
// There may be multiple No. Series Lines for the same day, so find the first one.
212+
NoSeriesLine.SetRange(Open, true);
215213
NoSeriesLine.SetRange("Starting Date", NoSeriesLine."Starting Date");
216-
NoSeriesLine.FindFirst();
217-
end else begin
214+
LineFound := NoSeriesLine.FindFirst();
215+
end;
216+
217+
if not LineFound then begin
218218
// Throw an error depending on the reason we couldn't find a date
219219
if HideErrorsAndWarnings then
220220
exit(false);
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
namespace Microsoft.Test.Foundation.NoSeries;
22
using System.TestLibraries.Utilities;
3-
3+
#if not CLEAN24
4+
using Microsoft.Foundation.NoSeries;
5+
#endif
46
permissionset 134530 "No. Series Test"
57
{
68
Assignable = true;
9+
#if not CLEAN24
10+
Permissions = codeunit "Library Assert" = X,
11+
tabledata "No. Series Line" = m;
12+
#else
713
Permissions = codeunit "Library Assert" = X;
14+
#endif
15+
816
}

src/Business Foundation/Test/NoSeries/src/NoSeriesTests.Codeunit.al

+126-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ codeunit 134530 "No. Series Tests"
1818
Any: Codeunit Any;
1919
LibraryAssert: Codeunit "Library Assert";
2020
LibraryNoSeries: Codeunit "Library - No. Series";
21-
CannotAssignNewErr: Label 'You cannot assign new numbers from the number series %1.', Comment = '%1=No. Series Code';
21+
CannotAssignNewErr: Label 'You cannot assign new numbers from the number series %1', Comment = '%1=No. Series Code';
2222

2323
#region sequence
2424
[Test]
@@ -275,6 +275,69 @@ codeunit 134530 "No. Series Tests"
275275
asserterror NoSeries.PeekNextNo(NoSeriesCode);
276276
LibraryAssert.ExpectedError(StrSubstNo(CannotAssignNewErr, NoSeriesCode));
277277
end;
278+
279+
280+
[Test]
281+
procedure TestGetNextNoWithMultipleLinesExhaustClosedLine_Sequence()
282+
var
283+
NoSeries: Codeunit "No. Series";
284+
PermissionsMock: Codeunit "Permissions Mock";
285+
NoSeriesCode: Code[20];
286+
begin
287+
// [Scenario] [Bug 538011] When we have multiple lines, the GetNextNo should return value from latest line. If there is no number left in the latest line, it should throw an error even there are numbers left in previous line.
288+
// [GIVEN] Initialize the test
289+
Initialize();
290+
PermissionsMock.Set('No. Series - Admin');
291+
292+
// [GIVEN] Create a No. Series
293+
NoSeriesCode := CopyStr(UpperCase(Any.AlphabeticText(MaxStrLen(NoSeriesCode))), 1, MaxStrLen(NoSeriesCode));
294+
LibraryNoSeries.CreateNoSeries(NoSeriesCode);
295+
// [GIVEN] Create the first line with 10 numbers and no start day, and the 'Last No. Used' set to 'TEST0005'
296+
LibraryNoSeries.CreateSequenceNoSeriesLine(NoSeriesCode, 1, 'TEST0001', 'TEST0010', 'TEST0005', 0D);
297+
// [GIVEN] Create the second line with 10 numbers and the start date is today, and the 'Last No. Used' set to 'TEST0039', so only one number is left
298+
LibraryNoSeries.CreateSequenceNoSeriesLine(NoSeriesCode, 1, 'TEST0030', 'TEST0040', 'TEST0039', Today());
299+
300+
PermissionsMock.SetExactPermissionSet('No. Series Test');
301+
302+
// [WHEN] Call GetNextNo and we get the last number from the second Series Line.
303+
LibraryAssert.AreEqual('TEST0040', NoSeries.GetNextNo(NoSeriesCode, Today()), 'Get the last SN from the second Series Line');
304+
// [Then] Call GetNextNo again, and we get an error since the second Series Line is out of SN although the first Series Line still has SN.
305+
asserterror NoSeries.GetNextNo(NoSeriesCode, Today());
306+
LibraryAssert.ExpectedError(StrSubstNo(CannotAssignNewErr, NoSeriesCode));
307+
end;
308+
309+
#if not CLEAN24
310+
#pragma warning disable AL0432
311+
[Test]
312+
procedure TestGetNextNoWithMultipleLinesExhaustClosedLine_Sequence_ObsoleteCode()
313+
var
314+
NoSeriesManagement: Codeunit NoSeriesManagement;
315+
PermissionsMock: Codeunit "Permissions Mock";
316+
NoSeriesCode: Code[20];
317+
begin
318+
// [Scenario] [Bug 538011] When we have multiple lines, the GetNextNo should return value from latest line. If there is no number left in the latest line, it should throw an error even there are numbers left in previous line.
319+
// [GIVEN] Initialize the test
320+
Initialize();
321+
PermissionsMock.Set('No. Series - Admin');
322+
323+
// [GIVEN] Create a No. Series
324+
NoSeriesCode := CopyStr(UpperCase(Any.AlphabeticText(MaxStrLen(NoSeriesCode))), 1, MaxStrLen(NoSeriesCode));
325+
LibraryNoSeries.CreateNoSeries(NoSeriesCode);
326+
// [GIVEN] Create the first line with 10 numbers and no start day, and the 'Last No. Used' set to 'TEST0005'
327+
LibraryNoSeries.CreateSequenceNoSeriesLine(NoSeriesCode, 1, 'TEST0001', 'TEST0010', 'TEST0005', 0D);
328+
// [GIVEN] Create the second line with 10 numbers and the start date is today, and the 'Last No. Used' set to 'TEST0039', so only one number is left
329+
LibraryNoSeries.CreateSequenceNoSeriesLine(NoSeriesCode, 1, 'TEST0030', 'TEST0040', 'TEST0039', Today());
330+
331+
PermissionsMock.SetExactPermissionSet('No. Series Test');
332+
333+
// [WHEN] Call GetNextNo and we get the last number from the second Series Line.
334+
LibraryAssert.AreEqual('TEST0040', NoSeriesManagement.GetNextNo(NoSeriesCode, Today(), true), 'Get the last SN from the second Series Line');
335+
// [Then] Call GetNextNo again, and we get an error since the second Series Line is out of SN although the first Series Line still has SN.
336+
asserterror NoSeriesManagement.GetNextNo(NoSeriesCode, Today(), true);
337+
LibraryAssert.ExpectedError(StrSubstNo(CannotAssignNewErr, NoSeriesCode));
338+
end;
339+
#pragma warning restore AL0432
340+
#endif
278341
#endregion
279342

280343
#region normal
@@ -566,6 +629,68 @@ codeunit 134530 "No. Series Tests"
566629
LibraryAssert.AreEqual(StartingNo, NoSeries.GetNextNo(NoSeriesCode), 'not the first number');
567630
LibraryAssert.AreEqual(IncStr(StartingNo), NoSeries.GetNextNo(NoSeriesCode), 'not the second number');
568631
end;
632+
633+
[Test]
634+
procedure TestGetNextNoWithMultipleLinesExhaustClosedLine()
635+
var
636+
NoSeries: Codeunit "No. Series";
637+
PermissionsMock: Codeunit "Permissions Mock";
638+
NoSeriesCode: Code[20];
639+
begin
640+
// [Scenario] [Bug 538011] When we have multiple lines, the GetNextNo should return value from latest line. If there is no number left in the latest line, it should throw an error even there are numbers left in previous line.
641+
// [GIVEN] Initialize the test
642+
Initialize();
643+
PermissionsMock.Set('No. Series - Admin');
644+
645+
// [GIVEN] Create a No. Series
646+
NoSeriesCode := CopyStr(UpperCase(Any.AlphabeticText(MaxStrLen(NoSeriesCode))), 1, MaxStrLen(NoSeriesCode));
647+
LibraryNoSeries.CreateNoSeries(NoSeriesCode);
648+
// [GIVEN] Create the first line with 10 numbers and no start day, and the 'Last No. Used' set to 'TEST0005'
649+
LibraryNoSeries.CreateNormalNoSeriesLine(NoSeriesCode, 1, 'TEST0001', 'TEST0010', 'TEST0005', 0D);
650+
// [GIVEN] Create the second line with 10 numbers and the start date is today, and the 'Last No. Used' set to 'TEST0039', so only one number is left
651+
LibraryNoSeries.CreateNormalNoSeriesLine(NoSeriesCode, 1, 'TEST0030', 'TEST0040', 'TEST0039', Today());
652+
653+
PermissionsMock.SetExactPermissionSet('No. Series Test');
654+
655+
// [WHEN] Call GetNextNo and we get the last number from the second Series Line.
656+
LibraryAssert.AreEqual('TEST0040', NoSeries.GetNextNo(NoSeriesCode, Today()), 'Get the last SN from the second Series Line');
657+
// [Then] Call GetNextNo again, and we get an error since the second Series Line is out of SN although the first Series Line still has SN.
658+
asserterror NoSeries.GetNextNo(NoSeriesCode, Today());
659+
LibraryAssert.ExpectedError(StrSubstNo(CannotAssignNewErr, NoSeriesCode));
660+
end;
661+
662+
#if not CLEAN24
663+
#pragma warning disable AL0432
664+
[Test]
665+
procedure TestGetNextNoWithMultipleLinesExhaustClosedLine_ObsoleteCode()
666+
var
667+
NoSeriesManagement: Codeunit NoSeriesManagement;
668+
PermissionsMock: Codeunit "Permissions Mock";
669+
NoSeriesCode: Code[20];
670+
begin
671+
// [Scenario] [Bug 538011] When we have multiple lines, the GetNextNo should return value from latest line. If there is no number left in the latest line, it should throw an error even there are numbers left in previous line.
672+
// [GIVEN] Initialize the test
673+
Initialize();
674+
PermissionsMock.Set('No. Series - Admin');
675+
676+
// [GIVEN] Create a No. Series
677+
NoSeriesCode := CopyStr(UpperCase(Any.AlphabeticText(MaxStrLen(NoSeriesCode))), 1, MaxStrLen(NoSeriesCode));
678+
LibraryNoSeries.CreateNoSeries(NoSeriesCode);
679+
// [GIVEN] Create the first line with 10 numbers and no start day, and the 'Last No. Used' set to 'TEST0005'
680+
LibraryNoSeries.CreateNormalNoSeriesLine(NoSeriesCode, 1, 'TEST0001', 'TEST0010', 'TEST0005', 0D);
681+
// [GIVEN] Create the second line with 10 numbers and the start date is today, and the 'Last No. Used' set to 'TEST0039', so only one number is left
682+
LibraryNoSeries.CreateNormalNoSeriesLine(NoSeriesCode, 1, 'TEST0030', 'TEST0040', 'TEST0039', Today());
683+
684+
PermissionsMock.SetExactPermissionSet('No. Series Test');
685+
686+
// [WHEN] Call GetNextNo and we get the last number from the second Series Line.
687+
LibraryAssert.AreEqual('TEST0040', NoSeriesManagement.GetNextNo(NoSeriesCode, Today(), true), 'Get the last SN from the second Series Line');
688+
// [Then] Call GetNextNo again, and we get an error since the second Series Line is out of SN although the first Series Line still has SN.
689+
asserterror NoSeriesManagement.GetNextNo(NoSeriesCode, Today(), true);
690+
LibraryAssert.ExpectedError(StrSubstNo(CannotAssignNewErr, NoSeriesCode));
691+
end;
692+
#pragma warning restore AL0432
693+
#endif
569694
#endregion
570695

571696
#region GetLastNoUsed

0 commit comments

Comments
 (0)