Describing design patterns is something that has been done for various programming languages and business areas over the years. As well, Microsoft Dynamics NAV developers are using recurring solutions to solve common problems which are specific to enterprise resource planning software and even more, they are specific to the NAV inner workings. We are giving a name and documenting some of those reusable paradigms. Although the solution offered does not pretend to be the only or the best one at all times, we hope it will provide a good start for more technical discussions, ideas and knowledge sharing. It also offers ready-made recipes which can be reused during implementations.
The Reusable Dynamics NAV Patterns is a joint initiative and I would like to thank the NAV partners who have been here at Microsoft Development Center Copenhagen for the NAV Patterns workshop: Eric Wauters, Gary Winter, Mark Brummel and Claus Lundstrøm. We are looking forward to see more NAV Patterns being published from their side. Furthermore, this is an open initiative to anyone who has documented design patterns which are specific to NAV, please reach back to us either by leaving a comment here, or by writing to us. This being said, find below the NAV design pattern of the week.
The Blocked Entity pattern is used when it is required to stop transactions for an entity (mostly master data), temporarily or permanently.
In this pattern, the business entity holds a state that controls if a given transaction is allowed. The state is used by the logic controlling transactions. The change of state could either be temporary or permanent.
An example of a temporary halt is when a retail chain selling items has received lot of complaints about an item, and the company wants to stop all transactions, both purchase and sale, with that item until the dealer has clarified the issue with his supplier and possibly received a replacement for the defective stock. Another common example is during counting the physical inventory using cycle counting where the counting is done in one section of a warehouse at a time, so that the regular operations can continue in the other parts of the warehouse. In these situations, it is necessary to block all transactions, such as picks and put-aways, for a bin while warehouse counting is in progress for that bin.
In contrast, a permanent halt to transactions could be required when an item has become obsolete (or is about to become obsolete), and the company wants to stop further purchase or sale of the item. However, the company wants to maintain the transaction history of the item and, therefore, does not want to delete the item record.
A simple design implementation of such requirements in Microsoft Dynamics NAV is to add a Blocked field in the entity table (and on the associated page). The implementation takes this state into the logic and checks for the value of this field in related transactions. For most simple scenarios, it is sufficient to have two states on the Blocked field, specifying whether it is allowed to perform transactions for the entity or not.
In certain situations, however, there could be different levels of blocking. For example, the company could block all sales to a customer that has overdue payments, and the company does not want to allow transactions with this customer until the payments are received. In other situations, the customer may have raised objections about an invoice, and the company has decided not to generate new invoices for the customer until the issue has been resolved. However, the company does want to continue shipping goods to the customer so as not to impact the customer’s operations. In these scenarios, it may be necessary to have multiple states on the Blocked field depending on the level of restriction that is needed.
As mentioned in the previous section, there are two implementations of this pattern depending on business requirements: The 2-state Boolean field for simple implementations and the multi-state option field for more complex requirements. The implementation flow is similar for both patterns, except how the validation is implemented. The following discusses the two scenarios one by one.
Add a Boolean field named Blocked in the table.
In the relevant logic, add a condition to check the status of the Blocked flag. The cheapest way is to use a TESTFIELD:
Alternatively, you can throw a custom error message. However, you should only do that if the default error message thrown by TESTFIELD is not sufficient.
Add an option field named Blocked in the table. The option values will reflect the different blocked states required by the company.
Add this field on the card page (or on the List page if the entity does not have a card). As with the Boolean implementation, the convention is to add this field in the right-hand column in the General FastTab of the card page.
Implement a function in the table that takes the transaction context as input and evaluates the Blocked field to decide whether the transaction should be allowed or not. Optionally, the function can be responsible for notifying the user and bubble up an error message straight away.
An example of the Boolean implementation on the Item card.
In codeunit 22 – Item Jnl.-Post Line, the following lines of code have implemented a check based on the value of the Blocked field:
IF NOT CalledFromAdjustment THEN
An example of the option field implementation on the Customer card.
The CheckBlockedCustOnDocs and CheckBlockedCustOnJnls functions in the Customer table are responsible for validating the Blocked state with respect to the input document type. These functions are invoked in several areas, such as posting routines, where a status check on the Blocked field is required. This is a good practice where the Blocked implementation gets more complex, as this encourages reuse and ensures uniformity of implementation.
Entities where the Blocked Entity pattern has been implemented include:
Bogdana Botez and the Reusable Dynamics NAV Patterns team
Thanks to Abhishek Ghosh for documenting this pattern.
Nice post and obviously nice serie to come !
I remember having reinvented the wheel when I had to format the date on a report before figuring out that there was a built in function to do the job :D
Hopefully it will prevent lot of people from doing the same mistake !
I see there is a better future coming :)