Programming Best Practices
This topic describes best practices for developing Dynamics NAV applications.
When you write a solution in Dynamics NAV, keep it simple. This applies to everything that becomes visible either to other programmers or to any users. The following are a few examples.
If the default value for a property is appropriate for a specific purpose, then do not make the default value explicit.
If a variable can be reset with a statement such as
a := 0;then do not use a special C/AL function, such as the CLEAR Function, to reset the variable.
If the contents of a record can be copied with a statement such as
MyRec := MyRec2;then do not use a special C/AL function, such as the TRANSFERFIELDS Function (Record), to copy the contents.
The Rec global variable references the source table of a page. When you refer to fields or functions of that table, you do not need to qualify them with Rec.< field> or Rec.< function>. You use <field> or <function>
If you want to use the value of a field to find a record in a table or if you want to activate an object identified by the field, then ensure that the field contains a value. To do this, use the TESTFIELD Function (Record), as shown in the following example. This produces more informative error messages if the value is zero or blank.
GLEntry.TESTFIELD("Department Code"); Dept.GET(GLEntry."Department Code"); GenJnlTemplate.TESTFIELD("Report ID"); REPORT.RUN(GenJnlTemplate."Report ID")
To set properties from C/AL, use code that is similar to the following code.
"Customer No.".Visible := TRUE; Cust.MARK := TRUE;
Do not use the following code.
Customer." No.".Visible(TRUE); Cust.MARK(TRUE);
When writing lookups in C/AL, do not filter records that the user may want to select. Instead, program the record cursor to be positioned on the most relevant record for the search even though it may not be first on the list. When programming the OnLookup trigger for a field, the code in the field’s OnValidate trigger is not called unless you explicitly call Field.VALIDATE. If errors can occur in the validation, then you must operate on a copy of the Rec variable as shown in the following example instead of directly on the Rec variable.
WITH Cust DO BEGIN Cust := Rec; Dept.Code := "Department Code"; IF PAGE.RUNMODAL(O,Dept) = Action::LookupOK THEN BEGIN "Department Code" := Dept.Code; VALIDATE("Department Code"); Rec := Cust; END; END;
To make Lookup work on a field that has a table relation to a system table, you must always explicitly set the LookupPageID Property on controls that show the field.
Set the LookupPageID Property and DrillDownPageID Property on most tables. You cannot anticipate when a user must activate a Lookup or DrillDown button. For example, if a user creates a report with a filter tab on the table, then the Lookup button on the filter tab will not appear unless the LookupPageID property is set on the table.
Designing Journal Pages
The default order of fields in journals is:
The order of fields in ledger entries should be the same. The order of fields in pages and reports should also be the same.
Laying Out Fields on Pages
This section contains guidelines for which fields to include on the following pages:
For each type of page, consistency is important. Similar pages in the application areas must be composed the same way.
Some card pages are related to a table that contains only a few fields. It is not hard to create such pages because it is often obvious where to place the fields on FastTabs on a page and which fields to promote to the FastTab header. Most card pages are related to tables with many fields.
Many pages use several FastTabs. How many FastTabs are needed and what to call them are specific to each page. The following FastTab names are commonly used:
General, which is the first tab
All relevant fields must be included on a card page. Even card pages with many tabs have a limited space for fields, so you must carefully consider relevancy. Which fields to include depends on the purpose of each page. We recommend using the following guidelines:
Always include dimensions, such as department, project, or location.
Do not include fields that are automatically filled in and do not need to be changed by the user.
Do not place the same field on a page twice, even on different tabs.
If two or more fields are related according to source or function, then group them.
On which FastTab to place a field depends on the specific page. Some fields are used on many pages. For consistency, place the following fields on the General FastTab:
Last Date Modified
Other information about the account
Place the following fields on the Posting or Invoicing FastTab:
General Business Posting Group
General Product Posting Group
Posting group from the actual application area
In general, all fields are included on worksheet pages. Some exceptions are mentioned in the following section. The fields are shown or hidden depending on how relevant they are and what the layout of the page is. You must consider the following points when you create worksheet pages:
Always include dimensions, such as department or project. The fields should be hidden.
Do not include FlowFields on worksheet pages unless the page is seldom used or the field is essential. FlowFields are calculated even when they are hidden.
Do not include more than about 25 fields on a page because this can affect performance. Consider carefully which fields, both hidden and visible, that you will include on a page. Because of performance considerations, worksheet pages should not include fields that may be informative but cannot be changed, such as Posting Group, Journal Name, Weights, and Source Type.
Never include fields that are used internally in the program, such as Closed by Entry No.
Use worksheet pages for all page in the Setup menu. Creating these page does not typically cause problems because they often contain only a code and a few information fields.
Pages such as journals, sales/purchase lines, and ledgers are difficult to create and maintain properly because the related tables contain a lot of functionality and many fields. In an uncustomized application, the same template is used to compose these pages so that they look similar. The following table shows the template. It is divided into sections according to functionality. In each section, the most common field names are mentioned.
The table does not include all functionality. Additionally, the order that is indicated in the table does not always indicate the order in pages.
|Dates||- Posting Date
- Document Date
|Document||- Entry Type
- Document Type
- Document No.
|No. (of Account)||No.|
|Dimensions||- Department Code
- Project Code
- Business Unit Code
- Location Code
- Salesperson/Purchaser Code
- Work Type Code
- Phase Code
- Task Code
- Step Code
|Currency||- Currency Code
- Exchange Rate
|General Posting Setup||- General Posting Type
- General Business Posting Group
- General Product Posting Group
- Invoiced Quantity
- Remaining Quantity
- Unit of Measure Code
|Prices/Cost||- Direct Unit Cost
- Indirect Cost %
- Unit Cost
- Total Cost
- Profit %
- Unit Price
- Total Price
- Price Group Code
- Chargeable Note: The exact name and order depend on the application area.
- Amount Including VAT
- VAT Amount
- Remaining Amount Note: Amounts in LCY must follow each amount type.
|Balancing Account||Balancing Account Type
Balancing Account No.
Balancing General Posting Type
Balancing General Business Posting Group
Balancing General Product Posting Group
|Sales/Purchase and Discount||- Sales/Purchase (LCY)
- Profit (LCY)
- Line Discount %
- Line Discount Amount
- Allow Invoice Discount
- Invoice Discount Amount
|Payment Terms||- Payment Terms Code
- Due Date
- Payment Discount Date
- Payment Discount %
|Application||- Serial No.
- Applies-To Document Type
- Applies-To Document No.
- Applies-To ID
- Applies-To Item Entry
- Applies-To Entry
- Apply and Close (Job)
|Miscellaneous Information||- Cost Is Adjusted
- Cost Posted to G/L
- On Hold
- Bank Payment Type
|Intrastat||- Transaction Type
- Transport Method
- Country/Region Code
|Posting Information||- Quantity to Ship
- Quantity Shipped
- Quantity to Invoice
- Quantity Invoiced
|Audit Information||- User ID
- Source Code
- Reason Code
- Entry No.
We'd love to hear your thoughts. Choose the type you'd like to provide:
Our feedback system is built on GitHub Issues. Read more on our blog.