Use the setup table and Singleton Design Pattern
A setup table is one of the core tables of an application area in Microsoft Dynamics 365 Business Central. The setup table provides the settings that define the behavior of the business logic in a specific area of the application. The business logic frequently depends on various configuration settings. Whenever the code decides how to handle a specific situation, it must check the appropriate setting in the setup table.
For example, when users post invoices, the business decision might be that posting is only allowed in a specific period. Instead of hard coding the starting and ending dates in the code, you should add the Allow Posting From and Allow Posting To dates to a setup table. Then, you can change the logic of the code to check whether the Posting Date of the invoice falls between the dates that are specified in the table. This logic simplifies a user's ability to change the periods of allowed posting. This logic is exactly how the General Ledger Setup table controls the posting behavior of any types of documents that affect the General Ledger application area.
At a minimum, setup tables contain the fields for configuring the number series that control the assignment of numbers to master records, documents, and posted documents of the application area. The more master records and document types, the more fields that the setup table contains. An application area can have only one setup record. For that reason, the table has a single primary key field, called Primary Key.
A setup table always has only one page of type Card that shows the information from the table. The setup card must make sure that only one record exists in the table. Therefore, this page always has the InsertAllowed and DeleteAllowed properties set to false. When the user opens the page and no record exists in the setup table, the page typically inserts the setup record.
Singleton Design Pattern
To develop your own setup tables, use the Singleton Design Pattern. A design pattern can be compared with a recipe that helps you, step by step, develop a solution for a common problem. You can find design patterns in other programming languages like C# and Java as well. In an object-oriented language such as C#, you can use the Singleton Design Pattern to have one single instance of an object that is used throughout the application.
A setup table only contains one record and is used across different sessions. Therefore, you can argue that a setup table can be compared with a single instance.
In application language (AL), the Singleton Design Pattern involves three steps:
Create a table and define a primary key. This primary key is:
Named Primary Key and is of type Code with a length of 10.
Populated with a blank value when the record is inserted.
Not added to the page.
Not modifiable, meaning that users can't modify the value of the primary key.
Create a (card) page.
The InsertAllowed and DeleteAllowed properties are set to false. This setting prevents the user from adding/deleting records.
On the OnOpenPage trigger, you need to check if a record already exists in the table. If not, you need to insert a record. This step ensures that one record always exists in the table.
Subscribe to the OnCompanyInitialize publisher of the Company-Initialize codeunit. (Optional)
In the OnRun trigger of the Company-Initialize codeunit, all existing setup tables are checked to determine if a record already exists. If not, a record is created. Because you cannot modify this codeunit, you need to subscribe to the OnCompanyInitialize publisher function to create your own setup table initialization.
This codeunit is run whenever you create a new company in Business Central.
Consider the following code samples. The first example is the table definition of a setup table, where you can see the Primary Key field and other fields that will be used to set the number series that is used in different master and document tables.
table 311 Sales & Receivables Setup
{
Caption = 'Sales & Receivables Setup';
DrillDownPageID = "Sales & Receivables Setup";
LookupPageID = "Sales & Receivables Setup";
fields
{
field(1; "Primary Key"; Code[10])
{
}
...
field(9; "Customer Nos."; Code[20])
{
TableRelation = "No. Series";
}
field(10; "Quote Nos."; Code[20])
{
TableRelation = "No. Series";
}
field(11; "Order Nos."; Code[20])
{
TableRelation = "No. Series";
}
field(12; "Invoice Nos."; Code[20])
{
TableRelation = "No. Series";
}
...
}
keys
{
key(Key1; "Primary Key")
{
Clustered = true;
}
}
}
The Sales & Receivables Setup page is a Card page, with the InsertAllowed and DeleteAllowed properties set to false. The Primary Key field is not available on the page; therefore, it can't be modified by a user. The OnOpenPage trigger contains a check mark if a record is already in the table. If not, the Insert function will create a new record in the table with a blank primary key.
page 459 Sales & Receivables Setup
{
Caption = 'Sales & Receivables Setup';
DeleteAllowed = false;
InsertAllowed = false;
PageType = Card;
SourceTable = "Sales & Receivables Setup";
layout
{
area(content)
{
group(General)
{
field("Discount Posting"; "Discount Posting")
{
}
field("Credit Warnings"; "Credit Warnings")
{
}
...
}
group("Number Series")
{
field("Customer Nos."; "Customer Nos.")
{
}
field("Quote Nos."; "Quote Nos.")
{
}
field("Blanket Order Nos."; "Blanket Order Nos.")
{
}
field("Order Nos."; "Order Nos.")
{
}
field("Return Order Nos."; "Return Order Nos.")
{
}
field("Invoice Nos."; "Invoice Nos.")
{
}
...
}
}
}
trigger OnOpenPage()
begin
Reset();
if not Get() then begin
Init();
Insert();
end;
end;
}
These different steps are defined in the Singleton Design Pattern. Follow those steps to create your own setup tables so that your extension will behave like the default application objects and will create a uniform experience for the user.