Development Tips, Excel, How To, Jet Reports, Office Integration, Report

Creating Simple List Report in Excel Using Jet Reports Part-2

In my previous post we saw how to create simple report in excel using Jet Report.

If not seen please refer it before you continue with this post, here is the link for same:

Creating Simple List Report in Excel Using Jet Reports Part-1

Using NL Lookup Part-1

Here we will start from where we left in previous post.

We will add one more sheet in Report we created in our previous post, and name it is as Option, where we will define all of our Filters.

Our Option sheet will look as below:
JetSimpleReport-7
Here we have created 3 Filters Customer No., Credit Limit LCY & Balance LCY.

Next Step will be to apply this Filter provided by user at runtime to the Report.

Return to your Report Sheet and edit the NL Function used to retrieve Rows from Customer as below:
JetSimpleReport-8
(*) in filter denotes all, in other words no Filter.

Now let see the Filter Sheet how it behaves when we run the report.

When we run the report first Report option is shown, where we will give our Filters:
JetSimpleReport-9

Here I am giving below filters:

Customer No. Filter                         *              Include All Customers

Credit Limit (LCY) Filter                  0              All rows with Credit Limit as Zero

Balance (LCY) Filter                      >0             All rows with Balance value greater than Zero

The output of the report should be as below:

JetSimpleReport-10

Stay tuned for more details in my future posts.

I will explain more about commands, filters, functions, lookup etc.…

Development Tips, Excel, How To, Jet Reports, Office Integration, Report

Using NL( Lookup ) in Jet Reports Part-1

The NL(“Lookup”) function can be used to provide Lookup to the Users so that he can select from a specified list of values when setting their report filters. This will allow them to see the list of options available to them in regards to a particular report filter.

The most common (and basic) use of the NL(“Lookup”) function is to simply pull a list of values from the database.

For example, if a list of customer numbers (“No.”) from the “Customer” table is desired then the function would look something like this:

=NL(“Lookup”,”Customer”,”No.”)

The resulting lookup that the user sees would be:

Lookup-1

It is also possible to allow the user to see more than one value from a particular table. This can help the user to make a choice more easily by displaying additional details about the values returned.

Multiple fields can be displayed by placing them in an array. This is accomplished by placing the list of fields to be displayed, separated by commas, in the Field parameter and surrounding it with curly braces.

If the fields to be shown are the “Name” and the “Country/Region Code” associated with each customer “No.”, the resulting function would look something like this:

=NL(“Lookup”,”Customer”,{“No.”,”Name”,”Country/Region Code”})

The resulting lookup would be:

Lookup-2

NOTE: The first field in the array is the field that will be returned by the Lookup form.

In addition to selecting multiple fields to be displayed in the list, it is also possible to customize the headers, that appear at the top of the Lookup window. This can be done by placing “Headers=” in one of the FilterField parameters of the NL(“Lookup”) function.

For example, instead of the field names appearing as “No.”, “Name”, and “Country/Region Code”, it has been decided that they should be displayed as “Cust. No.”,”Cust. Name”, and “Cust. State” to the user.

To do this, “Headers=” will be added in one of the FilterField parameters, and the desired names will be placed in the associated Filter parameter. The function should look like this:

=NL(“Lookup”,”Customer”,{“No.”,”Name”,”Country/Region Code”},”Headers=”,{“Cust. No.”,”Cust. Name”,”Cust. State”})

The resulting Lookup window would now appear as:

Lookup-3

In addition to returning a list of values from the database, it is also possible to manually specify the values that will be returned.

This allows you to present the user with a list of values that are not stored in your database. The syntax that will be used is slightly different. Since data is no longer being returned directly from the database, the Table parameter is no longer used to specify the table that the information will pull from. Instead, an array containing the values to be displayed is placed in the Table parameter of the Lookup function. The Field parameter will then contain the list of column headers of the Lookup window.

To create an NL(“Lookup”) function that will display “East”, “West”, “North”, and “South” for Directions, the function will be:

=NL(“Lookup”,{“East”,”West”,”North”,”South”},”Direction”)

The resulting lookup window would now be:
Lookup-4
NOTE: It is important to place the field name that will be displayed at the top of the Lookup window (in this example “Direction”) in the Field parameter. Omitting this will not display any values in the Lookup Window.

In addition to placing the values in the NL(“Lookup”) function itself, a cell reference can also be used. The following example will display the exact same result as the previous example, but the values are specified by a cell reference instead of text.

It is also possible to display multiple columns in the Lookup Window by utilizing cell references. To achieve this, another column of values will need to be inserted next to the values that we are already displaying. Once this is done, the cell reference in the NL(“Lookup”) function will also need to be expanded to encompass both columns of data. Since multiple columns are now being specified, names for these columns will also need to be defined in the NL(“Lookup”) function as well. This is done by using the array syntax that was described above in order to specify the field names in the Field parameter, in this case “Direction” and “Description”.

=NL(“Lookup”,F5:G8,{“Direction”,”Description”})

Below is an example of what this would look like:

Lookup-5

Will come up with more details in my next post on this.

Stay tuned for more details in my upcoming post.

Development Tips, Excel, How To, Jet Reports, Office Integration, Report

Creating Simple List Report in Excel Using Jet Reports Part-1

Dear friends I will discuss today simple report creating in Jet Reports.

I will take a simple example for creating Customer List showing the Credit Limit & Balances.

We will be using two basic Functions of Jet Reports NL & NF.

Then we will add few more features in my next post on this report.

Let’s Start Step wise Step:

Step 1: Add NL Function to retrieve Records from Customer Table.
JetSimpleReport-1
I have Add NL Function in Cell E5 as shown above, if want to add using Jfx – NL place a Cursor in E5 and press NL from Jfx Group of functions and fill as below:
JetSimpleReport-2

Step 2: Add Fields which you wish to include in your Report using NF Jfx Function.

I am adding No. field from Customer Table.

Here we have already created the connection to Customer Table in previous Step. This will retrieve all Fields and Records from the Customer Table.

Using NF function I am selecting the Fields of which we want to show/include value in our Report.

I have add the Function in Excel as shown below:
JetSimpleReport-3
I have Add NF Function in Cell F5 as shown above, if want to add using Jfx – NF place a Cursor in F5 and press NF from Jfx Group of functions and fill as below:
JetSimpleReport-4

Step 3: Following Step 2 add all other Fields.

The Excel should look as below:
JetSimpleReport-5

I have Added fields No., Name, Credit Limit (LCY), Balance (LCY).

I have also added Heading for these fields, and applied general Excel Formatting.

The Column E with NL function, I have Hide from the Report Output as the information is having no relevance showing to User.

Now we are god to see the output of our Report Created above. Output format of this report will be as below:
JetSimpleReport-6

Stay tuned to have more updates in my upcoming posts.

Development Tips, Jet Reports, Office Integration, Report

What’s New in Jet Reports for Word, How it is different from Navision Word Reports

Before we compare both the way of creating report in word, the features I would be suggesting you to review the posts which I have posted earlier Word Document Reports and Custom Layouts to refresh the concept of creating reports in Word.

Let’s start with comparing how it is different from Navision Word Report.

Create a custom layout for the report you wish to use

In your NAV client navigate to Report Layout Selection (Administration/IT Administration/ Reports).

Microsoft Dynamics NAV 2015 includes several sample Word reports including:

14125500             Sales Order – Jet Ex. Word

14125501             Sales Invoice – Jet Ex. Word

14125502             Sales Cr. Memo – Jet Ex. Word

14125504             Sales Quote – Jet Ex. Word

I have filtered the above Reports.

Select the report that you wish to customize. (I am Using 14125500 for this example)
CustomiseJetReport-1
Click Custom Layouts.

 To create a new Report Layout, click New.

A pop-up window will appear and allow you to choose the layout type.

Check the Insert Word Layout box and click OK.

CustomiseJetReport-2

CustomiseJetReport-3

In the Report Layouts window, you can change the Description.

Click OK

In the NAV Custom Report Layouts window, highlight the layout you wish to use and click the Import Layout button from the ribbon.

Browse to the Jet Express for Word Sample Documents, choose the template you want and click Open
CustomiseJetReport-4
Click Edit Layout to customize this layout.

CustomiseJetReport-5

Above screenshot show how to Access the XML part of the Report.

Left side shows Jet->Design

Right side shows Developer->XML Mapping Pane

If you remember In Navision word Report we use to select the Custom XML Part from the dropdown to access the available fields, Labels etc.

Whereas if we see In Jet Report this is not required.

Also you may have observed that Jet Report Pane Have search option, which makes easy to find desired fields rather than scrolling through the XML Nodes to access the desired Fields.
CustomiseJetReport-6

You may observe in above picture that I have typed the part of the Field I am looking for and Jet Report Pane suggested that Similar to what I typed there is a Field “Salesperson” and it available under 2 heads Labels & Header data items.

If I require to insert the Labels or Fields, Place the cursor at desired place where you want that Field to be inserted and Double Click to the Field from Jet Report Pane.
CustomiseJetReport-7
Where as to perform same action in Navision Word Place the cursor where we wish to Insert the Field then we use to Scroll to the Field we wish to insert then we perform step Right Click->Insert Content Control->Plain Text
CustomiseJetReport-8
I will come up with more details in my next post. We will see how we can design the Report Using Jet Report fast and easily.

Also some Best Practice, Tip & Tricks while using Jet Reports.

Development Tips

Not supported in Microsoft Dynamics NAV 2015

The following table provides an overview of the removed C/AL data types, functions, properties, and triggers in Microsoft Dynamics NAV 2015 since the previous version of Microsoft Dynamics NAV.

Data type, function, property, or trigger Not supported in Microsoft Dynamics NAV 2015  
BEEP Function Not supported on Microsoft Dynamics NAV Server.
Binary Data Type The Binary data type, used in earlier versions of Microsoft Dynamics NAV to store fixed lengths of binary data in a record, is not supported in Microsoft Dynamics NAV 2015. If you previously used the BINARY data type, consider using the BLOB Data Type instead.
BottomMargin Property Not supported in Microsoft Dynamics NAV 2015 reports.
COMMANDLINE Function Not supported in Microsoft Dynamics NAV 2015.
COUNTAPPROX Function Not supported in Microsoft Dynamics NAV 2015.
CREATETOTALS Function Redundant in Microsoft Dynamics NAV 2015 reports. We recommend that you use the SUM function in Visual Studio instead.
Dataports Not supported in Microsoft Dynamics NAV 2015. Use XMLports instead.
ENVIRON Function Not supported in Microsoft Dynamics NAV 2015.
EXPORT Function (BLOB) Not supported in Microsoft Dynamics NAV 2015.
EXPORTOBJECTS Function Not supported in Microsoft Dynamics NAV 2015. Use the finsql.exe executable with the ExportObjects command instead.
Forms Not supported in Microsoft Dynamics NAV 2015.
IMPORT Function (BLOB) Not supported in Microsoft Dynamics NAV 2015.
IMPORTOBJECTS Function Not supported in Microsoft Dynamics NAV 2015. Use the finsql.exe executable with the ImportObjects command instead.
ISSERVICETIER Function Obsolete in Microsoft Dynamics NAV 2015, but still supported. This function always returns true.
KeyGroups Property Not supported in Microsoft Dynamics NAV 2015.

Optionally, you can build indexes in SQL Server management tools.

LANGUAGE function Not supported in Microsoft Dynamics NAV 2015.
NEWPAGE Function Not supported in Microsoft Dynamics NAV 2015 reports.
NEWPAGEPERRECORD Function Not supported in Microsoft Dynamics NAV 2015 reports.
OBJECTID Function Not supported in Microsoft Dynamics NAV 2015 reports.
OnCreateHyperlink Trigger Not supported in Microsoft Dynamics NAV 2015 reports.
OnHyperlink Trigger Not supported in Microsoft Dynamics NAV 2015 reports.
OnPreSection Trigger Not supported in Microsoft Dynamics NAV 2015 reports.
OnPostSection Trigger Not supported in Microsoft Dynamics NAV 2015 reports.
OSVERSION Function Not supported in Microsoft Dynamics NAV 2015.
PAGENO Function Not supported in Microsoft Dynamics NAV 2015 reports.
PAPERSOURCE Function Not supported in Microsoft Dynamics NAV 2015 reports.
PaperSourceOtherPages Property Not supported on Microsoft Dynamics NAV 2015 reports.
RECORDLEVELLOCKING Function (Record and RecordRef) Not used in Microsoft Dynamics NAV 2015. The function is still available and compiles but always returns true.
READCONSISTENCY Function (Record and RecordRef) Not used in Microsoft Dynamics NAV 2015. The function is still available and compiles but because Microsoft Dynamics NAV 2015 uses SQL Server’s locking mechanisms and does not use snapshots like earlier versions of Microsoft Dynamics NAV, the return value is always false.
RequestOptionsForm system variable Not supported in Microsoft Dynamics NAV 2015.
SAVEASHTML Function Not supported in Microsoft Dynamics NAV 2015 reports.
SAVEASXML Not supported in Microsoft Dynamics NAV 2015 reports.
SETPERMISSIONFILTER Function (Record) Not supported in Microsoft Dynamics NAV 2015. Instead, you change the SecurityFiltering Property from Validated to Filtered.
SETPERMISSIONFILTER Function (RecordRef) Not supported in Microsoft Dynamics NAV 2015. Instead, you change the SecurityFiltering Property from Validated to Filtered.
SaveTableView property Not supported in Microsoft Dynamics NAV 2015.
SHELL Function Not supported in Microsoft Dynamics NAV 2015.
SHOWOUTPUT Function Not supported in Microsoft Dynamics NAV 2015 reports.
SYNCHRONIZEALLLOGINS Function Not supported in Microsoft Dynamics NAV 2015.
SYNCHRONIZESINGLELOGIN Function Not supported in Microsoft Dynamics NAV 2015
TOTALSCAUSEDBY Function Not supported in Microsoft Dynamics NAV 2015 reports.
URL Function Not supported on Microsoft Dynamics NAV 2015 reports.
VARIABLEACTIVE Function Not supported in Microsoft Dynamics NAV 2015.
VISIBLE Function Not supported in Microsoft Dynamics NAV 2015.
YIELD Function Not supported on Microsoft Dynamics NAV Server.
Development Tips, License, Multitenancy, Server

Uploading License to Tenant in Multitenant Environment

When we deploy solution for Multitenant Environment ever Tenant will be required a Separate License. Depending upon the License agreement with Microsoft every Tenant will either share same License or individual License.

Assume we are implementing Distributor Management System. Where every Tenant is a different Business entity linked with the Parent Group.

In this case the Server & Network is provided by the Parent Group and other Business group will share information but they will use their specific License to use the system, doesn’t matter who pays for fee.

In any case we need to upload License to each database in Multitenancy.

Import-NAVServerLicense

Imports a license file into a Microsoft Dynamics NAV database.

Syntax

Parameter Set: __AllParameterSets

Import-NAVServerLicense [-ServerInstance] <String> [-Database <LicenseDatabase> ] [-Force] [-Tenant <TenantId> ] [-Confirm] [-WhatIf] [ <CommonParameters>]

Parameter Set: LicenseDataSet

Import-NAVServerLicense [-LicenseData] <Byte[]> [-Force] [-Confirm] [-WhatIf] [ <CommonParameters>]

Parameter Set: LicenseFileSet

Import-NAVServerLicense [-LicenseFile] <String> [-Force] [-Confirm] [-WhatIf] [ <CommonParameters>]

Detailed Description

Use the Import-NAVServerLicense cmdlet to import a license file into a Microsoft Dynamics NAV database. If the Microsoft Dynamics NAV Server account specified does not have access to the location where the license file is stored, an error results. Check the Event Log on the Microsoft Dynamics NAV Server computer to see what permissions are required.

After importing a new license, restart all Microsoft Dynamics NAV Server instances to activate the license for client users.

Parameters

-Database<LicenseDatabase>

Specifies the database into which to import the license file. The possible values are described in the following list:

Default = 0

Default; overrides the license file currently in use.

Master = 1

Forces the license file to be global.

NavDatabase = 2

Forces the license file to be local and stored in the Microsoft Dynamics NAV database that is used by the specified Microsoft Dynamics NAV Server instance.

Tenant = 3

Forces the license file to be local and stored in the Microsoft Dynamics NAV database that is used by the tenant that is specified in the Tenant parameter.

Aliases none
Required? false
Position? named
Default Value none
Accept Pipeline Input? false
Accept Wildcard Characters? false

-Force

Forces the command to run without asking for user confirmation.

Aliases none
Required? false
Position? named
Default Value none
Accept Pipeline Input? false
Accept Wildcard Characters? false

-LicenseData<Byte[]>

Specifies the content retrieved from the certificate file by using the Get-Content cmdlet. For more information, see the examples.

Aliases none
Required? true
Position? 2
Default Value none
Accept Pipeline Input? false
Accept Wildcard Characters? false

-LicenseFile<String>

Aliases none
Required? true
Position? 2
Default Value none
Accept Pipeline Input? false
Accept Wildcard Characters? false

-ServerInstance<String>

Specifies the name of a Microsoft Dynamics NAV Server instance. The default instance name is DynamicsNAV80. You can specify either the full name of an instance (such as MicrosoftDynamicsNavServer$myinstance) or the short name (such as myinstance).

Aliases none
Required? true
Position? 1
Default Value none
Accept Pipeline Input? True (ByValue, ByPropertyName)
Accept Wildcard Characters? false

-Tenant<TenantId>

Specifies the ID of the tenant in which you want to import the license, such as Tenant1. This parameter is required unless the specified service instance is not configured to run multiple tenants.

Aliases Id
Required? false
Position? named
Default Value none
Accept Pipeline Input? True (ByPropertyName)
Accept Wildcard Characters? false

-Confirm

Prompts you for confirmation before running the cmdlet.

Required? false
Position? named
Default Value false
Accept Pipeline Input? false
Accept Wildcard Characters? false

-WhatIf

Shows what would happen if the cmdlet runs. The cmdlet is not run.

Required? false
Position? named
Default Value false
Accept Pipeline Input? false
Accept Wildcard Characters? false

<CommonParameters>

This cmdlet supports the common parameters: -Verbose, -Debug, -ErrorAction, -ErrorVariable, -OutBuffer, and -OutVariable.

Inputs

The input type is the type of the objects that you can pipe to the cmdlet.

  • System.String

You can pipe a string that contains a Microsoft Dynamics NAV Server instance name to the cmdlet.

Outputs

The output type is the type of the objects that the cmdlet emits.

  • None

This cmdlet does not generate any output.

Examples

This example imports a license file that is named “fin.flf” from the current directory into the default database.

C:\PS>Import-NAVServerLicense DynamicsNAV80 -LicenseData ([Byte[]]$(Get-Content -Path “fin.flf” -Encoding Byte))

This example imports a license file that is named “fin.flf” from the current directory into the local Microsoft Dynamics NAV database that is used by the MyInstance Microsoft Dynamics NAV Server instance.

C:\PS>Import-NAVServerLicense MyInstance -LicenseData ([Byte[]]$(Get-Content -Path “fin.flf” -Encoding Byte)) -Database NavDatabase

This example imports a license file that is named “fin.flf” from the current directory into the master database.

C:\PS>Import-NAVServerLicense ‘MicrosoftDynamicsNavServer$MyInstance’ -LicenseData ([Byte[]]$(Get-Content -Path “fin.flf” -Encoding Byte)) -Database Master

This example imports a license file that is named “fin.flf” from the current directory into the database that is used by the specified tenant, Tenant1.

C:\PS>Import-NAVServerLicense ‘MicrosoftDynamicsNavServer$MyInstance’ -LicenseData ([Byte[]]$(Get-Content -Path “fin.flf” -Encoding Byte)) -Database Tenant –Tenant Tenant1

Let import the license to the Tenants which we created in our earlier post.

If you missed previous post you can find it here. Adding Tenants to multitenancy Environment

I have created the Folder and placed my Tenants License in this.

License-1

Set-ExecutionPolicy unrestricted -Force

Import-Module ‘C:\Program Files\Microsoft Dynamics NAV\80\Service\NavAdminTool.ps1’

Import-NAVServerLicense MTenantDemo -Tenant ‘Tenant-1’ -LicenseData ([Byte[]]$(Get-Content -Path “C:\User Data\NAV 2015\MultiTenantDemo\Tenant License\Tenant-1.flf” -Encoding Byte))

Import-NAVServerLicense MTenantDemo -Tenant ‘Tenant-2’ -LicenseData ([Byte[]]$(Get-Content -Path “C:\User Data\NAV 2015\MultiTenantDemo\Tenant License\Tenant-2.flf” -Encoding Byte))

Import-NAVServerLicense MTenantDemo -Tenant ‘Tenant-3’ -LicenseData ([Byte[]]$(Get-Content -Path “C:\User Data\NAV 2015\MultiTenantDemo\Tenant License\Tenant-3.flf” -Encoding Byte))

Import-NAVServerLicense MTenantDemo -Tenant ‘Tenant-4’ -LicenseData ([Byte[]]$(Get-Content -Path “C:\User Data\NAV 2015\MultiTenantDemo\Tenant License\Tenant-4.flf” -Encoding Byte))

Import-NAVServerLicense MTenantDemo -Tenant ‘Tenant-5’ -LicenseData ([Byte[]]$(Get-Content -Path “C:\User Data\NAV 2015\MultiTenantDemo\Tenant License\Tenant-5.flf” -Encoding Byte))

Copy the above Script and paste into the Microsoft Dynamics NAV 2015 Administration Shell.

License-2

Our License have now successfully uploaded to respective databases. As the message suggest we need to re-start the service so that new License comes into effect.

You can use above Script to Upload License to individual Tenants, License could be different or same depends how you discussed with Microsoft and purchased.

Development Tips, Office Integration

Using Automation to Create a Graph in Microsoft Excel

In this walkthrough, you will transfer data for top 10 Customers Sales Contribution to Microsoft Excel and create a graph.

This example shows how to handle enumerations by creating a graph in Excel that shows the distribution of Sales by Customer.

ExcelChart-1

You will run the codeunit directly from Object Designer. In a real application, you would call it from an appropriate place, such as from a menu or any other window.

About This Walkthrough

This walkthrough illustrates the following tasks:

  • Creating a codeunit that declares the Automation variables that are required for using Excel Automation.
  • Adding a function to calculate Top 10 Customers Sales Contribution.
  • Adding C/AL code to the codeunit to run the Automation object that opens Excel.
  • Adding C/AL code to the Automation codeunit to transfer data from a table record to Excel.
  • Adding C/AL code that creates a graph in Excel. 

Prerequisites 

To complete this walkthrough, you will need:

  • Microsoft Dynamics NAV 2015 with a developer license.
  • The CRONUS International Ltd. demo data company.
  • Microsoft Excel 2013 or Microsoft Excel 2010.

Creating the Codeunit and Declaring Variables

To create the codeunit and declare variables

  • To implement Automation in a codeunit, you define the Automation variables. To define an Automation variable, you specify an Automation server and the Automation object.
  • The language in the regional settings of your computer matches the language version of Microsoft Excel.
  • In Object Designer, choose Codeunit, and then choose the New button to create a new codeunit.
  • On the View menu, choose C/AL Globals.
  • On the Variables tab, add the following variables:

Note

For the Automation data type variables, the subtype Microsoft Excel 15.0/14.0 Object Library defines the Automation server, and the class specifies the Automation object of the Microsoft Excel 15.0/14.0 Object Library.

ExcelChart-2

Name DataType Subtype Length
xlApp Automation ‘Microsoft Excel 15.0 Object Library’.Application
xlBook Automation ‘Microsoft Excel 15.0 Object Library’.Workbook
xlSheet Automation ‘Microsoft Excel 15.0 Object Library’.Worksheet
xlChart Automation ‘Microsoft Excel 15.0 Object Library’.Chart
xlRange Automation ‘Microsoft Excel 15.0 Object Library’.Range
Cust Record Customer
Window Dialog
CustAmount Record Customer Amount
CustFilter Text
CustDateFilter Text 30
ShowType Option  [Sales (LCY),Balance (LCY)]
NoOfRecordsToPrint Integer
CustSalesLCY Decimal
CustBalanceLCY Decimal
MaxAmount Decimal
BarText Text 50
i Integer
TotalSales Decimal
TotalBalance Decimal
ChartType Option  [Bar chart,Pie chart]
ChartTypeNo Integer
ShowTypeNo Integer
ChartTypeVisible Boolean
Integer Record Integer
Customer Record Customer
CellNo1 Text 5
CellNo2 Text 5
  • Close the C/AL Globals window.

Adding the Code

Now you add the code for the codeunit.

To add the code

  • Add a Function to calculate Top 10 Customers Sales Contribution as:

ExcelChart-3
Add code to it as:

I have not used all the values, just shown this way also you can think of while you design any such code & functions.

Window.OPEN(Text000);

i := 0;

Cust.RESET;

IF Cust.FINDSET THEN

REPEAT

Window.UPDATE(1,Cust.”No.”);

Cust.CALCFIELDS(“Sales (LCY)”,”Balance (LCY)”);

IF (Cust.”Sales (LCY)” <> 0) OR (Cust.”Balance (LCY)” <> 0) THEN

BEGIN

CustAmount.INIT;

CustAmount.”Customer No.” := Cust.”No.”;

IF ShowType = ShowType::”Sales (LCY)” THEN BEGIN

CustAmount.”Amount (LCY)” := -Cust.”Sales (LCY)”;

CustAmount.”Amount 2 (LCY)” := -Cust.”Balance (LCY)”;

END ELSE BEGIN

CustAmount.”Amount (LCY)” := -Cust.”Balance (LCY)”;

CustAmount.”Amount 2 (LCY)” := -Cust.”Sales (LCY)”;

END;

CustAmount.INSERT;

IF (NoOfRecordsToPrint = 0) OR (i < NoOfRecordsToPrint) THEN

i := i + 1

ELSE BEGIN

CustAmount.FIND(‘+’);

CustAmount.DELETE;

END;

TotalSales += Cust.”Sales (LCY)”;

TotalBalance += Cust.”Balance (LCY)”;

ChartTypeNo := ChartType;

ShowTypeNo := ShowType;

END;

UNTIL Cust.NEXT = 0;

CustSalesLCY := Cust.”Sales (LCY)”;

CustBalanceLCY := Cust.”Balance (LCY)”;

Window.CLOSE;

IF CustAmount.FIND(‘-‘) THEN

REPEAT

CustAmount.”Amount (LCY)” := -CustAmount.”Amount (LCY)”;

Customer.GET(CustAmount.”Customer No.”);

Customer.CALCFIELDS(“Sales (LCY)”,”Balance (LCY)”);

IF MaxAmount = 0 THEN

MaxAmount := CustAmount.”Amount (LCY)”;

CustAmount.”Amount (LCY)” := -CustAmount.”Amount (LCY)”;

UNTIL CustAmount.NEXT = 0;

  • In the C/AL Editor, make call to above function by adding the following code to the OnRun trigger.

CustAmount.DELETEALL;

TopTenCustomer(10,ShowType::”Sales (LCY)”,ChartType::”Bar chart”);

  • Create an instance of Excel by adding the following code.

CREATE(xlApp, FALSE, TRUE);

  • Add a new workbook to Excel.

xlBook := xlApp.Workbooks.Add(-4167);

xlSheet:= xlApp.ActiveSheet;

xlSheet.Name := ‘Top 10 Customer’;

The following describes the code:

    • In the first line, you use the Add method of the Workbooks collection to return a new workbook. The attribute -4167 is the enumerator value of worksheets as they apply to Workbook objects.
    • In the second line, you use the ActiveSheet property of the Application class to ensure that what is done next affects the active sheet of the new workbook.
    • In the third line, you use the Name property to name the sheet.

Transferring Data

To transfer the data, you must calculate the data and transfer the results of the calculation.

To transfer data

  • In the C/AL Editor, on the codeunit, use following code to transfer data of Top 10 Customers to Excel. To transfer the data to Microsoft Excel, add the following code.

CellNo1 := ‘A1’;

CellNo2 := ‘B1’;

IF CustAmount.FINDSET THEN

REPEAT

CellNo1 := INCSTR(CellNo1);

xlSheet.Range(CellNo1).Value := CustAmount.”Customer No.”;

CellNo2 := INCSTR(CellNo2);

xlSheet.Range(CellNo2).Value := ABS(CustAmount.”Amount (LCY)”);

UNTIL CustAmount.NEXT = 0;

  • The final step is to create the graph. You will use the ChartWizard method to create chart. This is a fast and simple way to do it. You can more tightly control the design of the graph by setting it up using the methods and properties of the various Chart objects, such as ChartArea and Legend.

Creating the Graph

The final step is to create the graph. You will use the ChartWizard method to create chart. This is a fast and simple way to do it. You can more tightly control the design of the graph by setting it up using the methods and properties of the various Chart objects, such as ChartArea and Legend.

To create the graph

  •   In the C/AL Editor, on the current codeunit, define a range for the data in the graph.

xlRange := xlSheet.Range(‘A2:’+FORMAT(CellNo2));

  • Add a new chart sheet and give it a name.xlChart.Name := ‘ Top 10 Customer – Graph’;

xlChart := xlBook.Charts.Add;

xlChart.Name := ‘ Top 10 Customer – Graph’;

  • Create the graph.

xlChart.ChartWizard(xlRange,-4101,7,2,1,0,1,’Top 10 Customer’);

The following table describes the optional arguments that are used in the ChartWizard method.

Argument Description Value in method call
Source The range that contains the source data for the new chart. xlRange – The object returned by xlSheet.Range(‘A2:C3’).
Gallery The chart type. -4101 – The enumerator for the Chart Shown above.
Format The option number for the built-in auto formats. 7
PlotBy An integer specifying whether the data for each series is in rows or columns. 2 – The enumerator for the xlRows XlRowCol enumerator.
CategoryLabels An integer specifying the number of rows or columns within the source range that contains category labels. 1 – There is one row with category labels (the department names).
SeriesLabels An integer specifying the number of rows or columns within the source range that contains series labels. 0 – There are no series labels in your data.
HasLegend TRUE to include a legend. 1
Title VARIANT with the title of the chart. You pass a string such as ‘Top 10 Customer’.
  • Make Excel visible by adding the following code.

xlApp.Visible := TRUE;

Excel produces a General Protection Fault error when you close a new Excel worksheet that is created when Excel is invisible. To resolve this, you can make Excel visible immediately after you create a new worksheet. You can also make Excel visible just before you create a new Excel worksheet and then make it invisible again immediately after creating the new Excel worksheet. In this case, you would add the following code.

xlApp.Visible := TRUE;

xlBook := xlApp.Workbooks.Open(FileName);

xlApp.Visible := FALSE;

  •  Clearing the Temp Table by adding the following code.

CustAmount.DELETEALL;

  • Complete code in OnRun trigger should look like below:

ExcelChart-4
Saving and Running the Codeunit

You can test the codeunit for creating the graph by running the codeunit from Object Designer.

To save and run a codeunit

  1. On the File menu, choose Save.
  2. In the Save As window, enter an ID and name, and then choose the OK
  3. In Object Designer, select the codeunit, and then choose the Run

The Microsoft Excel graph should appear. As show above in beginning of the post.

Note

If you get an error states Old format or invalid type library, then make sure that the language in the regional settings of your computer matches the language version of Microsoft Excel.

Below detailed reference to the values used in above code:

 

XlChartType

Name Value Description
xl3DArea -4098 3D Area.
xl3DAreaStacked 78 3D Stacked Area.
xl3DAreaStacked100 79 100% Stacked Area.
xl3DBarClustered 60 3D Clustered Bar.
xl3DBarStacked 61 3D Stacked Bar.
xl3DBarStacked100 62 3D 100% Stacked Bar.
xl3DColumn -4100 3D Column.
xl3DColumnClustered 54 3D Clustered Column.
xl3DColumnStacked 55 3D Stacked Column.
xl3DColumnStacked100 56 3D 100% Stacked Column.
xl3DLine -4101 3D Line.
xl3DPie -4102 3D Pie.
xl3DPieExploded 70 Exploded 3D Pie.
xlArea 1 Area
xlAreaStacked 76 Stacked Area.
xlAreaStacked100 77 100% Stacked Area.
xlBarClustered 57 Clustered Bar.
xlBarOfPie 71 Bar of Pie.
xlBarStacked 58 Stacked Bar.
xlBarStacked100 59 100% Stacked Bar.
xlBubble 15 Bubble.
xlBubble3DEffect 87 Bubble with 3D effects.
xlColumnClustered 51 Clustered Column.
xlColumnStacked 52 Stacked Column.
xlColumnStacked100 53 100% Stacked Column.
xlConeBarClustered 102 Clustered Cone Bar.
xlConeBarStacked 103 Stacked Cone Bar.
xlConeBarStacked100 104 100% Stacked Cone Bar.
xlConeCol 105 3D Cone Column.
xlConeColClustered 99 Clustered Cone Column.
xlConeColStacked 100 Stacked Cone Column.
xlConeColStacked100 101 100% Stacked Cone Column.
xlCylinderBarClustered 95 Clustered Cylinder Bar.
xlCylinderBarStacked 96 Stacked Cylinder Bar.
xlCylinderBarStacked100 97 100% Stacked Cylinder Bar.
xlCylinderCol 98 3D Cylinder Column.
xlCylinderColClustered 92 Clustered Cone Column.
xlCylinderColStacked 93 Stacked Cone Column.
xlCylinderColStacked100 94 100% Stacked Cylinder Column.
xlDoughnut -4120 Doughnut.
xlDoughnutExploded 80 Exploded Doughnut.
xlLine 4 Line.
xlLineMarkers 65 Line with Markers.
xlLineMarkersStacked 66 Stacked Line with Markers.
xlLineMarkersStacked100 67 100% Stacked Line with Markers.
xlLineStacked 63 Stacked Line.
xlLineStacked100 64 100% Stacked Line.
xlPie 5 Pie.
xlPieExploded 69 Exploded Pie.
xlPieOfPie 68 Pie of Pie.
xlPyramidBarClustered 109 Clustered Pyramid Bar.
xlPyramidBarStacked 110 Stacked Pyramid Bar.
xlPyramidBarStacked100 111 100% Stacked Pyramid Bar.
xlPyramidCol 112 3D Pyramid Column.
xlPyramidColClustered 106 Clustered Pyramid Column.
xlPyramidColStacked 107 Stacked Pyramid Column.
xlPyramidColStacked100 108 100% Stacked Pyramid Column.
xlRadar -4151 Radar.
xlRadarFilled 82 Filled Radar.
xlRadarMarkers 81 Radar with Data Markers.
xlStockHLC 88 High-Low-Close.
xlStockOHLC 89 Open-High-Low-Close.
xlStockVHLC 90 Volume-High-Low-Close.
xlStockVOHLC 91 Volume-Open-High-Low-Close.
xlSurface 83 3D Surface.
xlSurfaceTopView 85 Surface (Top View).
xlSurfaceTopViewWireframe 86 Surface (Top View wireframe).
xlSurfaceWireframe 84 3D Surface (wireframe).
xlXYScatter -4169 Scatter.
xlXYScatterLines 74 Scatter with Lines.
xlXYScatterLinesNoMarkers 75 Scatter with Lines and No Data Markers.
xlXYScatterSmooth 72 Scatter with Smoothed Lines.
xlXYScatterSmoothNoMarkers 73 Scatter with Smoothed Lines and No Data Markers.

expression .ChartWizard(Source, Gallery, Format, PlotBy, CategoryLabels, SeriesLabels, HasLegend, Title, CategoryTitle, ValueTitle, ExtraTitle)

expression A variable that represents a Chart object.

Parameters

Name Required/Optional Data Type Description
Source Optional Variant The range that contains the source data for the new chart. If this argument is omitted, Microsoft Excel edits the active chart sheet or the selected chart on the active worksheet.
Gallery Optional Variant One of the constants of XlChartType specifying the chart type.
Format Optional Variant The option number for the built-in autoformats. Can be a number from 1 through 10, depending on the gallery type. If this argument is omitted, Microsoft Excel chooses a default value based on the gallery type and data source.
PlotBy Optional Variant Specifies whether the data for each series is in rows or columns. Can be one of the following XlRowCol constants: xlRows or xlColumns. Values can be [1 or 2]
CategoryLabels Optional Variant An integer specifying the number of rows or columns within the source range that contain category labels. Legal values are from 0 (zero) through one less than the maximum number of the corresponding categories or series.
SeriesLabels Optional Variant An integer specifying the number of rows or columns within the source range that contain series labels. Legal values are from 0 (zero) through one less than the maximum number of the corresponding categories or series.
HasLegend Optional Variant True to include a legend.
Title Optional Variant The chart title text.
CategoryTitle Optional Variant The category axis title text.
ValueTitle Optional Variant The value axis title text.
ExtraTitle Optional Variant The series axis title for 3-D charts or the second value axis title for 2-D charts.

Remarks

If Source is omitted and either the selection isn’t an embedded chart on the active worksheet or the active sheet isn’t an existing chart, this method fails and an error occurs.

You can use other values from above table to create graph of your choice.

Development Tips

How to list Virtual Tables in Navision

You may have seen several posts listing the Virtual tables. Most of they say you create page/form and type in one by one table id in Range (2000000001.. 2000000200) and find the Virtual Tables and note them.

Today I will demo you easy way for getting this list with no additional efforts.

You will get below table list in every posts. I have listed tables below in Nav-2015.

Object Designer Virtual Itself from Virtual Table
Type ID Name   Object Type Object ID Object Name
Yes Table 2000000001 Object
1 2000000004 Permission Set Table 2000000004 Permission Set
1 2000000005 Permission Table 2000000005 Permission
1 2000000006 Company Table 2000000006 Company
Yes Table 2000000007 Date
Yes Table 2000000009 Session
Yes Table 2000000020 Drive
Yes Table 2000000022 File
Yes Table 2000000026 Integer
Yes Table 2000000028 Table Information
Yes Table 2000000029 System Object
Yes Table 2000000038 AllObj
Yes Table 2000000039 Printer
Yes Table 2000000040 License Information
Yes Table 2000000041 Field
Yes Table 2000000043 License Permission
Yes Table 2000000044 Permission Range
Yes Table 2000000045 Windows Language
Yes Table 2000000048 Database
Yes Table 2000000049 Code Coverage
1 2000000053 Access Control Table 2000000053 Access Control
Yes Table 2000000055 SID – Account ID
Yes Table 2000000058 AllObjWithCaption
Yes Table 2000000063 Key
1 2000000065 Send-To Program Table 2000000065 Send-To Program
1 2000000066 Style Sheet Table 2000000066 Style Sheet
1 2000000067 User Default Style Sheet Table 2000000067 User Default Style Sheet
1 2000000068 Record Link Table 2000000068 Record Link
1 2000000069 Client Add-in Table 2000000069 Client Add-in
1 2000000071 Object Metadata Table 2000000071 Object Metadata
1 2000000072 Profile Table 2000000072 Profile
1 2000000073 User Personalization Table 2000000073 User Personalization
1 2000000074 Profile Metadata Table 2000000074 Profile Metadata
1 2000000075 User Metadata Table 2000000075 User Metadata
1 2000000076 Web Service Table 2000000076 Web Service
1 2000000078 Chart Table 2000000078 Chart
1 2000000079 Object Tracking Table 2000000079 Object Tracking
1 2000000080 Page Data Personalization Table 2000000080 Page Data Personalization
1 2000000100 Debugger Breakpoint Table 2000000100 Debugger Breakpoint
Yes Table 2000000101 Debugger Call Stack
Yes Table 2000000102 Debugger Variable
Yes Table 2000000103 Debugger Watch Value
1 2000000104 Debugger Watch Table 2000000104 Debugger Watch
1 2000000110 Active Session Table 2000000110 Active Session
1 2000000111 Session Event Table 2000000111 Session Event
1 2000000112 Server Instance Table 2000000112 Server Instance
1 2000000114 Document Service Table 2000000114 Document Service
1 2000000120 User Table 2000000120 User
1 2000000121 User Property Table 2000000121 User Property
1 2000000130 Device Table 2000000130 Device
Yes Table 2000000135 Table Synch. Setup

All marked as Yes in above table under Virtual column are all the Virtual Tables.

I have not type one by one in the Page/form to get this list.

The Virtual table itself in Navision lists the Virtual tables in Navision. List can be different depending on the Version of Navision you see them.

Today I will share you smart way of finding this list of Virtual tables.

Next time you need not to do so hard work to list all the Virtual tables.

Here too you need to create a list page but you will not be required to key in the id of tables one by one, in fact only one table id which will give answers to your query.
VirtualTables-1
Save and execute your Page/Form.

VirtualTables-2
Now go to object Designer. Copy all the tables with id in range defined above and paste in Excel.

Copy above table list in Excel side by side and compare as above table shown in beginning of the post. All those which don’t match are your Virtual tables.

So easy, if anything is available why to waste effort for same.

It always good to share what you know with community, by this way we keep learning from each other.

Stay tuned for many such Tips.

Development Tips, Office Integration, Report

Using Automation to Write a Letter in Microsoft Office Word

Automation lets you use the capabilities and features of Microsoft Office products, such as Microsoft Word or Microsoft Excel, in your Microsoft Dynamics NAV application.

Today we will implement Word Automation from a customer card in the Microsoft Dynamics NAV Windows client.

Note: The Microsoft Dynamics NAV Web client does not support automation.

Most information that we need to transfer to Word for this example is in the Customer table. The Customer table contains a FlowField called Sales (LCY) that contains the aggregated sales for the customer.

In this example we are learning about Automation, so we will use the existing value. In a real customer installation, we would need to set up an appropriate date filter to get the sales for the past year only.

We also need to retrieve the information about our own company that we will use in the letterhead and in the greeting of the letter. This information is contained in the Company Information and User tables.

  • The Automation server must be installed on the computer that compiles an object that uses Automation. If you must recompile and modify an object on a computer that does not have the Automation server installed, then you must modify the code to compile it again. We recommend that you isolate code that uses Automation in separate codeunits.
  • Performance can be an issue if extra work is needed to create an Automation server with the CREATE system call. If the Automation server is to be used repeatedly, then you will gain better performance by designing your code so that the server is created only once instead of making multiple CREATE and CLEAR calls).

Performance can be improved by putting the code on the customer card because you do not have to open and close Word for each letter that is created in the session.

You can work around this problem. If Word is already open when it is called from the code, then the running instance is reused. You can manually open Word or do not close Word after creating the first letter.

We will extract and transfer data one customer at a time. We will also initiate this processing and the subsequent processing in Word from the customer card.

We will insert fields into the Word template and give these fields convenient mnemonic names that correspond to the names of the record fields that we are using.

To make this work, C/AL code must make two extra calls to Microsoft Office Word. You must call the ActiveDocument.Fields.Update method before using the fields. After you have transferred all the information, you must call the ActiveDocument.Fields.Unlink method. This ensures that you can successfully use the Word fields as placeholders.

In addition, while you can name the Customer or Address fields, you must reference them by indexing into the Fields collection of the document. This can make the C/AL code harder to understand.

Creating the Word Template for Use by Automation

First, task is to create a Word template that we will use to create letters to customers that qualify for a discount. To create the template, we will add mail merge fields for displaying data that is extracted from Microsoft Dynamics NAV that you want included in the customer letter, such as the customer’s name, contact, and total sales.

You will create and save the template on the computer running the Microsoft Dynamics NAV Windows client, because you will configure the automation object to run on the client.

  • On the computer running Microsoft Dynamics NAV Windows client, open Word and create a new document.

WordAutomation-1

  • Choose where you want to insert the fields. Then, on the Insert tab, in the Text group, choose Quick Parts, and then choose Field.

WordAutomation-2

  • In the Categories list, select Mail Merge.
  • In the Field names list, select MergeField.
  • In the Field Name box under Field Properties, type Contact. This field will display the name of your contact person at the customer site as taken from the Customer table.
  • Choose OK to add the field.

WordAutomation-3

  • Repeat steps as above to add the remaining fields as follows:
Field name Description Underlying table
Name The name of the customer. Customer
Address The address of the customer. Customer
Sales (LCY) The total amount that the customer has purchased from you. Customer
Company Name The name of your company. Company Information
  • Save the Word document as a template with the name Discount.dotx in folder of your choice.

WordAutomation-4

Creating the Codeunit and Declaring the Variables

The next step is to create the codeunit that calls Word and creates the letter.

To create the codeunit

  • In Object Designer, choose Codeunit, and then choose the New button to create a new codeunit.
  • On the View menu, choose Properties to open the Properties window of the codeunit.
  • In the TableNo field, choose the AssistEdit button to open the Table List window.
  • In the Table List window, select the Customer table, and then choose OK.

WordAutomation-5

  • Close the Properties window.

To declare the variables

  • Choose the OnRun Trigger and on the View menu, choose C/AL Locals, and then choose the Variables tab.
  • On a blank line, type wdApp in the Name field and set the Data Type field to Automation.

Note

When you create an Automation variable, some hidden events are also created for it. If you want to delete the variable, be aware that the events are also not deleted. This can cause issues if you then create a variable with the same name.

  • In the Subtype field, choose the AssistEdit button. The Automation Object List window is displayed.
  • In the Automation Server field, choose the AssistEdit button.
  • In the Automation Server List, select Microsoft Word 15.0 Object Library if you are running Word 2013, or select Microsoft Word 14.0 Object Library if you are running Word 2010, and then choose OK.
  • From the list of classes in the Automation Object List, select the Application class, and then choose OK.

WordAutomation-6

  • Repeat steps above to add the following two Automation variables:
Name Data type Subtype Class
wdDoc Automation Microsoft Word 14.0/15.0 Object Library Document
wdRange Automation Microsoft Word 14.0/15.0 Object Library Range
  • Add the following variables.
Name Data type Subtype Length
CompanyInfo Record Company Information
TemplateName Text 250
  • Close the C/AL Locals window.

Writing the C/AL Code

Before you start writing the C/AL code that uses Automation, you must do some initial processing. You start by calculating the Sales (LCY) FlowField. Then, you check whether the customer qualifies for a discount. Finally, you retrieve the information from the Company Information and User tables that you use to fill in some of the fields in the letter.

To write the C/AL code

  • In the C/AL Editor, add the following lines of code to the OnRun section.
  CALCFIELDS(“Sales (LCY)”);CompanyInfo.GET;
  • To create an instance of Word before using it, enter the following line of code.
 CREATE(wdApp, FALSE, TRUE);
  • This statement creates the Automation object with the wdApp variable.
    1. The first Boolean parameter in the statement (FALSE) tells the CREATE function to try to reuse an already running instance of the Automation server that is referenced by Automation before creating a new instance. If you change this to TRUE, then the CREATE function always creates a new instance of the Automation server.
    2. The second Boolean parameter in the statement creates the Automation object on the client. This is necessary to use this codeunit on a page in the Microsoft Dynamics NAV Windows client.
  • Enter the following lines of code to add a new document to Word that uses the template that you designed earlier. If required, replace C:\Users\atripathi5283\Desktop\Nav-2015\Word Letter with the correct folder path to the template that you defined in the procedure.
 TemplateName := C:\Users\atripathi5283\Desktop\Nav-2015\Word Letter\Discount.dotx’;wdDoc := wdApp.Documents.Add(TemplateName);wdApp.ActiveDocument.Fields.Update;
  • Because the Add method of the Documents collection requires that you pass the path to the template by reference, you must set up the TemplateName variable to hold this information. You will get a compilation error if you put the path into the call as a literal string.
  • The Documents property returns a Documents collection that represents all open documents. You can also see that the Documents collection object has an Add method, and that the Add method has the following syntax.
  • expression.Add(Template, NewTemplate, Document Type, Visible)
  • expression is a required argument, and it must be an expression that returns a Documents object. All the arguments are optional. You will use Template to open a new document that is based on your template.
  • For the syntax in the C/AL Symbol Menu, note that the Documents property returns an object of type DOCUMENTS, which is a user-defined type. The property returns a Documents class or IDispatch interface. This information helps the compiler perform a better type check during compilation. The following statement can also pass both the compile-time and the run-time type checks.
  • wdDoc := wdApp.Documents.Add(TemplateName);
  • Finally, the Add method returns a Document class. While you did not need to declare a C/AL variable for the interim Documents class, you have declared a variable for the wdDoc return value,.
  • The third line contains a call that must be made to ensure that the template works as intended.
  • wdApp.ActiveDocument.Fields.Update;

Transferring Data to Word

Now you can transfer the actual data from the Customer record to the placeholder fields in the Word document.

You have set up the first three fields in the template so that they can contain the contact, name, and address of the customer and you can transfer the data.

To transfer data to Word

  • Transfer the data by adding the following lines of code.
 wdRange := wdAPP.ActiveDocument.Fields.Item(1).Result; wdRange.Text := Contact; wdRange.Bold := 1; wdRange := wdAPP.ActiveDocument.Fields.Item(2).Result; wdRange.Text := Name; wdRange.Bold := 1; wdRange := wdAPP.ActiveDocument.Fields.Item(3).Result; wdRange.Text := Address; wdRange.Bold := 1;
  • You cannot use the fields directly as variables and make an assignment such as Fields.Item(3) := Address. Instead, you use the Result property of the field. This property returns the result of the field as a range. You place this range in the wdRange Automation variable that you declared.
  • You then set the Text property of the range to the desired values, which is the name of your contact person and the name and address of the customer. Finally, you add bold formatting.
  • The data you are transferring must be in text format. If it is not in text format, then you get a compilation error. wdRange.Text expects arguments to be of type BSTR, which maps to either Text or Code. This means that any data that is not Text or Code must be converted before it is passed to Word. To convert a field to Text, you use the FORMAT function. All the fields that are transferred in this step are in text format, so no conversion is needed and the FORMAT function is not used. However, in this example, you also need to transfer the Sales (LCY) field, which is a Decimal field. To see how to convert the Sales (LCY) field, go to the next step.
  • To transfer and format the data from the Sales (LCY) field, add the following code.
 wdRange := wdAPP.ActiveDocument.Fields.Item(4).Result;wdRange.Text := FORMAT(“Sales (LCY)”);wdRange.Bold := 0;
  • To transfer the information from the Company Information table, add the following code.
 wdRange := wdApp.ActiveDocument.Fields.Item(5).Result;wdRange.Text := CompanyInfo.Name;
  • To complete the processing in Word, add the following code.
 wdApp.Visible := TRUE;wdApp.ActiveDocument.Fields.Unlink;
  • The first statement opens Word and shows you the letter that was created. The second statement makes the fields work as placeholders.

WordAutomation-7

  • Save and compile the codeunit

To-Do List

Although this code will work, you must add a few things to make it complete:

  • We recommend that you do not use a hardcoded template name. You should keep the template name in a table, and the user should select it from a page. You can then have different templates for different types of letters that you want to send to your customers.
  • You should add some error-handling code. For example, the CREATE call fails if the user does not have Word installed or if the installation has been corrupted. You should check the return value of CREATE and give an appropriate message if it fails.
  • The user should get a message if the customer does not qualify for the discount. In the example, the codeunit closes without any message.

Calling the Codeunit from the Customer Card

The final task is to ensure that you can call the codeunit from the Customer Card page in the Microsoft Dynamics NAV Windows client.

To call the codeunit from the Customer card page in the Microsoft Dynamics NAV Windows client

  • Open Object Designer, and then choose Page.
  • Select the Customer Card page and then choose Design.
  • On the View menu, choose Page Actions.
  • To add a new action, locate the action container with the subtype set to ActionItems.
  • Right-click the next line after the ActionItems container, and then choose New.
  • In the Caption field of the new line, type Word Letter.
  • Set the Type field to Action.
  • With the new action selected, on the View menu, choose Properties.
  • In the RunObject field, type codeunit Discount Letter.

Note

If you saved the codeunit that you created in the previous procedure under a different name, then substitute Discount Letter with the name that you used.

  • Use the arrow buttons to make sure that the new action is indented only once from the ActionItems container above it

WordAutomation-8

  • Save and compile the Customer Card page.

To run the Customer Card and view the Word letter

  1. In Object Designer, choose the Page
  2. Select the Customer Card page, and then choose Run.
  3. In the ribbon, on the Actions tab, choose the Word Letter

The letter document opens in Word.

WordAutomation-9

Next Steps

The letter that you have just created only contains five fields and sample body text. Before you can use this letter in an actual situation, you will need to add some more fields, such as the name and address of your own company, the date, and the currency code, and the main text of the letter. It will also need some formatting to make it look more attractive. If you alter the order in which the fields appear in the template, you must change the numbering of the fields in the codeunit to ensure that the correct data is inserted into the appropriate fields.

 

Functional Tips

Preventing Posting of Sales Invoices that Are Not on Stock – in Navision 2015

By default, Microsoft Dynamics NAV 2015 is set up so that you are allowed to post sales invoices that contain items that you currently do not have on stock.

You can change that behavior to allow posting an invoice only if all the items on the lines are on stock. In this scenario, you will learn how to do it through the Inventory Setup page.

  • On the Role Center, o the Home tab, in the Setup group, choose Setup.
  • On the drop-down menu, choose Inventory Setup. The Inventory Setup window opens.

PrevNegSIPosting-1

  • In the Inventory Setup window, select the Prevent Negative Inventory check box.
  • Choose the OK button..