Number Series Examples
Complete working examples demonstrating number series implementation patterns in Business Central.
Example 1: Statistical Accounts (Simple Single Series)
This example extends Microsoft's Statistical Accounts extension to add automatic number series.
Setup Table
table 60700 "BCS Statistical Account Setup"
{
Caption = 'Statistical Account Setup';
DataClassification = ToBeClassified;
DrillDownPageID = "BCS Statistical Account Setup";
LookupPageID = "BCS Statistical Account Setup";
fields
{
field(1; "Primary Key"; Code[10])
{
AllowInCustomizations = Never;
Caption = 'Primary Key';
}
field(2; "Statistical Account Nos."; Code[20])
{
Caption = 'Statistical Account Nos.';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
}
keys
{
key(Key1; "Primary Key")
{
Clustered = true;
}
}
}
Setup Page
page 60700 "BCS Statistical Account Setup"
{
ApplicationArea = Basic, Suite;
Caption = 'Statistical Account Setup';
PageType = Card;
SourceTable = "BCS Statistical Account Setup";
DeleteAllowed = false;
InsertAllowed = false;
UsageCategory = Administration;
layout
{
area(Content)
{
group("Number Series")
{
Caption = 'Number Series';
field("Statistical Account Nos."; Rec."Statistical Account Nos.")
{
ApplicationArea = All;
ToolTip = 'Specifies the number series used for Statistical Accounts.';
}
}
}
}
trigger OnOpenPage()
begin
Rec.Reset();
if not Rec.Get() then begin
Rec.Init();
Rec.Insert();
end;
end;
}
Table Extension
tableextension 60700 "BCS Statistical Account" extends "Statistical Account"
{
fields
{
field(60700; "BCS No. Series"; Code[20])
{
Caption = 'No. Series';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
}
trigger OnBeforeInsert()
begin
if "No." = '' then begin
BCSStatisticalAccountSetup.Get();
BCSStatisticalAccountSetup.TestField("Statistical Account Nos.");
if NoSeries.AreRelated(BCSStatisticalAccountSetup."Statistical Account Nos.", xRec."BCS No. Series") then
"BCS No. Series" := xRec."BCS No. Series"
else
"BCS No. Series" := BCSStatisticalAccountSetup."Statistical Account Nos.";
"No." := NoSeries.GetNextNo("BCS No. Series");
end;
end;
trigger OnBeforeRename()
begin
if "No." = '' then begin
BCSStatisticalAccountSetup.Get();
BCSStatisticalAccountSetup.TestField("Statistical Account Nos.");
if NoSeries.AreRelated(BCSStatisticalAccountSetup."Statistical Account Nos.", Rec."BCS No. Series") then
"BCS No. Series" := Rec."BCS No. Series"
else
"BCS No. Series" := BCSStatisticalAccountSetup."Statistical Account Nos.";
"No." := NoSeries.GetNextNo("BCS No. Series");
end;
end;
procedure AssistEdit(): Boolean
begin
if not BCSStatisticalAccountSetup.Get() then
exit(false);
if NoSeries.LookupRelatedNoSeries(BCSStatisticalAccountSetup."Statistical Account Nos.", xRec."BCS No. Series", "BCS No. Series") then
"No." := NoSeries.GetNextNo("BCS No. Series");
end;
var
BCSStatisticalAccountSetup: Record "BCS Statistical Account Setup";
NoSeries: Codeunit "No. Series";
}
Page Extension
pageextension 60700 "BCS Statistical Account Card" extends "Statistical Account Card"
{
layout
{
modify("No.")
{
trigger OnAssistEdit()
begin
if Rec.AssistEdit() then
CurrPage.Update();
end;
}
}
}
User Experience Flow
- Initial Setup: User opens "BCS Statistical Account Setup" page via search
- Configure Series: User selects "STAT" series for "Statistical Account Nos." field
- Create Account: User opens "Statistical Account Card" and clicks New
- Automatic Numbering: System automatically assigns next number (e.g., STAT-0001) from configured series
- Manual Override: User can manually enter a different number if needed
- AssistEdit: User can press F6 on "No." field to select from related series (e.g., STAT, STAT-MANUAL)
Example 2: Multiple Series per Module
This pattern demonstrates multiple number series in a single setup table for different entity types.
Setup Table
table 60710 "BCS Project Management Setup"
{
Caption = 'Project Management Setup';
DataClassification = ToBeClassified;
fields
{
field(1; "Primary Key"; Code[10])
{
AllowInCustomizations = Never;
Caption = 'Primary Key';
}
field(10; "Internal Project Nos."; Code[20])
{
Caption = 'Internal Project Nos.';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
field(11; "External Project Nos."; Code[20])
{
Caption = 'External Project Nos.';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
field(20; "Task Nos."; Code[20])
{
Caption = 'Task Nos.';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
field(21; "Milestone Nos."; Code[20])
{
Caption = 'Milestone Nos.';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
}
keys
{
key(PK; "Primary Key")
{
Clustered = true;
}
}
}
Table Extension with Conditional Logic
tableextension 60710 "BCS Project" extends "Custom Project Table"
{
fields
{
field(60710; "BCS No. Series"; Code[20])
{
Caption = 'No. Series';
DataClassification = ToBeClassified;
TableRelation = "No. Series";
}
}
trigger OnBeforeInsert()
var
SeriesCode: Code[20];
begin
if "No." = '' then begin
ProjectSetup.Get();
// Select series based on project type
case "Project Type" of
"Project Type"::Internal:
begin
ProjectSetup.TestField("Internal Project Nos.");
SeriesCode := ProjectSetup."Internal Project Nos.";
end;
"Project Type"::External:
begin
ProjectSetup.TestField("External Project Nos.");
SeriesCode := ProjectSetup."External Project Nos.";
end;
end;
if NoSeries.AreRelated(SeriesCode, xRec."BCS No. Series") then
"BCS No. Series" := xRec."BCS No. Series"
else
"BCS No. Series" := SeriesCode;
"No." := NoSeries.GetNextNo("BCS No. Series");
end;
end;
procedure AssistEdit(): Boolean
var
SeriesCode: Code[20];
begin
if not ProjectSetup.Get() then
exit(false);
case "Project Type" of
"Project Type"::Internal:
SeriesCode := ProjectSetup."Internal Project Nos.";
"Project Type"::External:
SeriesCode := ProjectSetup."External Project Nos.";
end;
if NoSeries.LookupRelatedNoSeries(SeriesCode, xRec."BCS No. Series", "BCS No. Series") then begin
"No." := NoSeries.GetNextNo("BCS No. Series");
exit(true);
end;
end;
var
ProjectSetup: Record "BCS Project Management Setup";
NoSeries: Codeunit "No. Series";
}
Key Differences
- Multiple series fields in setup table (Internal, External, Tasks, Milestones)
- Conditional logic in OnBeforeInsert based on record field (Project Type)
- AssistEdit adapts to show appropriate related series based on type
- Single setup page manages all series configurations
Example 3: API Integration with Number Series
Number series can also be used in API scenarios for automatic document numbering.
API Document Numbering
page 60720 "BCS Stat Acc Journal API"
{
APIVersion = 'v2.0';
APIPublisher = 'bcscout';
APIGroup = 'statistical';
EntityCaption = 'Statistical Account Journal Line';
EntitySetCaption = 'Statistical Account Journal Lines';
EntityName = 'statisticalAccountJournalLine';
EntitySetName = 'statisticalAccountJournalLines';
PageType = API;
SourceTable = "Statistical Acc. Journal Line";
DelayedInsert = true;
ODataKeyFields = SystemId;
Extensible = false;
layout
{
area(Content)
{
repeater(Group)
{
field(id; Rec.SystemId)
{
Caption = 'Id';
Editable = false;
}
field(documentNumber; Rec."Document No.")
{
Caption = 'Document Number';
}
// ... other fields
}
}
}
trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
BCSStatAccJournalMgmt.InitializeAPIJournalLine(Rec);
end;
}
API Number Series Management Codeunit
codeunit 60720 "BCS Stat Acc Journal Mgmt"
{
procedure InitializeAPIJournalLine(var StatisticalAccJournalLine: Record "Statistical Acc. Journal Line")
begin
if not BCSStatisticalAccountSetup.Get() then
exit;
if StatisticalAccJournalLine."Journal Template Name" = '' then
StatisticalAccJournalLine."Journal Template Name" := BCSStatisticalAccountSetup."Default API Journal Temp. Name";
if StatisticalAccJournalLine."Journal Batch Name" = '' then
StatisticalAccJournalLine."Journal Batch Name" := BCSStatisticalAccountSetup."Default API Journal Name";
// Automatically assign document number if not provided
if StatisticalAccJournalLine."Document No." = '' then
StatisticalAccJournalLine."Document No." := NoSeries.GetNextNo(BCSStatisticalAccountSetup."Default API Document No.");
end;
var
BCSStatisticalAccountSetup: Record "BCS Statistical Account Setup";
NoSeries: Codeunit "No. Series";
}
API Usage Pattern
POST Request (without document number):
{
"statisticalAccountNo": "STAT-0001",
"amount": 1000,
"postingDate": "2026-03-22"
}
System automatically assigns:
documentNumber: "API-DOC-0001" (from setup)journalTemplateName: Default API templatejournalBatchName: Default API batch
Result: Seamless API integration with automatic document numbering matching BC conventions.
Example 4: Wizard-Based Setup
For complex modules, a setup wizard can guide users through number series configuration.
Setup Wizard Page
page 60730 "BCS Stat Acc Setup Wizard"
{
Caption = 'Statistical Account Setup Wizard';
PageType = NavigatePage;
SourceTable = "BCS Statistical Account Setup";
layout
{
area(content)
{
group(Step1)
{
Caption = 'Welcome';
Visible = Step = Step::Welcome;
group(WelcomeMessage)
{
Caption = '';
InstructionalText = 'This wizard helps you configure number series for Statistical Accounts.';
}
}
group(Step2)
{
Caption = 'Number Series';
Visible = Step = Step::NumberSeries;
field("Statistical Account Nos."; Rec."Statistical Account Nos.")
{
ApplicationArea = All;
ToolTip = 'Specifies the number series used for Statistical Accounts.';
trigger OnValidate()
begin
EnableNextButton();
end;
}
group(SeriesHelp)
{
Caption = '';
InstructionalText = 'Select the number series for automatic numbering. You can create a new series if needed.';
}
}
group(Step3)
{
Caption = 'Finish';
Visible = Step = Step::Finish;
group(FinishMessage)
{
Caption = '';
InstructionalText = 'Setup is complete! You can now create Statistical Accounts with automatic numbering.';
}
}
}
}
actions
{
area(processing)
{
action(ActionBack)
{
Caption = 'Back';
Image = PreviousRecord;
InFooterBar = true;
Enabled = BackEnabled;
trigger OnAction()
begin
NextStep(true);
end;
}
action(ActionNext)
{
Caption = 'Next';
Image = NextRecord;
InFooterBar = true;
Enabled = NextEnabled;
trigger OnAction()
begin
NextStep(false);
end;
}
action(ActionFinish)
{
Caption = 'Finish';
Image = Approve;
InFooterBar = true;
Enabled = FinishEnabled;
trigger OnAction()
begin
FinishAction();
end;
}
}
}
trigger OnOpenPage()
begin
Rec.Reset();
if not Rec.Get() then begin
Rec.Init();
Rec.Insert();
end;
Step := Step::Welcome;
EnableControls();
end;
local procedure NextStep(Backwards: Boolean)
begin
if Backwards then
Step := Step - 1
else
Step := Step + 1;
EnableControls();
end;
local procedure EnableControls()
begin
BackEnabled := Step > Step::Welcome;
NextEnabled := (Step < Step::Finish) and CanGoNext();
FinishEnabled := Step = Step::Finish;
end;
local procedure CanGoNext(): Boolean
begin
case Step of
Step::Welcome:
exit(true);
Step::NumberSeries:
exit(Rec."Statistical Account Nos." <> '');
end;
end;
local procedure EnableNextButton()
begin
EnableControls();
end;
local procedure FinishAction()
begin
Rec.Modify();
CurrPage.Close();
end;
var
Step: Option Welcome,NumberSeries,Finish;
BackEnabled: Boolean;
NextEnabled: Boolean;
FinishEnabled: Boolean;
}
Wizard Benefits
- Guided experience for first-time setup
- Validation at each step before proceeding
- Help text explains each configuration
- Finish action saves settings and closes wizard
Testing Checklist
For all number series implementations, verify:
Automatic Numbering
- Create new record with blank "No." field
- Verify system assigns next number from configured series
- Check series counter increments correctly
Manual Override
- Create new record and manually enter "No."
- Verify system accepts manual number
- Confirm no series counter unchanged (manual entry doesn't consume series number)
AssistEdit Functionality
- Press F6 or click AssistEdit button on "No." field
- Verify lookup shows only related series
- Select different series and confirm new number assigned
Related Series
- Configure related series (e.g., STAT and STAT-MANUAL with relationship)
- Create record using STAT-MANUAL series via AssistEdit
- Verify subsequent records continue using STAT-MANUAL (respects user choice)
Setup Validation
- Clear series field in setup
- Attempt to create new record
- Verify TestField error with clear message
Rename Handling
- Create record with automatic number
- Attempt to rename (if applicable)
- Verify OnBeforeRename trigger handles numbering correctly
API Integration (if applicable)
- POST new record via API without "No."
- Verify automatic numbering works via API
- POST with explicit "No." and verify manual number accepted