Not found
Oops! This page doesn't exist. Try going back to our home page.
From 35e175dacfc052a47431ba908f4ce42e1da50065 Mon Sep 17 00:00:00 2001
From: waldo1001 Oops! This page doesn't exist. Try going back to our home page. Oops! This page doesn't exist. Try going back to our home page. Patterns described to be used with Microsoft Dynamics NAV Patterns described to be used with Microsoft Dynamics NAVNot found
Not found
Author
Author
Categories
Category: Best Practice
3. CAL Coding Guidelines
Categories:
Actions - Images
Categories:
Begin as an 'After Word'
Categories:
Begin-End - Compound Only
Categories:
Binary Operator to Start Line
Categories:
Blank Lines
Categories:
By Reference Parameters
Categories:
CaptionML on System Pages
Categories:
CASE Action
Categories:
Class Coupling
Categories:
Colon usage in CASE
Categories:
Comments inside Curly Brackets
Categories:
Comment Spacing
Categories:
CONFIRM
Categories:
Cyclomatic Complexity
Categories:
Design
Categories:
Encapsulate Local Functionality
Categories:
END ELSE Pair
Categories:
FIELDCAPTION and TABLECAPTION
Categories:
FIELDERROR
Categories:
FINDSET FINDFIRST FINDLAST
Categories:
Global Text Constants
Categories:
Indentation
Categories:
Initialized Variables
Categories:
Internally used DotNet Types
Categories:
Internationalization
Categories:
Keyword Pairs - Indentation
Categories:
Line Start Keywords
Categories:
Localizability
Categories:
Lonely Repeat
Categories:
Maintainability Index
Categories:
MESSAGE and ERROR
Categories:
Named Invocations
Categories:
Nested WITHs
Categories:
One Statement Per Line
Categories:
Parameter Placeholders
Categories:
Readability
Categories:
Separate IF and ELSE
Categories:
Spacing Binary Operators
Categories:
Spacing Brackets and ::
Categories:
Spacing Unary Operators
Categories:
Static Object Invocation
Categories:
Suggested Abbreviations
Categories:
Temporary Variable Naming
Categories:
TextConst Suffixes
Categories:
Unary Operator Line End
Categories:
Unnecessary Compound Parenthesis
Categories:
Unnecessary ELSE
Categories:
Unnecessary Function Parenthesis
Categories:
Unnecessary Separators
Categories:
Unnecessary TRUE/FALSE
Categories:
Unreachable Code
Categories:
Unused Initialized Variables
Categories:
Unused Variables
Categories:
Use Text Constants
Categories:
Using Calcdate
Categories:
Using OptionCaptionML
Categories:
UX
Categories:
Variable Already Scoped
Categories:
Variable Capacity Mismatch
Categories:
Variable Naming
Categories:
Variables Declarations Order
Categories:
WITH Scope Name Collision
Categories:
API Page / Query
Categories:
begin as an afterword
Categories:
Begin-End - Compound Only
Categories:
Binary Operator to Start Line
Categories:
CASE Action on next line
Categories:
Comment Spacing
Categories:
Custom Telemetry
Categories:
DeleteAll
Categories:
end else pair
Categories:
if not then exit
Categories:
IsTemporary record safeguard
Categories:
Keyboard Shortcuts
Categories:
Keyword Pairs - Indentation
Categories:
Line Start Keywords
Categories:
Lonely Repeat
Categories:
Named Invocations
Categories:
One Statement per Line
Categories:
Seperate if and else
Categories:
Spacing Binary Operators
Categories:
Subscriber Codeunits
Categories:
Suggested Abbreviations
Categories:
Title Here
Categories:
Unnecessary else
Categories:
Unnecessary true/false
Categories:
Variable Naming
Categories:
Variables Declarations Order
Categories:
When not to use Blank Lines
Categories:
Category: Best Practice
3. CAL Coding Guidelines
Categories:
Actions - Images
Categories:
Begin as an 'After Word'
Categories:
Begin-End - Compound Only
Categories:
Binary Operator to Start Line
Categories:
Blank Lines
Categories:
By Reference Parameters
Categories:
CaptionML on System Pages
Categories:
CASE Action
Categories:
Class Coupling
Categories:
Colon usage in CASE
Categories:
Comments inside Curly Brackets
Categories:
Comment Spacing
Categories:
CONFIRM
Categories:
Cyclomatic Complexity
Categories:
Design
Categories:
Encapsulate Local Functionality
Categories:
END ELSE Pair
Categories:
FIELDCAPTION and TABLECAPTION
Categories:
FIELDERROR
Categories:
FINDSET FINDFIRST FINDLAST
Categories:
Global Text Constants
Categories:
Indentation
Categories:
Initialized Variables
Categories:
Internally used DotNet Types
Categories:
Internationalization
Categories:
Keyword Pairs - Indentation
Categories:
Line Start Keywords
Categories:
Localizability
Categories:
Lonely Repeat
Categories:
Maintainability Index
Categories:
MESSAGE and ERROR
Categories:
Named Invocations
Categories:
Nested WITHs
Categories:
One Statement Per Line
Categories:
Parameter Placeholders
Categories:
Readability
Categories:
Separate IF and ELSE
Categories:
Spacing Binary Operators
Categories:
Spacing Brackets and ::
Categories:
Spacing Unary Operators
Categories:
Static Object Invocation
Categories:
Suggested Abbreviations
Categories:
Temporary Variable Naming
Categories:
TextConst Suffixes
Categories:
Unary Operator Line End
Categories:
Unnecessary Compound Parenthesis
Categories:
Unnecessary ELSE
Categories:
Unnecessary Function Parenthesis
Categories:
Unnecessary Separators
Categories:
Unnecessary TRUE/FALSE
Categories:
Unreachable Code
Categories:
Unused Initialized Variables
Categories:
Unused Variables
Categories:
Use Text Constants
Categories:
Using Calcdate
Categories:
Using OptionCaptionML
Categories:
UX
Categories:
Variable Already Scoped
Categories:
Variable Capacity Mismatch
Categories:
Variable Naming
Categories:
Variables Declarations Order
Categories:
WITH Scope Name Collision
Categories:
API Page / Query
Categories:
begin as an afterword
Categories:
Begin-End - Compound Only
Categories:
Binary Operator to Start Line
Categories:
CASE Action on next line
Categories:
Comment Spacing
Categories:
Custom Telemetry
Categories:
DeleteAll
Categories:
end else pair
Categories:
if not then exit
Categories:
IsTemporary record safeguard
Categories:
Keyboard Shortcuts
Categories:
Keyword Pairs - Indentation
Categories:
Line Start Keywords
Categories:
Lonely Repeat
Categories:
Named Invocations
Categories:
One Statement per Line
Categories:
Seperate if and else
Categories:
Spacing Binary Operators
Categories:
Subscriber Codeunits
Categories:
Suggested Abbreviations
Categories:
Title Here
Categories:
Unnecessary else
Categories:
Unnecessary true/false
Categories:
Variable Naming
Categories:
Variables Declarations Order
Categories:
When not to use Blank Lines
Categories:
Categories
Categories
Category: Pattern
1. Patterns
Categories:
Sensitive Data Encapsulation
Categories:
Data Encryption
Categories:
Single Point of Access
Categories:
Masked Text
Categories:
SSL in NAV
Categories:
Activity Logs
Categories:
Argument Table
Categories:
Blocked Entity
Categories:
Cached Web Server Calls
Categories:
Conditional Cascading Update
Categories:
Copy Document
Categories:
Create Data from Templates
Categories:
Create URLs to NAV Clients
Categories:
Creating Custom Charts
Categories:
Cross Session Events
Categories:
Cue Table
Categories:
Currently Active Record
Categories:
Data Driven Blocked Entity
Categories:
Data Migration Façade
Categories:
Discovery Event
Categories:
Document
Categories:
Easy Update Of Setup Or Supplementary Information
Categories:
Error Message Processing
Categories:
Extending the Role Center Headlines
Categories:
Feature Localization For Data Structures
Categories:
Hooks
Categories:
Surrogate keys using Autoincrement Pattern
Categories:
In-context Notifications
Categories:
Instructions in the UI
Categories:
Integration of Addresses
Categories:
Journal Error Processing
Categories:
Journal Template Batch Line
Categories:
Master Data
Categories:
Multi-file Download
Categories:
Multi-Page List
Categories:
Multilanguage Application Data
Categories:
NET Exception Handling in CAL
Categories:
No Series
Categories:
Notification Lifecycle Management Pattern
Categories:
Notifications
Categories:
Observer
Categories:
Posting Routine - Select Behavior
Categories:
Product Name
Categories:
Queries
Categories:
Read-once Initialization and Validation
Categories:
Released Entity
Categories:
Report Selection
Categories:
Security
Categories:
SELECT DISTINCT with Queries
Categories:
Setup Specificity Fallback
Categories:
Setup Table
Categories:
Silent File Upload and Download
Categories:
Singleton
Categories:
Singleton Codeunit
Categories:
Singleton Table
Categories:
Standard Journal
Categories:
Temporary Dataset Report
Categories:
Totals and Discounts on Subpages Sales and Purchases
Categories:
Transfer Custom Fields
Categories:
TryFunction NET Exception Handling in CAL
Categories:
Use Queries to Detect Duplicate Records
Categories:
Use Queries to Replace Nested Loops
Categories:
Variant Facade
Categories:
API Register Fieldset
Categories:
Command Queue
Categories:
Delegate API Operation
Categories:
Event Bridge
Categories:
Façade
Categories:
Generic Method
Categories:
No. Series
Categories:
Template Method Pattern
Categories:
Title Here
Categories:
Category: Pattern
1. Patterns
Categories:
Sensitive Data Encapsulation
Categories:
Data Encryption
Categories:
Single Point of Access
Categories:
Masked Text
Categories:
SSL in NAV
Categories:
Activity Logs
Categories:
Argument Table
Categories:
Blocked Entity
Categories:
Cached Web Server Calls
Categories:
Conditional Cascading Update
Categories:
Copy Document
Categories:
Create Data from Templates
Categories:
Create URLs to NAV Clients
Categories:
Creating Custom Charts
Categories:
Cross Session Events
Categories:
Cue Table
Categories:
Currently Active Record
Categories:
Data Driven Blocked Entity
Categories:
Data Migration Façade
Categories:
Discovery Event
Categories:
Document
Categories:
Easy Update Of Setup Or Supplementary Information
Categories:
Error Message Processing
Categories:
Extending the Role Center Headlines
Categories:
Feature Localization For Data Structures
Categories:
Hooks
Categories:
Surrogate keys using Autoincrement Pattern
Categories:
In-context Notifications
Categories:
Instructions in the UI
Categories:
Integration of Addresses
Categories:
Journal Error Processing
Categories:
Journal Template Batch Line
Categories:
Master Data
Categories:
Multi-file Download
Categories:
Multi-Page List
Categories:
Multilanguage Application Data
Categories:
NET Exception Handling in CAL
Categories:
No Series
Categories:
Notification Lifecycle Management Pattern
Categories:
Notifications
Categories:
Observer
Categories:
Posting Routine - Select Behavior
Categories:
Product Name
Categories:
Queries
Categories:
Read-once Initialization and Validation
Categories:
Released Entity
Categories:
Report Selection
Categories:
Security
Categories:
SELECT DISTINCT with Queries
Categories:
Setup Specificity Fallback
Categories:
Setup Table
Categories:
Silent File Upload and Download
Categories:
Singleton
Categories:
Singleton Codeunit
Categories:
Singleton Table
Categories:
Standard Journal
Categories:
Temporary Dataset Report
Categories:
Totals and Discounts on Subpages Sales and Purchases
Categories:
Transfer Custom Fields
Categories:
TryFunction NET Exception Handling in CAL
Categories:
Use Queries to Detect Duplicate Records
Categories:
Use Queries to Replace Nested Loops
Categories:
Variant Facade
Categories:
API Register Fieldset
Categories:
Command Queue
Categories:
Delegate API Operation
Categories:
Event Bridge
Categories:
Façade
Categories:
Generic Method
Categories:
No. Series
Categories:
Template Method Pattern
Categories:
Title Here
Categories:
Remove Begin..End around Single Statements from the Active Editor : removes begin..end around single statement from the current editorRemove Begin..End around Single Statements from the Active Project : removes begin..end around single statement from the current projectRemove Empty Lines from the Active Editor : removes empty duplicate lines from the current editorRemove Empty Lines from the Active Project : removes empty duplicate lines from the current projectCreated by Microsoft, Described by waldo
Always start comments with // followed by one space character.
RowNo += 1000; //Move way below the budget
RowNo += 1000; // Move way below the budget
This section will be cover things that aren’t as simple as Design Patterns, but will help make sure your development is:
Generally, all readability rules are Microsoft style choices only. You can use them to keep consistency with the existing code.
Some guidelines are simply better for performance considerations rather than readability or anything else. In this section, let’s look into some..
All discussion related to Best Practice are to be found on the Github Repo’s Discussion pages, found here
Created by Christian Lenz, Described by Christian Lenz
To increase developer productivity while coding, use keyboard shortcuts that are available in the specific context to execute actions faster.
This is a selection of the community’s favorites (more to come).
Windows
| What | Where | How |
|---|---|---|
| Delete word | Editor | CTRL + Backspace |
VS Code
| What | Where | How |
|---|---|---|
| Switch Tab | Editor | ALT + <Arrow Left/Right> |
| Move Line Up/Down | Editor | ALT + <Arrow Up/Down> |
| Copy Line Below/Above | Editor | ALT + SHIFT + <Arrow Up/Down> |
| Delete Line | Editor | CTRL + X (without selection) |
| Add Selection To Next Match | Editor | CTRL + D |
| Select All Occurences Of Find Match | Editor | CTRL + SHIFT + L |
| Add Cursors To Line Ends | Editor | SHIFT + ALT + I (after selecting lines) |
| Add Cursor Above/Below | Editor | CTRL + ALT + <Arrow Up/Down> |
| Place Multiple Cursors Manually | Editor | ALT + Click |
| Fast Scrolling | Editor | ALT + Mouse Wheel |
| Go To Symbol In File | Editor | CTRL + SHIFT + O |
| Breadcrumbs - Open And Select | Editor | CTRL + SHIFT + . |
| Go Back / Forward | Go To Definition | ALT + <Arrow Left/Right> |
Created by Microsoft, Described by waldo
When calling an object statically use the Object Name, not the Object Id.
Page.RunModal(525, SalesShptLine);
Page.RunModal(Page::"Posted Sales Shipment Lines", SalesShptLine);
The BusinessCentral.LinterCop extension adds a new rule to check your code for hardcoded object IDs.
Created by waldo, Described by waldo
In general, subscribers have to be put in codeunits. There are a few performance considerations that you should keep in the back of your minds, when designing such a codeunit.
Let’s discuss all points
Every time a subscriber gets called, a new instance of the codeunit is being loaded in memory, which takes memory and processing power. The smaller the codeunit, the less memory, and the faster it is.
Therefore, it’s suggested to split the subscribers by functionality and avoid putting business logic in the actual codeunit. Tip: put all business logic in an “Method Codeunit”.
Examples:
codeunit 2037325 "Setup Subs"
+ Create project issueCreated by waldo, Described by waldo
In general, subscribers have to be put in codeunits. There are a few performance considerations that you should keep in the back of your minds, when designing such a codeunit.
Let’s discuss all points
Every time a subscriber gets called, a new instance of the codeunit is being loaded in memory, which takes memory and processing power. The smaller the codeunit, the less memory, and the faster it is.
Therefore, it’s suggested to split the subscribers by functionality and avoid putting business logic in the actual codeunit. Tip: put all business logic in an “Method Codeunit”.
Examples:
codeunit 2037325 "Setup Subs"
{
SingleInstance = true;
@@ -134,8 +134,8 @@ Keep the codeunit as small as possible Every time a subscriber gets called, a ne
if JustSomeTable.Color = 'RED' then
UnbindSubscription(DemoSubs);
until JustSomeTable.Next() < 1;
-The reason for this is, that it breaks the batch-calls:
Avoid subscribers to these events.
The reason for this is, that it breaks the batch-calls:
Avoid subscribers to these events.
Created by Microsoft, Described by waldo
Whenever possible, do not use abbreviations in variables, functions and objects names.
If there is no other choice, then use the suggestions below.
| word | Abbreviation |
|---|---|
| absence | Abs |
| account | Acc |
| accounting | Acc |
| accumulated | Accum |
| action | Act |
| activity | Activ |
| additional | Add |
| address | Addr |
| adjust | Adj |
| adjusted | Adjd |
| adjustment | Adjmt |
| agreement | Agrmt |
| allocation | Alloc |
| allowance | Allow |
| alternative | Alt |
| amount | Amt |
| amounts | Amts |
| answer | Ans |
| applies | Appl |
| application | Appln |
| arrival | Arriv |
| assembly | Asm |
| assemble to order | ATO |
| assignment | Assgnt |
| associated | Assoc |
| attachment | Attmt |
| authorities | Auth |
| automatic | Auto |
| availability | Avail |
| average | Avg |
| ba db. | BA |
| balance | Bal |
| bill of materials | BOM |
| blanket | Blnkt |
| budget | Budg |
| buffer | Buf |
| business | Bus |
| business interaction management | BIM |
| buying | Buy |
| calculate | Calc |
| calculated | Calcd |
| calculation | Calcu |
| calendar | Cal |
| capacity | Cap |
| capacity requirements planning | CRP |
| cash flow | CF |
| cashflow | CF |
| catalog | ctlg |
| category | Cat |
| Central Processing Unit | CPU |
| center | Ctr |
| change | Chg |
| changes | Chgs |
| character | Char |
| characters | Chars |
| charge | Chrg |
| charges | Chrgs |
| check | Chk |
| classification | Class |
| collection | coll |
| column | col |
| comment | Cmt |
| company | Co |
| component | Comp |
| completion | Cmpltn |
| components | Comps |
| composition | Compn |
| compression | Compr |
| concurrent | Concrnt |
| confidential | Conf |
| confirmation | Cnfrmn |
| conflict | Confl |
| consolidate | Consol |
| consolidation | Consolid |
| consumption | Consump |
| contact | Cont |
| container | Cntr |
| contract | Contr |
| contracted | Contrd |
| control | Ctrl |
| controls | Ctrls |
| conversion | Conv |
| correction | Cor |
| correspondence | Corres |
| corresponding | Corresp |
| cost | Cst |
| sold | COGS |
| credit | Cr |
| cumulate | Cumul |
| currency | Curr |
| current | Crnt |
| customer | Cust |
| customer/vendor | CV |
| daily | Dly |
| dampener | Damp |
| database management system | DBMS |
| date | D |
| definition | Def |
| demonstration | Demo |
| department | Dept |
| department/project | DP |
| depreciation | Depr |
| description | Desc |
| detail | Dtl |
| detailed | Dtld |
| details | Dtls |
| deviation | Dev |
| difference | Diff |
| dimension | Dim |
| direct | Dir |
| discount | Disc |
| discrete | Discr |
| distribute | Distr |
| distributed | Distrd |
| distributor | Distbtr |
| distribution | Distrn |
| document | Doc |
| duplicate | Dupl |
| entered | Entrd |
| engineering | Engin |
| exchange | Exch |
| excluding | Excl |
| execute | Exec |
| expected | Expd |
| expedited | Exped |
| expense | Exp |
| expression | Expr |
| expiration | Expir |
| extended | Ext |
| explode | Expl |
| export | Expt |
| final | Fnl |
| finance | Fin |
| fiscal | Fisc |
| finished | Fnshd |
| fixed asset | FA |
| forward | Fwd |
| freight | Frt |
| general | Gen |
| general ledger | GL |
| group | Gr |
| header | Hdr |
| history | Hist |
| holiday | Hol |
| human resource | HR |
| identification | ID |
| import | Imp |
| inbound | Inbnd |
| including | Incl |
| included | Incld |
| incoming | Incmg |
| independent software vendor | ISV |
| industry | Indust |
| information | Info |
| initial | Init |
| Intrastat | Intra |
| interaction | Interact |
| integration | Integr |
| interest | Int |
| Interim | Intm |
| internal protocol | IP |
| inventory | Invt |
| inventoriable | Invtbl |
| invoice | Inv |
| invoiced | Invd |
| item tracking | IT |
| journal | Jnl |
| language | Lang |
| ledger | Ledg |
| level | Lvl |
| line | Ln |
| list | Lt |
| local currency | LCY |
| location | Loc |
| mailing | |
| maintenance | Maint |
| management | Mgt |
| manual | Man |
| manufacturing | Mfg |
| manufacturer | Mfr |
| material | Mat |
| marketing | Mktg |
| maximum | Max |
| measure | Meas |
| message | Msg |
| minimum | Min |
| miscellaneous | Misc |
| modify | Mod |
| month | Mth |
| negative | Neg |
| non-inventoriable | NonInvtbl |
| notification | Notif |
| number | No |
| numbers | Nos |
| object | Obj |
| operating | Oper |
| opportunity | Opp |
| order | Ord |
| orders | Ords |
| original | Orig |
| organization | Org |
| outbound | Outbnd |
| Outgoing | Outg |
| output | Out |
| outstanding | Outstd |
| overhead | Ovhd |
| payment | Pmt |
| percent | Pct |
| personnel | Persnl |
| physical | Phys |
| picture | Pic |
| planning | Plng |
| posted | Pstd |
| posting | Post |
| positive | Pos |
| precision | Prec |
| prepayment | Prepmt |
| product | Prod |
| production | Prod |
| production order | ProdOrd |
| project | Proj |
| property | Prop |
| prospect | Prspct |
| purchase | Purch |
| purchases | Purch |
| purchaser | Purchr |
| purchase order | PurchOrd |
| quality | Qlty |
| quantity | Qty |
| questionnaire | Questn |
| quote | Qte |
| radio frequency | RF |
| range | Rng |
| receipt | Rcpt |
| received | Rcd |
| record | Rec |
| records | Recs |
| reconcile | Recncl |
| reconciliation | Recon |
| recurring | Recur |
| reference | Ref |
| register | Reg |
| registration | Regn |
| registered | Regd |
| relation | Rel |
| relations | Rels |
| relationship | Rlshp |
| release | Rlse |
| released | Rlsd |
| remaining | Rem |
| reminder | Rmdr |
| replacement | Repl |
| replenish | Rplnsh |
| replenishment | Rplnsht |
| report | Rpt |
| represent | Rep |
| represented | Repd |
| request | Rqst |
| required | Reqd |
| requirement | Reqt |
| requirements | Reqts |
| requisition | Req |
| reserve | Rsv |
| reserved | Rsvd |
| reservation | Reserv |
| resolution | Resol |
| resource | Res |
| response | Rsp |
| responsibility | Resp |
| retain | Rtn |
| retained | Rtnd |
| return | Ret |
| returns | Rets |
| revaluation | Revaln |
| reverse | Rev |
| review | Rvw |
| round | Rnd |
| rounded | Rndd |
| rounding | Rndg |
| route | Rte |
| routing | Rtng |
| routine | Rout |
| sales & receivables | Sales |
| safety | Saf |
| schedule | Sched |
| second | Sec |
| segment | Seg |
| select | Sel |
| selection | Selctn |
| sequence | Seq |
| serial | Ser |
| serial number | SN |
| service | Serv |
| sheet | Sh |
| shipment | Shpt |
| source | Src |
| special | Spcl |
| specification | Spec |
| specifications | Specs |
| standard | Std |
| frequency | SF |
| statement | Stmt |
| statistical | Stat |
| statistics | Stats |
| stock | Stk |
| stockkeeping unit | SKU |
| stream | Stm |
| structured query language | SQL |
| subcontract | Subcontr |
| subcontracted | Subcontrd |
| subcontracting | Subcontrg |
| substitute | Sub |
| substitution | Subst |
| suggest | Sug |
| suggested | Sugd |
| suggestion | Sugn |
| summary | Sum |
| suspended | Suspd |
| symptom | Sympt |
| synchronize | Synch |
| temporary | Temp |
| total | Tot |
| transaction | Transac |
| transfer | Trans |
| translation | Transln |
| tracking | Trkg |
| troubleshoot | Tblsht |
| troubleshooting | Tblshtg |
| unit of measure | UOM |
| unit test | UT |
| unrealized | Unreal |
| unreserved | Unrsvd |
| update | Upd |
| valuation | Valn |
| value | Val |
| value added tax | VAT |
| variance | Var |
| vendor | Vend |
| warehouse | Whse |
| web shop | WS |
| worksheet | Wksh |
| g/l | GL |
| % | Pct |
| 3-tier | Three-Tier |
| Outlook Synch | Osynch |
Sort Variables in the Active Editor : sorts variables in the current editorSort Variables in the Active Project : sorts variables in the current projectAL Guidelines is a community project, and as such YOU are encouraged to submit corrections and new ideas. In order to get your content included, you must submit a pull request to the GitHub Repository (Located here: https://github.com/microsoft/alguidelines). All Pull Requests are subject to approval by a minimum of three admins.
If You are toying with an idea, but You aren’t ready to create a document just yet, you are encouraged to create a project discussion thread here: https://github.com/microsoft/alguidelines/discussions
This is a warning. If You haven’t worked in collaboration with “external” GitHub repositories before, please familiarize yourself with that process by visiting:
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests
Now that You have decided that You are ready to contribute, these are the steps to take.
You can read more about this process here:
https://docs.github.com/en/get-started/quickstart/contributing-to-projects
In order to work on the repository, You must Fork the repository.
By forking the repository, You essentially create a copy into Your own account.
Start by going to the GitHub Repository (https://github.com/microsoft/alguidelines), and press the Fork 
Once You have successfully forked the repository, go to your own GitHub repository : 
You are now able to clone your own repository to your local pc and start editing using your favorite editor. Visual Studio Code is perfectly fine for this task.
You can read more about forking here:
https://docs.github.com/en/get-started/quickstart/fork-a-repo
While not necessarily a must, it is always good practice to create a branch off of your forked repository. That will allow you to work on multiple contributions at the same time and won’t have to wait for pull requests to be approved before you can continue on your next contribution.
You can read more about Branches here:
Once you are happy with your contribution, it’s time to create a pull request to propose changes into the main project! This is the final step in producing a fork of someone else’s project, and arguably the most important. If you’ve made a change that you feel would benefit the community as a whole, you should definitely consider contributing back.
To do so, head on over to the repository on GitHub where your project lives. For this example, it would be at https://www.github.com/<your_username>/alguidelines. You’ll see a banner indicating that your branch is one commit ahead of microsoft:main. Click Contribute and then Open a pull request.
GitHub will bring you to a page that shows the differences between your fork and the microsoft/alguidelines repository. Click Create pull request.
GitHub will bring you to a page where you can enter a title and a description of your changes. It’s important to provide as much useful information and a rationale for why you’re making this pull request in the first place. The project owners needs to be able to determine whether your change is as useful to everyone as you think it is. Finally, click Create pull request.
{{< youtube QVOMCYitLEc >}}
makes:
{{< figure src="http://www.waldo.be/wp-content/uploads/2021/11/business-central-logo.png" title="Business Central" >}}
makes:
Business Central
For cases when most of the journal data can be used later (like monthly electricity payments, for example), the user has the possibility to save the current transaction details for later use. See the related pattern, Standard Journal.
By Soren Klemmensen, Partner-Ready-Software & 360 Visibility
The goal of this design pattern is to outline a standard way of creating master data, such as customers, vendors or items, in NAV.
This pattern creates a standard master data entity, listing all necessary prerequisites, attributes and methods to generate a basic version of the data entity.
It is being used for creating a master data entity and can roughly be divided into 2 categories: Business and Product
Examples of Master Data tables are:
Business Data:
Product Data:
Master Data has attributes such as Location, Countries & Item Vendors. These tables are closely related to Master Data tables and are called Supplemental and Subsidiary tables.
Supplemental:
Subsidiary:
Master Data is among other used in journals, posting routines and historic data like ledger entries.
Naming & Conventions
Table & Card Page
Singular
Examples: Customer, Vendor & Item
List Page
Plural if Editable = TRUE.
Singular + “List” if Editable = FALSE.
The data entity has a single primary key field with the following properties:
| Field No. | 1 |
| Name | “No.” |
| Date Type | Code 20 |
Each master data entity has a field which gives a name tag to the data entity carrying the natural name of the entity. This field is called Name if the data entity refers to a living person or an organization, such as a customer or a vendor; it is called Description instead if the data entity does not refer to a person or organization, such as an item. The field has the following properties:
| Name | Name or Description |
| Date Type | Text 50 |
An added benefit of using the Name or Description field naming is that this will be part of the dropdown when looking up based on the table relation.
The table properties of a master data table contain the following entries:
| LookupPageID | A ListType Page referring to the table which is not editable. |
| DrillDownPageID | The same page as defined in the LookupPageID |
| DataCaptionFields | The primary key plus the field which provides the primary name tag for the record. This will typically be the Name or Description field defined earlier. |
We will create an Example table here with a Card and List Page as described above.
First we create the Table with No. as the primary key.
Than we create a non-editable Page called Example List
Than we create an Example Card Page with the following definition
Now we can set the properties of the 2 pages.
First the Example Card Page Properties
Than the Example List Page Properties
Last but not least we set the Table Properties
You can see this pattern used in the following tables & pages:
Business Data:
Product Data:
This pattern should not be used when this is not Master Data.
Patterns that are typically used in connection with the Master Data Pattern could be the “No. Series”, “Address Integration” and/or the “Entity State” design patterns., Master Data are central to almost everything we do, so most patterns connect in one way or another to the Master Data Pattern.
Originally by Bogdana Botez at Microsoft Development Center Copenhagen
Generally, NAV translation refers to the translation of UI elements like captions and user texts (messages on dialogs, warnings, error messages). This translation is done by the Microsoft Dynamics NAV team before releasing the localized version of the product.
But there is one more scenario. In this scenario, Cronus International Ltd., wants to sell a “Fiets” to a Dutch customer, a"Cykel" to a Danish one, and a “Bicicletta” to an Italian customer. All 3 are the same inventory item - and its default name is “Bicycle”. But for reporting, Cronus International Ltd. wants to use the customer language preferences for translating the bicycle’s name.
Sometimes there’s a need to support multiple languages for domestic transactions, too. For example, Switzerland has 4 official languages: German, French, Italian and Romansh, the first 3 of them being supported by NAV.
The example below uses the Item Translation feature of NAV, however, implementations of the same pattern exist for other application areas.
Enter translations for “Bicycle”
In the Windows client, on the bicycle Item card, on the Home ribbon tab, choose Translations.
On the opened page, enter the Danish (language code DAN), the Italian (ITA), and the Dutch (NLD) translations for “Bicycle”.
Set the desired language for the Dutch, Danish, and Italian customers
On the customer card for your 3 customers, in the Foreign Trade FastTab, choose the preferred language for each customer. If no language is specified, then the default item description will be used for items sold or anyhow associated to that customer. If for example, the DAN (Danish) language is specified for the customer, and the “Bicycle” has a translation in Danish, then this translation “Cykel” will be used instead of the default name “Bicycle”.
See the result
After those changes, when the customer (in this case the Danish “Lauritzen Kontormøbler A/S”) transactions a bicycle, the translated description “Cykel” will be displayed on the documents and reports. For example, creating a sales order for this customer with 1 item No. 1000, shows:
Create the translation table
Named “<Entity> Translation” table, where <Entity> is replaced with the name of the actual object being translated. For the Item example above, this table will be named “Item Translation”.
The table definition contains at a minimum:
| Field | Description |
|---|---|
| Entity ID field | For example, Item No. |
| Language Code | Identifies the language of this translation string (for example, “DAN” (Danish), “BGR”(Bulgarian). This is one of the language codes defined in the Languages table. |
| Translation | The translated string. |
The table above has a key composed of the first two fields.
Create the user interface for entering new translations of <Entity>
Some of the NAV implementations of this pattern are:
The Extended Text pattern is a more powerful version of the Multilanguage application data pattern presented in this section. The main differences are:
| Pattern | Multilanguage Application Data | Extended Text |
|---|---|---|
| Supports translation of application data | Yes | Yes |
| Format | Single- or multi-line | Single-line |
| Applies to document type | Can choose which document types are affected. | All document types are affected. |
@@ -134,7 +134,7 @@ When there is a need to use .NET classes within C/AL, one of the main …"> }
}
The DotNet Exception Handler codeunit has been used for the Web service integration required for:
Extend the language support in C/AL to provide a built-in Try-Catch-Finally statement, similar to .NET languages.
When this pattern should not be used: avoid nesting of codeunits. To properly handle the exceptions, you need to use the codeunit as an atomic piece of functionality that may pass or fail without using Codeunit.Run internally.
By Soumya Dutta at Microsoft Development Center Copenhagen
Application developers need to raise a notification on events that are not blocking but do require attention from users. Notifications alert users to issues or information, and let them decide whether to react immediately or finish what they’re doing first.
Application developers have started to use system calls like CONFIRM or MESSAGE to alert or inform users about a condition. These calls interrupt users by displaying a window in the middle of the screen and forcing an immediate response.
Notifications display a message in a blue bar at the top of the workspace, as shown in Figure 1.
Figure 1 - Example of a notification
Notifications alert users to something they probably should act on, but can choose to ignore. For example, a notification might alert someone who is about to invoice a customer for inventory that isn’t available, as shown in Figure 1, but allow them to post the invoice anyway. This is different from an error that prevents someone from posting an invoice without specifying a required field.
In this example, if you choose Details a page opens to show the status of the inventory, as shown in Figure 2.
Figure 2 - Clicking an action in a notification
The code in Figure 3 raises the notification in Figure 1.
COD 311: Item-Check Avail.
CreateAndSendNotification
AvailabilityCheckNotification.ID(GetItemAvailabilityNotificationId);
AvailabilityCheckNotification.MESSAGE(STRSUBSTNO(NotificationMsg,ItemNo));
AvailabilityCheckNotification.SCOPE(NOTIFICATIONSCOPE::LocalScope);
AvailabilityCheckNotification.ADDACTION(DetailsTxt,CODEUNIT::“Item-Check Avail.”,‘ShowNotificationDetails’);
ItemAvailabilityCheck.PopulateDataOnNotification(AvailabilityCheckNotification,ItemNo,UnitOfMeasureCode
,InventoryQty,GrossReq,ReservedReq,SchedRcpt,ReservedRcpt,CurrentQuantity,CurrentReservedQty,
TotalQuantity,EarliestAvailDate);
AvailabilityCheckNotification.SEND;
…
Figure 3 - Raising a notification
The first thing to note is that a new Notification DataType object has been introduced to C/SIDE.
Figure 4. Notification is a new data type
In the code sample in Figure 3, the first line defines the scope. Currently , only the LocalScope is supported.
The ID is an optional parameter for the notification object that tracks the object in communications between the client and the server. Notifications have unique IDs that can be hard coded as GUIDs, as shown in Figure 5. A GUID can be generated using the CREATEGUID system function.
COD 311: Item-Check Avail.
GetItemAvailabilityNotificationId
EXIT(‘2712AD06-C48B-4C20-820E-347A60C9AD00’);
Figure 5. Uniquely identifying a notification
If the call to set ID is skipped, sending the notification creates a new notification with an ID that is generated at run-time instead of updating a notification that is already displayed (if present) with the ID.
Notifications should display a message. This message is set by an assignment call to the MESSAGE parameter of the notification object.
Notifications can display action buttons, as shown in Figure 2 where a button named Details opens the inventory status for the item. To do that, when the button is clicked the ADDACTION method is invoked on the notification object using the following parameters:
Figure shows the method that is called when the action is invoked- ShowNotificationDetails.
COD 311: Item-Check Avail.
ShowNotificationDetails
ItemAvailabilityCheck.InitializeFromNotification(AvailabilityCheckNotification);
ItemAvailabilityCheck.SetHeading(AvailabilityCheckNotification.MESSAGE);
ItemAvailabilityCheck.RUNMODAL;****
Figure 6 - Invoking an action
To show the inventory status using the Availability check page, certain parameters must be initialized. For example, the item number, the unit of measure code, and so on. This is done in the call to InitializeFromNotification method on the page. Figure 7 shows the code for this call.
Page 1872: Item Availability Check
InitializeFromNotification
GET(AvailabilityCheckNotification.GETDATA(‘ItemNo’));
SETRANGE(“No.",AvailabilityCheckNotification.GETDATA(‘ItemNo’));
EVALUATE(TotalQuantity,AvailabilityCheckNotification.GETDATA(‘TotalQuantity’));
EVALUATE(InventoryQty,AvailabilityCheckNotification.GETDATA(‘InventoryQty’));
CurrPage.AvailabilityCheckDetails.PAGE.SetUnitOfMeasureCode(
AvailabilityCheckNotification.GETDATA(‘UnitOfMeasureCode’));
Figure 7 - Fetching parameters from a notification object
Note how GETDATA uses a key to fetch values from the notification object, and how those values are used to initialize the page.
Notifications can include zero, one, or more than one action buttons. More than one action buttons result in multiple ADDACTION calls to the notification object.
Actions use the values set on the notification objects. As shown in Figure 3 and Figure 7, the line that calls the method PopulateDataOnNotification does that. The result is shown in Figure 8.
Page 1872: Item Availability Check
PopulateDataOnNotification
AvailabilityCheckNotification.SETDATA(‘ItemNo’,ItemNo);
AvailabilityCheckNotification.SETDATA(‘UnitOfMeasureCode’,UnitOfMeasureCode);
AvailabilityCheckNotification.SETDATA(‘GrossReq’,FORMAT(GrossReq));
…
Figure 8 - Populating parameters on notifications
The invoked method must be stateless. Therefore, the context for creating the notification should be reproducible by using data that could be a part of the notification object. In this example, the SETDATA method on the notification object passes values for the item number, unit of measure code, and so on, as key value pairs.
The last line in Figure 3 calls SEND to display the notification. If you know the ID of the notification, you can also call RECALL to hide it. However, avoid updating a displayed notification, for example by changing the message, by calling both RECALL and SEND. This makes two server–client calls. Instead, call only SEND. Calling SEND for a notification that is already displayed updates the notification.
By default, all notifications are turned on. However, you can specify the notifications you want to receive, and turn on or turn off some or all of them. For example, if you don’t want to be disturbed or are willing to accept the consequences of ignoring the message. This is unique to notifications.
Figure 9 - The My Notifications page
Additionally, some notifications let you specify the conditions under which they are sent. For example, if you want to be notified when inventory is running low, but only for items you buy from a certain vendor.
The MyNotifications object determines whether notifications are turned on or off. Notifications are isolated from each other by the hard-coded GUID, as discussed in the section titled Identifying a notification. A fixed ID is essential to turning off a notification. The following are ways to achieve this.
Codeunit 311: Item-Check Avail.
OnInitializingNotificationWithDefaultState
MyNotifications.InsertDefaultWithTableNum(GetItemAvailabilityNotificationId,
ItemAvailabilityNotificationTxt,
ItemAvailabilityNotificationDescriptionTxt,
DATABASE::Item);
Figure 10 - Adding a notification to the My Notifications page
You must subscribe to this method and call either InsertDefault or InsertDefaultWithTableNum on the MyNotifications table. Both of these take the ID of the notification, a short description of the notification, and text that provides details about the conditions for the notification. The difference is that the InsertDefaultWithTableNum method takes an additional argument representing the table number if there is specific criteria for when to turn on a notification for a certain table. In this case, the notification can be enabled only for items that the criteria specified in the FilterPage. The FIlterPage is opened from the MyNotifications page.
Figure 11 - Defining filter criteria to turn on a notification
Codeunit 311: Item-Check Avail.
IsItemAvailabilityNotificationEnabled
EXIT(MyNotifications.IsEnabledForRecord(GetItemAvailabilityNotificationId,Item));
Figure 12 - Checking whether notifications are turned on
You may check that the call to this function is made almost as the first step in checking for availability.
The ability to turn notifications on or off is not required. If skipped, the notification is always shown when the condition that triggers it is met, and a user cannot turn it off.
For examples of how these objects are used in Dynamics NAV, look at the code for the following objects:
The following list summarizes best practices for creating notifications:
alguidelines.dev - Business Central Design Patterns
@@ -9,7 +9,7 @@
Create Issue
Discussions
Create project issueA collection of patterns about notifications.
Figure 3: Three sales lines with a notification for each one
Imagine that you’re adding several items to a sales order, and inventory is low for some of the items. Each sales line will send a notification for its item if the quantity to sell is higher than the available inventory. By using dynamically generated notification IDs (CREATEGUID), each notification will not be overwritten, which is what we want. This is shown in Figure 3. But after you see the notification, you may decide to decrease the quantity in the sales line. At that point, the notification should be recalled. To do that, we need a way to track the notifications and their IDs.
Solution
The solution is to use the Notification Lifecycle Management framework.
The framework allows you to keep track of notifications by saving notification IDs and with other useful information (record ID and optional additional context) that will allow you to easily find the notification IDs to recall. This can be seen as an internal dictionary to put and get notification IDs.
This framework has three main components:
A temporary, in-memory table: Notification Context (1519). This table stores each notification GUID, the record ID of the record that caused each notification (on what object), and optionally, an additional GUID that represents an additional context: the cause of the notification (why). This lets you track and recall each notification. You can fire-and-forget the notification, but if you need to recall it you can find it by using the record ID of the cause and the optional additional context ID.
A singleton codeunit: Notification Lifecycle Mgt. (1511), that provides functions to create new notification context lines and recall them. This codeunit contains one instance of the temporary table Notification Context.
A helper codeunit:Notification Lifecycle Helper (1508), that subscribes to various events and makes the calls to the Notification Lifecycle Mgt. codeunit.
The unit tests for this framework are in codeunit Notification Lifecycle Tests (139480).
The main functions provided by codeunit 1511 are:
SendNotification(NotificationToSend : Notification;RecId : RecordID)
SendNotificationWithAdditionalContext(NotificationToSend : Notification;RecId : RecordID;AdditionalContextId : GUID)
RecallNotificationsForRecord(RecId : RecordID;HandleDelayedInsert : Boolean)
RecallNotificationsForRecordWithAdditionalContext(RecId : RecordID;AdditionalContextId : GUID;HandleDelayedInsert : Boolean)
SetRecordID(RecId : RecordID)
UpdateRecordID(CurrentRecId : RecordID;NewRecId : RecordID)
Usage
The simple case is:
Figure 4: without additional context
Figure 5: with additional context
However, delayed insert means that the simple case seen above doesn’t happen very often. The issue is that when we call SendNotification, we provide the cause object’s record ID. If this object has not been inserted yet, which is often the case when the user creates a new invoice, a new line, and so on, the record ID is incomplete. When the object is inserted the record ID is completed, but if we call RecallNotificationsForRecord at a later point, the record ID will be different from the incomplete record ID we used when sending the notification. The solution is to detect that the object is not yet inserted when we send the notification, and at a later point, set the record ID when the cause object is inserted.
The realistic case is:
Figure 6: delayed insert, with additional context
Usages in NAV:
COD311 (Item-Check Avail.)
COD312 (Cust-Check Cr. Limit)
COD1508 (Notification Lifecycle Handler)
Related Patterns:
On many occasions, it’s needed to refer to the product name in messages or errors. It’s not a good practice to hardcode the brand name like Dynamics NAV 2017, and change this value with each rebranding. You can use client ProductName System Object instead to refer to the product name.
When you want to refer to product name in informational messages or errors, it’s not a good practice to hardcode the brand name, as this requires changing this text when a rebranding happens.
Instead of hardcoding the product name like “Dynamics NAV 2017”, it’s recommended to use ProductName System Object that platform provides.
You can use ProductName to refer to the product name, this you can use in text messages. ProductName has 3 values ProductName.Short, ProductName.Full, and ProductName.Marketing, each one should be used according to the context of your message.
It’s recommended to use ProductName.Short for most in-product texts , ProductName.Full when other dynamics apps are present in the message context (like CRM), and ProductName.Marketing only when absolutely necessary.
Usage: You should make a placeholder in your text constant and substitute this placeholder with ProductName as shown below.
Output
alguidelines.dev - Business Central Design Patterns
@@ -9,7 +9,7 @@
Create Issue
Discussions
Create project issueExpand to see NAV design patterns which use queries.
By Bogdana Botez, at Microsoft Development Center Copenhagen
This pattern explains how to perform SELECT DISTINCT by using queries in Dynamics NAV.
Description
When working with tables, sometimes a developer needs to perform a SELECT DISTINCT (also known as SELECT UNIQUE) from a table. As NAV does not provide this out of the box, we present below a way to select unique records by using queries.
Problem statement
Let’s consider the VAT Entry table as below:
The goal is to select one line for each separate document that produced VAT Entries. In other words, we want records grouped by Type, Document Type and Document No.. However, if there are multiple lines with the same value of the triad Type, Document Type and Document No. in the VAT Entry table, we only want to see one of them.
Create a new query object VAT Entry Distinct Document No., with a single DataItem sourced from VAT Entry table. Add the three desired group-by fields Type, Document Type and Document No. as columns.
To enable grouping, add one more column, with Method Type = Totals. This will automatically set the Group By checkbox to TRUE on the three precedent fields.
Note that the Group By field is read-only and trying to set it by hand will clarify that:
Running the query yields a single record per document. You can notice in the second line below for example, how the sales invoice number 103001 had 2 VAT Entries, but it shows up only once in the query:
One thing is to be noted: there is a limitation to how much information you can take out from the records. For example, if we need to extract more information than just the one we already have in the columns, then the following apply: adding one more column of Method Type = None will indeed show more information, but it might affect the grouping. More details below.
The grouping is affected for example when the additional column is the VAT Entry No. In this case, this column brings up additional grouping criteria and one group for each entry number will end up being created.
You can notice that both lines of document 103001 are not visible, which contradicts the goal of SELECT DISTINCT.
The grouping is not affected when the additional column does not influence grouping (has variation identical with one of the other existing columns). For example, adding Posting Date as a new column, does not change anything because posting date is the same for all lines of a document, so the query result is identical with the initial one:
Below is the result of this query, where you can notice that the initial grouping is preserved and correct. Bonus, we can now read the Posting Date of the document too.
The grouping is also not affected when adding more columns of Method Type = Totals. However, this can only be done with columns of Decimal data type.
This pattern is used in Query 19: VAT Entries Base Amt. Sum. This query is used in Report 19: VAT- VIES Declaration Tax Auth.
The pattern is also used in Query 1511: User IDs by Notification Type.
A variation using loops could be described, for C/AL development on NAV 6 where query objects are not available.
By Tim Grant
One time query and validation of a setup table.
Firstly identifies if a setup table record is in memory, removing the need to execute and validate the re-query again within a code unit. (From NAV 2013+ service tier database caching exists).
If you need to query a setup table, but not sure if the table is yet in memory from earlier code, this helps to determine this call (see Singleton Table pattern).
Allows a central function to validate critical fields before processing automated code. TESTFIELD calls are added to the function and not the INIT call in order to ensure that critical functions do not run without this human check in place as these may rely on key configuration. If you have a design where specific field values are critical (custom or standard) for integrity, then INIT INSERT is a dangerous default which could result in the corruption of processes. This is separate automated INIT INSERT from a setup page.
A global variable record and a global status indicator, but within the context of a local function.

A similar example of this is in Codeunit 80, but without any validation.
E.g. If there is a bespoke change, then this existing GetGLSetup can be called earlier to accommodate for an earlier bespoke change:
This means that by the time the code reaches the original GetGLSetup code requirement, this record is already in memory as the status flag is set to True, eliminating another check. For such Patterns the setup record should never be cleared, it should be called once globally, initiated and left in memory for future checks. It should not be declared locally at the same time, review your code for matching local variable usage before implementing this.
Merge Singleton Table with dynamic validation field meta configuration. This removes the coding of TESTFIELD to a central setup check.
Example with the Sales & Receivables Setup
If in the circumstance that a field value in the setup table is expected to change within the life of the code component instance. e.g. If a CHANGECOMPANY is required to cross reference another Setup table, use a separate variable.
This is related to the Singleton Table pattern.
Authors: Henrik Langbak and Kim Ginnerup, Bording Data
This pattern prevent data from being used elsewhere before it is in a system consistent state.
NAV inserts a record as soon as the primary key has been set. But the record may not be in a valid state at this point in time. How do you know if a newly inserted record is ready for use?
Whenever you need to stall the release of data, you can use this pattern.
Because NAV decides when a record is written to the database, it may not be in a system consistent state. Nobody should use the record before everything is in place and the record is valid. An inserted record may even have data in other tables that needs to be inserted and in a valid state before other parts of the system can use the data without running into a problem.
Data entered into the system may have to be approved by a second person before it can be used.
Data requires different parties (e.g. Departments) to add information before data is valid.
The solution is an Option Field with two or three values:
(Open, Released) or (Open, Pending, Released)
The states should be interpreted as:
| State | Description |
|---|---|
| Open | Not all data is in place. The record is system inconsistent. The record or record hierarchy is invisible for all other parts of the system. |
| Pending | The record is system consistent. But is awaiting someone to manually raise the state to Released. The record is still invisible. |
| Released | All data is in place and the record is system consistent, and ready for use. It is now visible for the rest of the system. The state can never be reversed. |
The option field name: Release State.
This pattern is very similar to the Blocked Entity pattern, but it has one significant difference.
The record is not visible to any part of the system, before it is in the Released state.
There is no going back. When the Released state is reached, it will stay that way for the life of the record. In case of a tri-state, it is ok to bypass Pending seen from a system state perspective.
If there is a hierarchy, e.g. Header and Lines, then the Release State field resides on the Header. As long as the Header remains unreleased, the lines are considered inconsistent and must not be used.
The important and critical part of this pattern is that the whole application needs to obey the “Release State”-contract or the system will fail.
To use this pattern you need to create an Option Field named: “Release State” with at least the two states: Open, Released.
If it is feasible to set the Release State automatically, create a local function named: “CheckAndSetReleaseState” that validates the record and sets Release State to Pending or Released, when all system requirements are met.
The function only works one way. It can only increase the state. If the function is called when release state is Pending or Release, the function will do nothing.
If the function is implemented, then the user should not be able to change the value from Open to Pending or Released, only the function can do that.
The function should be called on every change, this way it will be visible to the end user immediately when all requirements are met.
If the Pattern is implemented without this function, then field is maintained by the end user.
NAV has Table 36 Sales Header, Field 120 Status.
In this example, it is called: Status.
Status has 4 values: Open, Released, Pending Approval, Pending Prepayment.
The example above, taken from NAV, shows similarity with this pattern, but in the Sales Header example it is possible to modify the Release state to an earlier state, through a function in NAV. This is not recommended in the pattern.
In case of a Pending State, you may need an Approved Date and Approved By. Depending on how formal it needs to be.
This pattern is only used on data creation.
If there is a need for shuffling between states back and forth, then this is not the pattern to use.
Blocked Entity is a variant of this pattern but Blocked Entity is used later in the life-cycle.
An alternative to the pattern is temporary tables. But the temporary table is an all or nothing approach. If all data in the Record is valid, the temporary record can update the real data. If not, abandon the process. The Release State pattern is simpler and requires less code.
There is a term called: Long Term Lock. This pattern has some resemblance.
When talking about hierarchical data structures and the Release State is held on the root node, there is a pattern called Hierarchical Locking that has some resemblance.
By Bogdana Botez at Microsoft Development Center Copenhagen
Aliases: Encapsulation, Separation of Concerns [1]
Context: You want to store and protect sensitive data which already exists in a system, but it is not clear which data needs protection and how to store it.
Problem: Sensitive data is scattered and mixed with other data in various parts of the system (passwords residing in the same table with non-sensitive data, part of the private information might be stored in files, hardcoded text constants, hardcoded info as part of the code etc.).
Forces:
Solution: Extract and separate sensitive data into a single known repository.
To apply this pattern in Dynamics NAV, a table structure similar to Table 1261 Service Password can be used. The Service Password table also contains additional functionality which will help to further apply related patterns like Access Control and Encryption.
Figure 1 describes the definition of a table which is already available in Dynamics NAV. This table can be used for storing sensitive data. As a minimum, the table only needs two fields:
Figure 1- Example definition, table used for Sensitive Data Encapsulation
Let’s use a software system (which can be a Dynamics NAV extension or customization). Chances are that the system will look similar to the one described in part 1 of Figure 2: there is data handled in various places of the system, on various storage solutions. Intertwined with normal data, there is sensitive data. For example: Dynamics CRM (Customer Relationship Management) connection information could be all stored in one table, and consists of the connection URI (normal data), enabled/disabled status (normal data), and connection password (sensitive data).
Figure 2 illustrates the system before and after applying the Sensitive Data Encapsulation pattern.
Furthermore, actors which have to interact with the data, need to remember where to find each piece of information and how to retrieve it.
Figure 2 - Data access before and after Sensitive Data Encapsulation.
Benefits:
Drawbacks:
References
[1] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Separation_of_concerns.
[2] “GUID Structure,” [Online]. Available: https://msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx.
[3] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Binary_large_object.
[4] waldo, “How Do I: Manage Companies in Microsoft Dynamics NAV 2013 R2”.
[5] Microsoft, “Multitenant Deployment Architecture,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/dn271675(v=nav.90).aspx.
[6] B. Botez, “Setup Table design pattern,” Microsoft, 2013. [Online]. Available: https://community.dynamics.com/nav/w/designpatterns/76.setup-table. [Accessed 31 07 2016].
[7] “Shotgun Surgery,” [Online]. Available: https://en.wikipedia.org/wiki/Shotgun_surgery. [Accessed 31 07 2016].
[8] M. Fowler, Refactoring: Improving the design of existing code, Addison Wesley, 1999.
[9] “Masking out,” [Online]. Available: https://en.wikipedia.org/wiki/Data_masking#Masking_out. [Accessed 29 7 2016].
[10] “Key Vault,” Microsoft, [Online]. Available: https://azure.microsoft.com/en-us/services/key-vault/.
[11] “How to: Configure SSL to Secure the Connection to Microsoft Dynamics NAV Web Client,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/hh167264(v=nav.90).aspx. [Accessed 2 8 2016].
[12] “sniffer,” [Online]. Available: http://compnetworking.about.com/od/networksecurityprivacy/g/bldef_sniffer.htm. [Accessed 02 08 2016].
Figure 2- The administrator is advised to enable encryption.
Now Stan becomes aware that there is no encryption and has the opportunity to enable it. If he clicks on “Yes”, Stan will be taken to the Data Encryption Management page (Figure 3).
Figure 3- Data Encryption Management page
Stan can now choose “Enable Encryption” from the ribbon which informs him that an encryption key will be created (Figure 4).
Figure 4- The administrator is encouraged to save a copy of the encryption key.
Stan has the option to save the encryption key in a safe location. He invokes the action Enable Encryption and is guided forward (Figure 5).
Figure 5- The encryption key needs to be protected by a password.
Stan chooses a password, which in this implementation requires minimum 8 characters with at least one uppercase character, one lowercase character and one digit. If the chosen password is too weak, Stan is given information on the expected complexity (Figure 6).
Figure 6- The administrator chooses a strong password.
In the end, Stan chooses a location for the encryption key on disk, in a standard file save dialog. The layout of the file save dialog depends on the display target used (web browser, rich client etc.).
NAV Usages. Encryption examples can be found in NAV in the following places:
Benefits:
Anti-patterns:
References
[1] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Separation_of_concerns.
[2] “GUID Structure,” [Online]. Available: https://msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx.
[3] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Binary_large_object.
[4] waldo, “How Do I: Manage Companies in Microsoft Dynamics NAV 2013 R2”.
[5] Microsoft, “Multitenant Deployment Architecture,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/dn271675(v=nav.90).aspx.
[6] B. Botez, “Setup Table design pattern,” Microsoft, 2013. [Online]. Available: https://community.dynamics.com/nav/w/designpatterns/76.setup-table. [Accessed 31 07 2016].
[7] “Shotgun Surgery,” [Online]. Available: https://en.wikipedia.org/wiki/Shotgun_surgery. [Accessed 31 07 2016].
[8] M. Fowler, Refactoring: Improving the design of existing code, Addison Wesley, 1999.
[9] “Masking out,” [Online]. Available: https://en.wikipedia.org/wiki/Data_masking#Masking_out. [Accessed 29 7 2016].
[10] “Key Vault,” Microsoft, [Online]. Available: https://azure.microsoft.com/en-us/services/key-vault/.
[11] “How to: Configure SSL to Secure the Connection to Microsoft Dynamics NAV Web Client,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/hh167264(v=nav.90).aspx. [Accessed 2 8 2016].
[12] “sniffer,” [Online]. Available: http://compnetworking.about.com/od/networksecurityprivacy/g/bldef_sniffer.htm. [Accessed 02 08 2016].
By Bogdana Botez at Microsoft Development Center Copenhagen
Context: Protected data needs to be used. There are many types of entities which might attempt to use the data.
Problem: If no standard way of accessing data exists, then each entity might attempt to build its own system for handing the sensitive data. The data access layer might be implemented over and over again by each entity, without reuse of known best practices and with a lot of code duplication.
Forces:
Solution: In Dynamics NAV the same library which offers Encryption, is also intended to be used as a Single Point of Access. Write code to create, read and remove sensitive data only through codeunit 1266 Encryption Management, and never directly.
In Figure 9 (figure numbering is continued from pattern Encryption), the panels 1, 2 and 3 have applied the Sensitive Data Encapsulation and Encryption patterns. Once data is encapsulated, no matter if it has been encrypted or not, the next pattern, Single Point of Access, becomes available as seen in the panels 2 and 3 of Figure 1.
You can observe that, in panel 3, each usage needs to access separately the encrypted data. This means that each usage needs to implement again the encryption capabilities. This is resolved in panel 4, where all users access one common API which encrypts, hence the workload of encryption is moved from the usages, to the API, and needs to be implemented only once.
Figure 1- Single Point of Access pattern applied.
This shows how pattern application is an iterative process, where one step follows another. Refactoring [8] the code to apply one pattern, cleans and clarifies the code and in some cases, makes clear the possibility of further refactoring.
Usage: call the procedures available in codeunit 1266 Encryption Management to store and access sensitive data.
Benefits:
Consequences:
References
[1] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Separation_of_concerns.
[2] “GUID Structure,” [Online]. Available: https://msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx.
[3] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Binary_large_object.
[4] waldo, “How Do I: Manage Companies in Microsoft Dynamics NAV 2013 R2”.
[5] Microsoft, “Multitenant Deployment Architecture,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/dn271675(v=nav.90).aspx.
[6] B. Botez, “Setup Table design pattern,” Microsoft, 2013. [Online]. Available: https://community.dynamics.com/nav/w/designpatterns/76.setup-table. [Accessed 31 07 2016].
[7] “Shotgun Surgery,” [Online]. Available: https://en.wikipedia.org/wiki/Shotgun_surgery. [Accessed 31 07 2016].
[8] M. Fowler, Refactoring: Improving the design of existing code, Addison Wesley, 1999.
[9] “Masking out,” [Online]. Available: https://en.wikipedia.org/wiki/Data_masking#Masking_out. [Accessed 29 7 2016].
[10] “Key Vault,” Microsoft, [Online]. Available: https://azure.microsoft.com/en-us/services/key-vault/.
[11] “How to: Configure SSL to Secure the Connection to Microsoft Dynamics NAV Web Client,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/hh167264(v=nav.90).aspx. [Accessed 2 8 2016].
[12] “sniffer,” [Online]. Available: http://compnetworking.about.com/od/networksecurityprivacy/g/bldef_sniffer.htm. [Accessed 02 08 2016].
By Bogdana Botez at Microsoft Development Center Copenhagen
Aliases: Masking out
Context: In the user interface (UI) of a software system, the user enters protected information such as a password, an access key, a credit card number etc.
Problem: The entered information is visible during data entry and whenever any user (the one who entered the data, or a foreign user) opens the UI.
Forces:
Solution: Use the “Masked” field property to display dots instead of characters on the sensitive text field in the UI.
Usage: Figure 1 shows how an unmasked and a masked field look in Dynamics NAV. On page Microsoft Dynamics CRM Connection Setup, the first two fields (Dynamics CRM URL and User Name) are not masked. The next field (Password) is masked. As the user types text into the Password field, the characters are one by one replaced with dots. When the user had finished typing and had left the Password field (moved focus to another page element), then a pre-defined number of dots is showed in the field, no matter what the real length of the password is. This is done so that the length of the text is not disclosed. Hence, no matter if the text had 5, 10 or 20 characters, as soon as the user leaves the masked field, 10 dots will be visible.
Figure 1 - The field “Password” is masked.
To apply this pattern in Dynamics NAV, the developer has two choices:
Mask the field in all pages which expose it or will expose it in the future. In this case, masking needs to be set at the table level, by opening the table in design mode and setting the field’s property ExtendedDatatype=Masked.
Mask the field in only a subset of pages. Open the pages where the field should be masked in design mode, open the property page for the field in question, and set ExtendedDatatype=Masked. This option can be used for example when a field should be hidden from most users (in most usual pages), but still visible to administrators in specific pages.
Benefits:
Drawbacks:
References
[1] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Separation_of_concerns.
[2] “GUID Structure,” [Online]. Available: https://msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx.
[3] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Binary_large_object.
[4] waldo, “How Do I: Manage Companies in Microsoft Dynamics NAV 2013 R2”.
[5] Microsoft, “Multitenant Deployment Architecture,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/dn271675(v=nav.90).aspx.
[6] B. Botez, “Setup Table design pattern,” Microsoft, 2013. [Online]. Available: https://community.dynamics.com/nav/w/designpatterns/76.setup-table. [Accessed 31 07 2016].
[7] “Shotgun Surgery,” [Online]. Available: https://en.wikipedia.org/wiki/Shotgun_surgery. [Accessed 31 07 2016].
[8] M. Fowler, Refactoring: Improving the design of existing code, Addison Wesley, 1999.
[9] “Masking out,” [Online]. Available: https://en.wikipedia.org/wiki/Data_masking#Masking_out. [Accessed 29 7 2016].
[10] “Key Vault,” Microsoft, [Online]. Available: https://azure.microsoft.com/en-us/services/key-vault/.
[11] “How to: Configure SSL to Secure the Connection to Microsoft Dynamics NAV Web Client,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/hh167264(v=nav.90).aspx. [Accessed 2 8 2016].
[12] “sniffer,” [Online]. Available: http://compnetworking.about.com/od/networksecurityprivacy/g/bldef_sniffer.htm. [Accessed 02 08 2016].
By Bogdana Botez at Microsoft Development Center Copenhagen
Context: The security of data transmission is just as important as the security of data storage. When data is transmitted over the web, Secure Sockets Layer (SSL) is available to be used with the web client in Dynamics NAV. Microsoft’s NAV cloud solution has SSL enabled by default. However, if a partner company chooses to deploy their own NAV, then they need to handle SSL explicitly.
Problem: Although data is stored securely, before it even gets to be stored, it needs to travel the web on a client-server connection, where it is vulnerable.
Forces:
By using data storage patterns like Sensitive Data Encapsulation, Encryption, Single Point of Access or Azure Key Vault, the sensitive data is preserved securely in the implementation of Dynamics NAV. But before it gets into a secure store, this data needs to be transmitted from the user, through a user interface, on a client-server connection and all the way to the database. Is the data safe while being transmitted?
Solution: To protect the data before it reaches the server, remember to configure SSL (Secure Sockets Layer) in Dynamics NAV.
SSL is a web protocol that encrypts data that is transmitted over a network to make the data and the network more secure and reliable. A website that is enabled with SSL uses Hypertext Transfer Protocol Secure (HTTPS) instead of Hypertext Transfer Protocol (HTTP) as a communication protocol.
Figure 1 shows data communication between the client (where the user enters data) and the server (which connects further to the database). Without encryption (left side), data is available in clear text over the wire. A person equipped with a network sniffer can easily intercept and read it. On the right side of the picture, SSL is used to encrypt the user’s data. Sniffing the traffic would capture the encrypted stream, but access to the real content would be impeded by encryption.
Figure 1 - Data transmission before (http://…) and after SSL encryption (https://…).
Usage: the latest information about how to configure SSL for the web client in Dynamics NAV is found online at on MSDN at https://msdn.microsoft.com/en-us/library/hh167264(v=nav.90).aspx.
Benefits:
Consequences:
References
[1] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Separation_of_concerns.
[2] “GUID Structure,” [Online]. Available: https://msdn.microsoft.com/en-us/library/aa373931(VS.85).aspx.
[3] “Wikipedia,” [Online]. Available: https://en.wikipedia.org/wiki/Binary_large_object.
[4] waldo, “How Do I: Manage Companies in Microsoft Dynamics NAV 2013 R2”.
[5] Microsoft, “Multitenant Deployment Architecture,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/dn271675(v=nav.90).aspx.
[6] B. Botez, “Setup Table design pattern,” Microsoft, 2013. [Online]. Available: https://community.dynamics.com/nav/w/designpatterns/76.setup-table. [Accessed 31 07 2016].
[7] “Shotgun Surgery,” [Online]. Available: https://en.wikipedia.org/wiki/Shotgun_surgery. [Accessed 31 07 2016].
[8] M. Fowler, Refactoring: Improving the design of existing code, Addison Wesley, 1999.
[9] “Masking out,” [Online]. Available: https://en.wikipedia.org/wiki/Data_masking#Masking_out. [Accessed 29 7 2016].
[10] “Key Vault,” Microsoft, [Online]. Available: https://azure.microsoft.com/en-us/services/key-vault/.
[11] “How to: Configure SSL to Secure the Connection to Microsoft Dynamics NAV Web Client,” Microsoft, [Online]. Available: https://msdn.microsoft.com/en-us/library/hh167264(v=nav.90).aspx. [Accessed 2 8 2016].
[12] “sniffer,” [Online]. Available: http://compnetworking.about.com/od/networksecurityprivacy/g/bldef_sniffer.htm. [Accessed 02 08 2016].
By Bogdana Botez at Microsoft Development Center Copenhagen
When sensitive data is stored inside the Dynamics NAV database, if negligently handled, it can become vulnerable. Particularly, the location, access and the state of the data are critical.
Use the following patterns to enhance security on your NAV system.
By Jan Hoek at IDYN
The Setup Specificity Fallback pattern allows users to efficiently define a potentially complex setup in terms of rules and exceptions to these rules, exceptions to the exceptions, etc.
The pattern involves a setup table with a compound (i.e. consisting of more than one field) primary key, where each record in the table maps a combination of primary key values to a particular setup value. However, setting up and maintaining each and every combination could prove to be rather labour-intensive.
With the Setup Specificity Pattern in place, primary key fields in the setup table can have a special value (typically: zero or an empty string) that acts as a wildcard, meaning that the setup record in question applies to a combination of primary key fields with any value in the field containing that wildcard. According to the pattern, when querying the setup table, the application attempts to find the appropriate setup record by searching less and less specific, starting with only specified primary key values, and possibly ending with only wildcard values, replacing specific values with wildcards in a predefined order until a setup record is found, e.g.:
| Step 1. | Try to find record with: Field A = value “a” and Field B = value “b” | If found, return record; if not, go to step 2. |
| Step 2. | Try to find record with: Field A = value “a” and Field B = wildcard value | If found, return record; if not, go to step 3. |
| Step 3. | Try to find record with: Field A = wildcard value and Field B = value “b” | If found, return record; if not, go to step 4. |
| Step 4. | Try to find record with: Field A = wildcard value and Field B = wildcard value | If found, return record; if not, optionally return hard-coded value |
The least specific record can be thought of as the general rule, and each of the subsequent records is an exception to that rule. By defining only exceptions to the rule, instead of each and every combination, the burden of setting up and maintaining the setup records is strongly reduced, and the overall setup is much easier to read and understand.
The Printer Selection table in NAV is an example of the Setup Specificity Fallback pattern. Its primary key consists of two fields. A blank value in either field means that the record applies to any user or report respectively.
The FindPrinter function in codeunit 1 searches for the printer to use, with a decreasing level of specificity.
@@ -10,7 +10,7 @@ Context: The pattern described in this article applies to Dynamics NAV only. For
Create Issue
Discussions
Create project issueBy Bogdana Botez at Microsoft Development Center Copenhagen
Context: The pattern described in this article applies to Dynamics NAV only. For the general definition of the Singleton pattern, see for example this link.
Problem: As a C/AL developer, you need to coordinate action (through a codeunit) or store information (in a table) that is unique across the system.
Forces:
Solution: create an object which resides in memory in a single copy (instance). Have a way to retrieve this unique object from code. This object can either be a Singleton Table, or a Singleton Codeunit.
The implementation varies depending on the technology and language used. In object-oriented (OO) languages like C#, C++ or Java, the Singleton uses static classes and class members to instantiate. There is a mechanism to ensure only one instance of the object can exist. This mechanism is many times explicit (like in OO languages) and sometimes implicit as part of the compiler or platform (as it is in NAV).
Benefits:
Limitation: The generic object-oriented Singleton pattern permits instantiation of a limited number n of objects (where usually n=1, but it can have other positive values too). However, in Dynamics NAV, the Singleton patterns are limited: n is always 1.
Solution: restrict the number of instantiations of a codeunit to only one, by setting the codeunit property SingleInstance to Yes.
Returning to the previous example, let’s analyze the case when the codeunit Permission Manager is a singleton codeunit:
When the codeunit Permission Manager is a singleton, then no matter from where it is invoked, the same instance will be reached. Therefore, the status set by the test (SaaS = TRUE) will be reachable from the production code, and the test will pass, as seen in the figure below.
Consequences
1. Use Singleton Codeunit with care and only when there is no other solution. Preserving a global state could often enough be more harmful than useful. One risk is that tests might fail apparently non-deterministically.
For example, a problem we have met in the development team for Madeira release, was that the singleton codeunit function PermissionManager.SetSoftwareAsAService(TRUE) is often used to emulate and test SaaS conditions. However, if a test ‘forgets’ to reset the state to default (FALSE), then another codeunit which is not supposed to emulate SaaS, will suddenly run as SaaS and will fail. Even if the test has code that resets the state to FALSE, this code might never be reached because of an earlier failure or other error in the test which would stop execution.
2. The singleton codeunit is only “alive” for the current session. If the user logs out, the old session is closed and the singleton cleared out so any values stored in the old session’s singleton will be lost when the session was closed. When the user logs in again, a new session (with a new fresh instance of the singleton) will be created.
NAV Usages
Most of the usages in NAV refer to the so-called “management codeunits”. The management codeunits are needed to run, in a centralized way, various modular parts of the application (features), like the CRM integration, Permissions, Workflows etc. Some of the Singleton Codeunits in NAV are listed below:
Note: while the object-oriented Singleton pattern can restrict the number of instantiations of the singleton to an integer n > 0, in Dynamics NAV the Singleton Codeunit can only have n=1.
By Bogdana Botez at Microsoft Development Center Copenhagen
Cues are the second usual application of the Singleton Table pattern in Dynamics NAV, after Setup Tables.
Context: The user gets overview information about the business on the Dynamics NAV Role Center page.
Figure 1 - Cue information in Dynamics NAV shows cue information seen by the user on the Sales Order Processor role center.
The overview information consists of summed-up numbers, calculated from business data, like for example how many sales orders are still open, how many shipments are ready to go, or partially shipped, how many documents are waiting for approval etc.
Problem: NAV stores data in tables. By definition, a table is a repetitive structure containing multiple lines, each line having a different piece of the information. But sometimes this repetitive information needs to be summed-up or otherwise synthetized, and presented as an overview.
Solution: Store overview information in a singleton table.
There are two ways of calculating overview information in NAV.
By using a FlowField. This applies for simpler calculations, like filtered or unfiltered counts, sums etc.
By writing C/AL code to perform custom calculations. Use this when:
The implementation of Cues is already described in detail on MSDN, in Creating and Customizing Cues and in Walkthrough: Creating a Cue Based on a FlowField.
NAV Usages
Table 1 - Cue tables in Dynamics NAV shows some examples of singleton tables used for creating Cues.
| Table ID | Table Name |
|---|---|
| 1313 | Activities Cue |
| 5370 | CRM Synch. Job Status Cue |
| 9042 | Team Member Cue |
| 9050 | Warehouse Basic Cue |
| 9051 | Warehouse WMS Cue |
| 9052 | Service Cue |
| 9053 | Sales Cue |
| 9054 | Finance Cue |
| 9055 | Purchase Cue |
| 9056 | Manufacturing Cue |
| 9057 | Job Cue |
| 9058 | Warehouse Worker WMS Cue |
| 9059 | Administration Cue |
| 9060 | SB Owner Cue |
| 9061 | RapidStart Services Cue |
| 9063 | Relationship Mgmt. Cue |
| 9069 | O365 Sales Cue |
| 9070 | Accounting Services Cue |
Table 1 - Cue tables in Dynamics NAV
Related topics
The Singleton Table has two established applications in Dynamics NAV:
YouTube Video of NAV Singleton:
Company-Initialize Codeunit
The Company-Initialize codeunit (codeunit 2) is executed when a new company is created. We recommended that you add records to the single-record tables in this codeunit. If some of the fields are expected to have default values, they can also be populated here.
NAV Usages
Several Setup tables in NAV implement this pattern. Some of those are:
Variation: While most tables just insert a record with empty primary key in codeunit 2, table 242 (“Source Code Setup”) offers an example of inserting default values into all fields of the table (method “InitSourceCodeSetup”). This practice, wherever feasible, is likely to reduce the effort during implementation.
Related resources: Considerations on optimizing the Singleton Table, by Søren Klemmensen.
By Bogdana Botez, at Microsoft Development Center Copenhagen
Meet the Standard Journal pattern, which gives the NAV user the advantage of storing transaction details and reusing them multiple times at later dates. For example, this is how to pay a monthly bill.
If the journal data can be reused later, the user has the possibility to save the current temporary transaction details. One example can be the case of monthly electricity payments. The user will manually enter the details for the first payment, of the current month. Next month, a part of the data will be the same, such as the vendor and transaction details. If the user has saved the initial monthly payment as a standard journal, then they can now reuse it to create the draft of the next monthly payment. Once the draft journal lines are created, they can be updated with the current month information.
When a journal is created, the user can invoke the Save as Standard Journal action to save the current journal for later use. When saving the journal as a standard journal, the user is required to choose a code, which is later used to identify the saved journal. The journal lines are stored in a separate table. There can be one standard journal saved per journal type and code.
Later, the user can create new journal lines by using the Get Standard Journals action. This action restores the saved journal into the new journal lines.
Step 1: The data entered by the user through the Journal page is stored temporarily in the Journal Line table. The data is available for editing or deleting. The journal line data will be stored in this table until it is either deleted or posted.
Step 2: The user decides to save the current journal line entries for later use. If this is the monthly rent, the user may want to use similar entries next month when a new payment is due. On the Journal page, the user invokes the Save as Standard Journal action. This triggers the Save as Standard Journal report, which copies the entries from the Journal Line table to the Standard Journal Line table. When saving, the user will be asked for an identifier, a code, which will be used to later uniquely identify the saved entries.
Step 3: When the user invokes the Get Standard Journal action, a list of codes are presented to the user so that they can decide which standard journal to restore and copy in the Journal Line table.
The sequence flow of the three steps is described in the following diagram.
In the standard version of NAV, the Standard Journal functionality is implemented in the following journals:
The user enters data in the General Journal page (39) and invokes the Save/Get actions as illustrated in the following screenshot:
When saving the journal lines, the Save as Standard Gen. Journal report (750) is invoked. The report saves the entries in the Standard General Journal Line table (751).
By Nikola Kukrika at Microsoft Development Center Copenhagen
To increase discoverability and productivity, critical information, such as statistics, can be moved from separate pages onto the document where it is needed.
For example, documents should clearly display totals and discounts information to provide quick overview, make it easy to relate the amounts to the document currency, and to allow the user to see and apply discounts directly on the document.
Before Microsoft Dynamics NAV 2015, totals and discount information was scattered between the document and the Statistics page, which made it less discover-able and less usable for new users. It was difficult to see the discount amounts, relate the amounts to the currency of the invoice, and it was not-intuitive that you had to update the Statistics page to see updates on the document. In addition, the result of the update was not visible on the main document, which added to the confusion.
Totals and discount information logically belongs on the document, as is the case on many competitor products.
The Statistics page contains too much information for most common scenarios, and only a part of the information is visible on the related document. See the following example for sales order statistics.
With the pattern implemented, selected statistics fields are placed on the sales order, as in the following example.
This new layout gives precise and complete information about totals and discounts, with discounts on the left side and totals on the right side. The currency is clearly shown, and the layout resembles a printed document. The values are always updated (with some exceptions that are explained in the next following sections), and the user can apply a discount directly on the document.
Options considered when deciding on the layout:
The Lines subpage option was chosen because:
Concerning update of totals and discounts, the following were considered:
The following artifacts were implemented to achieve the desired functionality.
In order to always update the totals, the system must have a way to mark that a specific change should trigger a recalculation of the totals. To achieve this, the following was implemented.
The UpdateAmounts function sets the new field to TRUE for any execution. This function was chosen as it is a central entry point for any amount-related change.
Update diagram
The following new codeunits were added:
Note: In case of web-service implementations that do not use the existing pages, the total calculation and the invoice discount logic should be called specifically to display similar functionality.
A new CU, COD57 has been added and it contains the logic used to update the fields that will, in the end, be displayed in the UI. Decision was to merge both the sales and purchase functionality into one place.
The pattern is applied to both non-posted documents (orders, invoices, etc.) and posted documents (posted Invoice, etc.). Because the posted document is a document that does not change, the implementation is simplified as follows.
The OnAfterGetCurrRecord function call is responsible for updating the totals- and discount-related controls.
To avoid duplicating lots of code in many places, a single function with more parameters “pattern” was chosen. The function returns all the controls updated in a single call, as follows.
Manual invoice discount. One function call when applying a manual invoice discount, as follows.
Note: After applying the manual discount, the lines should be refreshed as they will be changed in batch mode.
The following “decorators” were added to recalculate amounts on the fly:
Code should be added to the validate triggers of the controls that are changing the amounts in order to refresh the total controls.
Note: Amounts will not always be up to date because of the following:
Only the _OnAfterGetCurrRecord _function will have code because posted documents cannot be changed. Therefore, totals do not need to be updated.
After Platform added support for this specific case, the layout is very simple, as follows.
This will produce the layout we wanted:
As mentioned before, there are cases when the user is informed that totals/discounts might not be up to date and that it should select a link in order to get the updated values.
The link is part of the sub-part where totals and discounts are added. The visibility is controlled by actually controlling the text (message, or empty), because Platform does not support making only one visible/invisible (it must be a group). When the link is displayed, the styling is also changed for the total/discount controls, and the values are set to 0.
We have implemented these scenarios for sales and purchase documents (order, invoice, quote, credit memos, return orders, including posted documents). Note that the implementation in NAV 2015 is a bit different than the one in NAV 2014 C5 objects (1300 range). It was decided not to merge the two implementations, among other reasons because the NAV 2014 C5 implementation does not fit the full application.
The pattern can easily be extended to new sales and purchase documents. If the pattern is followed, it can also be extended to other types of documents, such as in services, jobs, etc.
Note: This new pattern is not implemented in the North America and India versions. This is due to special local features in the two versions regions and the multitude of sales tax/vat options that would make the solution non-user friendly and not optimized for performance.
Platform support to be able to trigger full-page update from the lines. Support does exist today, but it is not programmatically controlled at design time. This means that it cannot be used in all cases.
From the PrintDocument signature it is clear that it will not need to be changed in the future.
Code duplication is avoided, specific code is isolated in the PrepareRecord function, there is clear extension point to add support for new records in the future. Since code is not duplicated and there is a single flow through the method, inserting hooks and events in the future will be straightforward.
When adding the support for new records in most cases it is not need to change any code within the method, thus the cost of extending the usage is minimal.
Note - PrepareRecord function is placed for the illustrational purposes. An improvement would be to move all of the code from the PrepareRecord function before calling the function. So for the SalesHeader and PurchaseHeaders discounts should be calculated before invoking the function. For passing of the argument it should be one of the fields in the Argument Table, thus the entire specific code would be eliminated.
OO Facade https://en.wikipedia.org/wiki/Facade_pattern
Argument Table pattern - https://community.dynamics.com/nav/w/designpatterns/245.argument-table-pattern
Rules Table pattern
Find below some related NAV Design Patterns links.
MSDN NAV Team Blog - posts about patterns
NAV Application Design slides from NAV TechDays conference in Antwerp, 2013
NAV Application Design movie from NAV TechDays conference in Antwerp, 2013
NAV’s Secret Code: Design Patterns of Today and Tomorrow slides from NAV TechDays conference in Antwerp, 2013
The snippets are:
tcodeunitMethodWithoutUIwaldotcodeunitMethodWithUIwaldoThere have been a number of occasions where people have been sharing this pattern. Here is one:
This section will cover patterns that solve certain design challenges in Business Central.
From wikipedia:
In Computer science, a Design pattern is an abstract solution to a certain problem. Design patterns are used in object oriented programming. They give a possible solution to a problem of designing software … They also simplify the language between computer scientists. Ideally, a design pattern should be reusable many times. It is like a brick of a house, it can be used for many different problems. One can also build bridges with bricks, not only houses.
All discussion related to Best Practice are to be found on the Github Repo’s Discussion pages, found here
alguidelines.dev - Business Central Design Patterns
alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.devPatterns described to be used with Microsoft Dynamics NAV
Patterns described to be used with Microsoft Dynamics NAV
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev
alguidelines.dev - Business Central Design Patterns
-alguidelines.dev