Chapter 9. Successful Conclusions

 

"The most powerful designs are always the result of a continuous process of simplification and refinement."

 
 --Kevin Mullet
 

"All the good ideas never lie under one hat."

 
 --Dale Turner

Each new version of NAV includes new features and capabilities. NAV 2015 is no exception. It is our responsibility to understand how to apply these new features, to use them intelligently in our designs, and to develop with both their strengths and limitations in mind. The new features in NAV 2015 include new ways to debug our work and new ways to deliver information to our users. Our goal in the end is not only to provide workmanlike results but, if possible, to delight our users with the quality of the experience and the ease of use of our products.

In this chapter, we will:

  • Review NAV objects that contain functions we can use directly or as templates in our solutions
  • Review some of the primary NAV C/SIDE tools that help us debug our solutions
  • Learn about the way we can enhance our solutions using external controls integrated into NAV
  • Discuss design, development, and delivery issues that should be addressed in our projects.

Creating new C/AL routines

Now that we have a good overall picture of how we enable users to access the tools that we have created, we are ready to start creating our own NAV C/AL routines. It is important that we learn our way around the NAV C/AL code in the standard product first. You may recall the advice in a previous chapter that the new code we create should be visually and logically compatible with what already exists. If we think of our new code as a guest being hosted by the original system, we will be doing what any thoughtful guest does – fitting smoothly into the host's environment.

An equally important aspect of becoming familiar with the existing code is to increase the likelihood we can take advantage of the features and components of the standard product to address some of our application requirements. There are at least two types of existing NAV C/AL code, of which we should make use whenever appropriate.

One group is the callable functions that are used liberally throughout NAV. Once we know about these, we can use them in our logic whenever they fit. There is no documentation for most of these functions, so we must either learn about them here or by doing our homework, studying the NAV code. The second group includes the many code snippets we can copy when we face a problem similar to something the NAV developers have already addressed.

The code snippets differ from the callable functions in two ways. First, they are not structured as coherent and callable entities. Second, they are likely to serve as models - code that must be modified to fit the situation (for example, changing variable names, adding or removing constraints, and so on).

In addition to the directly usable C/AL code, we should also make liberal use of the NAV Design Patterns Repository located at: https://community.dynamics.com/nav/w/designpatterns/105.nav-design-patterns-repository.aspx

NAV Design Patterns provide common definitions of how certain types of functions are implemented in NAV. Pattern examples include:

  • Copy Document
  • Create Data from Templates
  • No. Series
  • Single-Record (Setup) Table
  • Master Data

There are many others and new pattern definitions are added often.

Callable functions

Most of the callable functions in NAV are designed to handle a very specific set of data or conditions and have no general-purpose use (for example, the routines for updating Check Ledger entries during a posting process are likely to apply only to that specific function). If we are making modifications to a particular application area within NAV, we may find functions that we can utilize, either as is or as models for our new functions.

There are quite a few functions within NAV that are relatively general purpose. They either act on data that is common in many different situations (such as dates) or they perform processing tasks that are common to many situations (such as providing access to an external file). We will review a few such functions in detail, then list a number of others worth studying. If nothing else, these functions are useful as guides for "here is how NAV does it". The various parameters in these explanations are named to assist with our learning and not named the same as in the NAV code (though all structures, data types, and other technical specs match the NAV code).

If we are going to use one of these functions, we must take care to clearly understand how it operates. In each case, we should study the function and test with it before assuming that we understand how it works. There is little or no documentation for most of these functions, so understanding their proper use is totally up to us. If we need a customization, that must be done by making a copy of the target function and then modifying the copy.

Codeunit 358 – Date FilterCalc

This codeunit is a good example of how a well designed and well written code has long term utility. If we look at the Object Designer information for this codeunit, we will see that it originated in NAV (Navision) V3.00 in 2001. That doesn't mean it is out of date; it means that it was well thought out and complete.

Codeunit 358 contains two functions we can use in our code to create filters based on the Accounting Period Calendar. The first is CreateFiscalYearFilter. If we are calling this from an object that has Codeunit 358 defined as a Global variable named DateFilterCalc, our call would use the following syntax:

DateFilterCalc,CreateFiscalYearFilter
       (Filter,Name,BaseDate,NextStep)

The calling parameters are Filter (text, length 30), Name (text, length 30), BaseDate (date), and NextStep (integer).

The second such function is CreateAccountingPeriodFilter that has the following syntax:

DateFilterCalc.CreateAccountingPeriodFilter
          (Filter,Name,BaseDate,NextStep)

The calling parameters are Filter (text, length 30), Name (text, length 30), BaseDate (date), and NextStep (integer).

In the following code screenshot from Page 151 – Customer Statistics, we can see how NAV calls these functions. Page 152 – Vendor Statistics, Page 223 – Resource Statistics, and a number of other Master table statistics forms also use this set of functions:

Codeunit 358 – Date FilterCalc

In the next code screenshot, NAV uses the filters stored in the CustDateFilter array to constrain the calculation of a series of FlowFields for the Customer Statistics page:

Codeunit 358 – Date FilterCalc

When one of these functions is called, the Filter and Name parameters are updated within the function, so we can use them as return parameters, allowing the function to return a workable filter and a name for that filter. The filter is calculated from the BaseDate and NextStep we supply.

The returned filter is supplied back in the format of a range filter string, 'startdate..enddate' (for example, 01/01/16..12/31/16). If we call CreateFiscalYear, the Filter will be for the range of a fiscal year, as defined by the system's Accounting Period table. If we call CreateAccountingPeriodFilter, the Filter will be for the range of a fiscal period, as defined by the same table.

The dates of the Period or Year filter returned are tied to the BaseDate parameter, which can be any legal date. The NextStep parameter tells which period or year to use, depending on which function is called. A NextStep = 0 says use the period or year containing the BaseDate, NextStep = 1 says use the next period or year into the future, and NextStep = -2 says use the period or year before last (go back two periods or years).

The Name value returned is also derived from the Accounting Period table. If the call is to CreateAccountingPeriodFilter, then Name will contain the appropriate Accounting Period Name. If the call is to CreateFiscalYearFilter, then Name will contain 'Fiscal Year yyyy', where yyyy will be the four-digit numeric year.

Codeunit 359 – Period Form Management

This codeunit contains three functions that can be used for date handling. They are FindDate, NextDate, and CreatePeriodFormat.

  • FindDate function
    • Calling Parameters (SearchString (text, length 3), Calendar (Date table), PeriodType (Option, integer))
    • Returns DateFound Boolean
      FindDate(SearchString,CalendarRec,PeriodType)

This function is often used in pages to assist with the date calculation. The purpose of this function is to find a date in the virtual Date table based on the parameters passed in. The search starts with an initial record in the Calendar table. If we pass in a record that has already been initialized by positioning the table at a date, then that will be the base date, otherwise the Work Date will be used.

PeriodType is an Option field with the option value choices of day, week, month, quarter, year, and accounting period. For ease of coding, we could call the function with the integer equivalent (0, 1, 2, 3, 4, 5) or set up our own equivalent Option variable. In general, it's a much better practice to set up an Option variable because the Option strings make the code self-documenting.

SearchString allows us to pass in a logical control string containing =, >, <, <=, >=, and so on. FindDate will find the first date starting with the initialized Calendar date that satisfies the SearchString logic instruction and fits the PeriodType defined. For example, if the PeriodType is day and the date 01/25/16 is used along with the SearchString of >, then the date 01/26/16 will be returned in Calendar.

  • NextDate function
    • Calling Parameters (NextStep (integer), Calendar (Date table), PeriodType (Option, integer))
    • Returns Integer:
      IntegerVariable := NextDate(NextStep,CalendarRec,PeriodType)

NextDate will find the next date record in the Calendar table that satisfies the calling parameters. The Calendar and PeriodType calling parameters for FindDate have the same definition as they do for the FindDate function. However, for this function to be really useful, Calendar must be initialized before calling NextDate—otherwise, the function will calculate the appropriate next date from day 0. The NextStep parameter allows us to define the number of periods of PeriodType to move, so as to obtain the desired next date. For example, if we start with a Calendar table positioned on 01/25/16, PeriodType of quarter (that is 3), and NextStep of 2, then NextDate will move forward two quarters and return with Calendar focused on Quarter 7/1/16 to 9/30/16.

  • CreatePeriodFormat function
    • Calling Parameters (PeriodType (Option, integer), Date (date))
    • Returns Text, length 10
      FormattedDate := CreatePeriodFormat(PeriodType,DateData)

CreatePeriodFormat allows us to supply a date and specify which of its format options we want via PeriodType. The function's return value is a ten-character formatted text value; for example, mm/dd/yy, ww/yyyy, mon/yyyy, qtr/yyyy, or yyyy.

Codeunit 365 – Format Address

The functions in the Format Address codeunit do the obvious, they format addresses in a variety of situations. The address data in any master record (Customer, Vendor, Sales Order Sell-to, Sales Order Ship-to, Employee, and so on) may contain embedded blank lines. For example, the Address 2 line may be empty. When we print out the address information on a document or report, it will look better if there are no blank lines. These functions take care of such tasks.

In addition, NAV provides setup options for multiple formats of City – Post Code – County – Country combinations. The Format Address functions format addresses according to what was chosen in the setup or was been defined in the Countries/Regions page for different postal areas.

There are over 60 data-specific functions in the Format Address codeunit. Each data-specific function allows us to pass a record parameter for the record containing the raw address data (such as a Customer record, a Vendor Record, a Sales Order, and so on) plus a parameter of a one-dimensional Text array with 8 elements of length up to 90 characters. Each function extracts the address data from its specific master record format and stores it in the array. The function then passes that data to a general-purpose function, which does the actual work of re-sequencing according to the various setup rules and compressing the data by removing blank lines.

The following are examples of function call format for the functions for Company and the Sales Ship-to addresses. In each case, AddressArray is Text, Length 90, and one-dimensional with 8 elements.

"Format Address".Company(AddressArray,CompanyRec);
"Format Address".SalesHeaderShipTo(AddressArray,SalesHeaderRec);

The function's processed result is returned in the AddressArray parameter.

In addition to the data-specific functions in the Format Address codeunit, we can also directly utilize the more general-purpose functions contained there. If we add a new address structure as part of an enhancement, we may want to create our own data-specific address formatting function in our custom codeunit. But we should design our function to call the general purpose functions that already exist (and are already debugged).

The primary general-purpose address formatting function (the one we are most likely to call directly) is FormatAddr. This is the function that does most of the work in this codeunit. The syntax for the FormatAddr function is as follows:

FormatAddr(AddressArray,Name,Name2,ContactName,Address1,Address2,
         City,PostCode,County,CountryCode)

The calling parameters of AddressArray, Name, Name2, and ContactName are all Text, length 90. Address1, Address2, City, and County are all Text, length 50. PostCode and CountryCode are data type Code, length 20 and length 10, respectively.

Our data is passed into the function in the individual Address fields. The results are passed back in the AddressArray parameter for us to use.

There are two other functions in the Format Address codeunit that are often called directly. They are FormatPostCodeCity and GeneratePostCodeCity. The FormatPostCodeCity function serves the purpose of finding the applicable setup rule for PostCode + City + County + Country formatting. It then calls the GeneratePostCodeCity function, which does the actual formatting.

Accompanying the defined NAV Patterns (on the same website as the Patterns), there is a section entitled "Recipes – The NAV C/AL Cookbook". One of those recipes, "Address Integration", applies to the preceding section on address formatting and provides a presentation on this topic at https://community.dynamics.com/nav/w/designpatterns/234.address-integration.aspx.

Codeunit 396 – NoSeriesManagement

Throughout NAV, master records (for example Customer, Vendor, Item, and so on) and activity documents (Sales Order, Purchase Order, Warehouse Transfer Orders, and so on) are controlled by the unique identification number assigned to each one. This unique identification number is assigned through a call to a function within the NoSeriesManagement codeunit. That function is InitSeries. The calling format for InitSeries is as follows:

NoSeriesManagement.InitSeries(WhichNumberSeriesToUse, LastDataRecNumberSeriesCode, SeriesDateToApply, NumberToUse, NumberSeriesUsed)

The parameter WhichNumberSeriesToUse is generally defined on a Numbers Tab in the Setup record for the applicable application area. LastDataRecNumberSeriesCode tells the function what Number Series was used for the previous record in this table. The SeriesDateToApply parameter allows the function to assign ID numbers in a date-dependent fashion. NumberToUse and the NumberSeriesUsed are return parameters.

The following screenshot shows an example for Table 18 – Customer:

Codeunit 396 – NoSeriesManagement

The next screenshot shows a second example for Table 36 – Sales Header. In this case, the call to NoSeresMgt has been placed in a local function:

Codeunit 396 – NoSeriesManagement

With the exception of GetNextNo (used in assigning unique identifying numbers to each of a series of transactions) and possibly TestManual (used to test if manual numbering is allowed), we are not likely to use other functions in the NoSeriesManagement codeunit. The other functions are principally used either by the InitSeries function or other NAV routines whose job it is to maintain Number Series control information and data.

There is also a NAV Pattern defined describing the use of number series in NAV. It is titled "No. Series".

Function models to review and use

It is very helpful when we're creating new code to have a model that works which we can study (or clone). This is especially true in NAV where there is little or no development "how to" documentation available for many of the different functions we would like to use. One of the more challenging aspects of learning to develop in the NAV environment is learning how to handle issues in the "NAV way". Learning the "NAV way" is very beneficial because then our code works better, is easier to maintain, and is easier to upgrade. There is no better place to learn the strengths and subtle features of the product than to study the code written by the developers who are part of the inner circle of NAV creation.

Tip

If there is a choice, don't add custom functions to the standard NAV Codeunits. Well segregated customizations in clearly identified custom objects make both maintenance and upgrades easier. When we build functions modeled on NAV functions, the new code should be in a customer licensed codeunit.

A list of objects follows which contain functions we may find useful for use in our code or as models. We find these useful for studying how "it's" done in NAV ("it" obviously varies depending on the function's purpose).

  • Codeunit 1 – Application Management: A library of utility functions widely used in the system
  • Codeunits 11, 12, 13, 21, 22, 23, 80, 81, 82, 90, 91, 92 – the Posting sequences for Sales, Purchases, General Ledger, Item Ledger; these control the posting of journal data into the various ledgers
  • Codeunit 228 – Test Report-Print: Functions for printing Test Reports for user review prior to Posting data
  • Codeunit 229 – Print Documents: Functions for printing Document formatted reports.
  • Codeunits 397, 400 – Mail: Functions for interfacing with Outlook and SMTP mail
  • Codeunit 408 – Dimension Management: Don't write your own; use these
  • Codeunit 419 – 3-tier File Management: Functions including BLOB tasks, file uploading, and downloading
  • Codeunits 802 – Online Map interfacing
  • Codeunit 5054 – Word Management: Interfaces to Microsoft Word
  • Codeunit 5063 – Archive Management: Storing copies of processed documents
  • Codeunits 5300 thru 5313 – More Outlook interfacing
  • Codeunits 5813 thru 5819 – Undo functions
  • Codeunit 6224 – XML DOM Management for XML structure handling
  • Table 330 – Currency Exchange Rate: Contains some of the key currency conversion functions
  • Table 370 – Excel Buffer: Excel interfacing
  • Page 344 – Navigate: Home of the unique and powerful Navigate feature

Management codeunits

There are over 150 codeunits with the word "Management" or "Mgt" as part of their description name (filter the codeunits using *Management*|*Mgt*). Each of these codeunits contains functions in which the purpose is the management of some specific aspect of NAV data. Many are very specific to a narrow range of data. Some are more general, because they contain functions we can reuse in another application area (for example, Codeunit 396 – NoSeriesManagement).

When we are working on an enhancement in a particular functional area, it is extremely important to check the Management codeunits utilized in that area. We may be able to use some existing standard functions directly. This will have the benefit of reducing the code we have to create and debug. Of course, when a new version is released, we will have to check to see if the functions on which we relied have changed in a way that affects our code.

If we can't use the existing material as is, we may find functions we can use as models for tasks in the area of our enhancement. And, even if that is not true, by researching and studying the existing code, we will learn more about how data is structured and processes flow in the standard NAV system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset