Microsoft Dynamics NAV

Team Blog

  • Microsoft Dynamics NAV Team Blog

    Cumulative Update 20 for Microsoft Dynamics NAV 2013 has been released

    • 1 Comments

    Cumulative Update 20 includes all application and platform hotfixes and regulatory features that have been released for Microsoft Dynamics NAV 2013.

    The cumulative update includes hotfixes that apply to all countries and hotfixes specific to the following local versions: 

    • AU - Australia
    • AT - Austria
    • BE - Belgium
    • CH - Switzerland
    • DE - Germany
    • DK - Denmark
    • ES - Spain
    • FI - Finland
    • FR - France
    • IS - Iceland
    • IT - Italy
    • NA - North America
    • NL - Netherlands
    • NO - Norway
    • NZ - New Zealand
    • SE - Sweden
    • UK - United Kingdom

    Where to find Cumulative Update 20

    You can download the cumulative update from KB 3013213 - Cumulative Update 20 for Microsoft Dynamics NAV 2013 (Build 38454).

    For a full list of all hotfixes included in cumulative updates for Microsoft Dynamics NAV 2013, see the following CustomerSource and PartnerSource pages:

    CustomerSource:

    PartnerSource:

    For a list of all released cumulative updates, see Released Cumulative Updates for Microsoft Dynamics NAV 2013.

  • Microsoft Dynamics NAV Team Blog

    How to get back the 'hotfix directories' from NAV 2015 Cumulative Update 1

    • 8 Comments

    As you might have read from the comments on the Cumulative Update 1 for Microsoft Dynamics NAV 2015 has been released post, we are no longer providing the 'hotfix directories' in the hotfix download but some people have hinted that they have the need for them. We have created a PowerShell script that should give you back the same folder structure as was present before, and we are providing the source of the script, so that you can modify it to meet your naming needs.

    In order to use it:

    1. Copy the code below to a local file, and save the file as Copy-UpdateFilesToBatchDirectory.ps1.
    2. Unzip the DVD zip file from the Cumulative Update to a local folder.
    3. Run the script.
      1. Open the Microsoft Dynamics NAV 2015 Administration Shell as Administrator
      2. Run this command:
        Import-Module DIRECTORY\Copy-UpdateFilesToBatchDirectory.ps1
        where DIRECTORY is the location where you saved the .ps1 file.
      3. Run this command:
        Copy-UpdateFilesToBatchDirectory -DvdDirectory DVDDIRECTORY -BatchDirectory BATCHDIRECTORY
        where DVDDIRECTORY is the location where you unzipped the DVD from the update, and BATCHDIRECTORY is the location where you want to files to be copied to.
         
    4. It should take a couple of minutes to go through the process, but when done, you should get the same structure as you had before, located in the path you specified for -BatchDirectory

    Here is the script:

    function Copy-UpdateFilesToBatchDirectory
    {
        [CmdletBinding()]
        param (
            [parameter(Mandatory=$true)]
            [string] $DvdDirectory,

            [parameter(Mandatory=$true)]
            [string] $BatchDirectory
        )
        PROCESS
        {
            # Copy all the files from the DVD to a _TEMP folder
            Write-Verbose "Copying files from $DvdDirectory to $BatchDirectory\_Temp\..."
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\RTC\Add-ins
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\NST\Add-ins
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\BPA
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\"WEB CLIENT"
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\OUTLOOK
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\ADCS
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\HelpServer
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\UpgradeToolKit
            New-Item -ItemType Directory -Force -Path $BatchDirectory\_Temp\WindowsPowerShellScripts
            Copy-Item $DvdDirectory\"RoleTailoredClient\program files\Microsoft Dynamics NAV\80\RoleTailored Client"\* -destination $BatchDirectory\_Temp\RTC -recurse -Force
            Copy-Item $DvdDirectory\"ServiceTier\program files\Microsoft Dynamics NAV\80\Service"\* -destination $BatchDirectory\_Temp\NST -recurse -Force
            Copy-Item $DvdDirectory\BPA\* -destination $BatchDirectory\_Temp\BPA -recurse -Force
            Copy-Item $DvdDirectory\"WebClient\Microsoft Dynamics NAV\80\Web Client"\* -destination $BatchDirectory\_Temp\"WEB CLIENT" -recurse -Force
            Copy-Item $DvdDirectory\"Outlook\program files\Microsoft Dynamics NAV\80\OutlookAddin"\* -destination $BatchDirectory\_Temp\OUTLOOK -recurse -Force
            Copy-Item $DvdDirectory\"ADCS\program files\Microsoft Dynamics NAV\80\Automated Data Capture System"\* -destination $BatchDirectory\_Temp\ADCS -recurse -Force
            Copy-Item $DvdDirectory\"HelpServer\DynamicsNAV80Help"\* -destination $BatchDirectory\_Temp\HelpServer -recurse -Force
            Copy-Item $DvdDirectory\"UpgradeToolKit"\* -destination $BatchDirectory\_Temp\UpgradeToolKit -recurse -Force
            Copy-Item $DvdDirectory\"WindowsPowerShellScripts"\* -destination $BatchDirectory\_Temp\WindowsPowerShellScripts -recurse -Force
            Write-Verbose "Done copying files RTC files from $DvdDirectory to $BatchDirectory\_Temp."

            # Delete files that are not needed for an installation scenario
            Write-Verbose "Deleting files from $BatchDirectory that are not needed for the batch directory..."

            Get-ChildItem $BatchDirectory\_Temp -include '*.etx' -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.stx' -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.chm' -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.hh'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.config'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.stx'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.etx'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.ico'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.flf'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            Get-ChildItem $BatchDirectory\_Temp -include '*.sln'  -Recurse | Remove-Item -force -ErrorAction SilentlyContinue
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\RTC\ 'ENU')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\RTC\ 'en-US')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\RTC\ 'Images')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\RTC\ 'SLT')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\RTC\ 'ReportLayout')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\BPA\ 'Scripts')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\"WEB CLIENT"\ 'Resources')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\HelpServer\ 'css')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\HelpServer\ 'help')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\HelpServer\ 'images')
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\_Temp\WindowsPowerShellScripts\ 'ApplicationMergeUtilities')
            Write-Verbose "Done deleting files from $BatchDirectory that are not needed for for the batch directory."

            # Copy the result to the requested directory and remove the _Temp folder
            Copy-Item $BatchDirectory\_Temp\* -destination $BatchDirectory\ -recurse -Force
            RemoveUnnecessaryClickOnceDirectory (Join-Path $BatchDirectory\ '_Temp')
        }
    }

    function RemoveUnnecessaryClickOnceDirectory
    {
        param ([string]$directory)
        Remove-Item $directory -force -Recurse -ErrorAction SilentlyContinue
    }

     

    Hope this helps,

    Jorge

  • Microsoft Dynamics NAV Team Blog

    Microsoft Dynamics NAV: Faster than ever.

    • 9 Comments

     

    First, let me start by saying that based on the evidence so far: It is. Significantly.

    A number of the changes to the Dynamics NAV 2013 architecture contribute to the performance boosts that many of the test have shown. To outline some of the changes:

    • Middle tier is 64 bit
    • We are no longer using cursors but MARS
    • Ability to auto-update sift fields when looping, rather than repeating the process for each call. SETAUTOCALCFIELDS reduces the amount of statements issued
    • Pages containing flowfields now issue ‘SmartSQL’ queries, basically one source table query with outer joins for each flowfield query, again reducing the ‘chattiness’
      and calculating sift values in one server roundtrip
    • Global cache
    • REPEATABLEREAD is default isolation level
    • Locking changes in posting routines, locking at later point and reducing overall blocking time

    … and more.

    However(!), a few things have surfaced in the course of time that are not as explicitely documented as the changes above, nor as apparent, and might have unexpected side effects. I have collected some of the side effects that you might or not be aware of and that might leave you panicking if not certain what you’re facing.

     

    • Pages (with FlowFields) will in general run faster on Dynamics NAV 2013 than on NAV 2009 due to SmartSQL queries and reduced chattiness. Flow Fields on a page (all of them) are calculated in one go, which greatly reduces number of statements issued. But SmartSQL queries are not cached. Also, since we changed to MARS, SQL seems to be more sensitive to an index's column cardinality then before. You might experience that (depending on various factors) some queries that have run fine in the past now take much longer, this is due to a poor execution plan on SQL. With Dynamic cursors, query plan optimizer tended to optimize for the ORDER BY, while with MARS, SQL is free to choose.  It does a good job at it too, but in rare occasions might chose poorly. These cases are exceptions and contrary to the popular belief, this is not caused by the SmartSQL queries. These queries will have same poor execution plan and perform poorly even when isolated from the SmartsSQL query.

     

    Consider the following example. This is just an illustration of the problem, constructed on CRONUS extended database:

    A lot of Inventory transactions are posted through the Item Journal, generating a lot of Post cost to the G/L Entry. After this, when browsing an item list and opening an Item card, the page opens very slowly.

    After locating the offending query in the SQL profiler and running it isolated in Microsoft SQL Server Management Studio with ‘Include Actual Execution Plan’ option enabled, the plan looks similar to the one shown below:

     

     

    Each sub-query shows reasonably (small) percentage of cost and no apparent reason for bad execution plan. There are no obvious extreme costs, however there is a Clustered Index Scan here:

     

    Looking at the filter that SQL Server applies, namely it filters on “Post Value Entry to G_L”. “Item_No_” = “Item”.”No_”:


     

     

    Although SQL Server reports Operator Cost as small, it shows CPU Cost in excess of 2.3 in approx. 1.94 executions. So, it is likely scanning the table twice and unfortunately the table has 4,7 million rows.

    Although it is not obvious from the actual SQL Server execution plan that this is a problem, profiling with the SQL Server Profiler reports the query to use more than 5 seconds of CPU, while doing 131.519 reads to fetch 52 rows:

     
     

    The reason the Duration is on par with CPU Seconds is that all reads are logical from SQL Server Buffers. Re-issuing the query after adding the supporting index shows this in SQL Server Profiler:

     


    So Reads were reduced by a factor of 100 and (warm) duration was reduced by a factor of 40.

    As you can see, these poor execution plans are not caused by the SmartSQL. However the fact that the SmartSQL queries don’t cache their results will only amplify the issue. To solve it, we have to tackle the performance of that one isolated query by creating a covering index to improve the execution plan.

    And no, it won’t help to merely customize the page or change the visibility of the field. As long as it is contained in page metadata (so unless removed from page altogether), it will be calculated.

    So in short, if you do run into an issue of rather dramatic slowness of a page containing flowfields in Dynamics NAV 2013 or higher, isolating and testing the Flow Field queries separately (focusing on ones with clustered index scan, regardless of cost) should lead you to the culprit fairly quickly.  A supporting index should resolve the problem.

    • Temp tables: These are now moved to .NET. When you create a Temp record, your private C# TempTableDataProvider object is created. It will store whatever records you insert into a C# Dictionary, with the Primary Key Fields as the key for the Dictionary. The Dictionary is in memory and stores records in the order they
      are inserted.  When you add a SetCurrentKey, an AVLTree is built on the fly at first FindXX() you perform with that (current) key. In terms of performance, this is an expensive operation. This tree is in memory however, so it will be cached and reused later. If you issue a query without calling SetCurrentKey, an AVLTree for the primary key will be used.

    However, maintaining all this can consume quite a lot of memory on your middle tier, so plan for ample memory when scaling. Also, as mentioned above, querying temp tables is cached but sorting them is a fairly expensive operation, just something to keep in mind.

    • The next one is not strictly a performance issue, but can have a fairly drastic performance side-effect if you’re affected by it, so deserves to be mentioned:

    You might (or might not) be aware that the transaction scope and behavior of a page action has changed in Microsoft Dynamics NAV 2013 and higher. This will be especially significant if you are calling functions in codeunits (or objects other than the source table), passing the REC as a parameter and intend to lock the record in that function.

    Consider the following example: You have added an action that invokes a function in a codeunit, that in turn locks/ modifies the record (typically calling custom posting routine)

    So OnAction trigger code is, for example, as follows:

     

      PostingFunction(Rec);

     

    Where PostingFunction is a function (in any object other than the source table).

    Now, the consequence of the previously mentioned transaction scope change and the fact that you’re locking the record in the function, is that the entire source table (Rec) you passed as a parameter in the example above, is locked. In other words, you’re passing the current record as a parameter, but you are locking the whole table. The behavior would cause more damage than good to change at this point due to all functionality it would affect, so it won’t be changed, but fortunately – if
    you’re aware of this issue, the solution is very simple:

    SETSELECTINOFILTER(Rec);  //adding this line

    PostingFunction(Rec);

    Adding the line above should reduce the scope of locking and leave you with locking just the one record (or selection of records if on a list). This applies to card pages as well.

     

    • Last, but not least: you might have noticed increased Async_Network_IO waits. These cause quite a lot of concern out there. However, this is a symptom and not a problem per se.

    When Dynamics NAV issues a query that returns thousands of rows, SQL Server will start a work thread to return the result. If the application does not consume the rows as fast as they are delivered from SQL Server then the SQL Server work thread will have to wait and that shows up as wait type Network_Async_IO. If the application never consumes the entire result set then the worker thread will be hanging until the transaction is ended (when we close the statement), or if it was a read transaction, for a longer period either until the connection is closed (as idle) or if the statement is overwritten by another statement (statement cache is full).

    Example: when we do a FINDSET, a number of records (50, 100...) is retrieved. If it is a larger set it will run until all records are retrieved (or buffer is full), even if only first 10 are actually read by application. Eventually the session goes to sleep and after transaction ends sleeping sessions are removed. So in short, these are merely reflecting NAV data access methods, and are not a problem as such. If you want to reduce these, make sure you’re reading all the rows you’re asking for when using FINDSET, otherwise use FIND(‘-‘) or FIND(‘+’).

     

    With thanks to Jesper Falkebo and Jens Klarskov Jensen

     

    Jasminka Thunes

    Microsoft CSS

     

    These postings are provided "AS IS" with no
    warranties and confer no rights. You assume all risk for your use.

  • Microsoft Dynamics NAV Team Blog

    Please Check your Management Port in Microsoft Dynamics NAV 2013 R2

    • 1 Comments

    As you know, since Microsoft Dynamics NAV 2013 R2, schema changes are now handled in a different way as described, among other places, in the Paradigm blog post. All schema changes are now synchronized to the SQL Server database through the Microsoft Dynamics NAV service tier.

    We sometimes hear of partners receiving the following error when they try to import a .fob file:

    "The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state."

    This can cause huge problems, especially if it is a newly upgraded database, and you need to Import the fobs from the older version, or if you want to import in a live environment some objects that you just developed in your test environment.

    There are several reasons why you can get the ServiceChannel error, one of which was fixed in build 36310 (TFS#358256 Channel errors when trying to default to SPN). So if you are still using an older build number, please be sure you are on a higher build number.

    But still, it happens quite often, that even on higher build numbers, you still get the error. In this case you should do the following:.

    1. Verify that you are selecting the correct Microsoft Dynamics NAV Server instance in the development environment by choosing File, Database, Information, and then verifying the value of Server Instance.
    2. Verify that the firewall is opened for the Server Port (usually 7046) and the Management Port (usually 7045) on the corresponding box where the service is running.

    It sounds too easy, and in most of the cases the people do not believe us! But after a while they come back to say…yes It was really the management port.

    So whenever you want to import any objects into Microsoft Dynamics NAV 2013 R2, if you get any related errors, please check the management port and the firewall settings.

  • Microsoft Dynamics NAV Team Blog

    Cumulative Update 1 for Microsoft Dynamics NAV 2015 has been released

    • 46 Comments

    Cumulative Update 1 includes all application and platform hotfixes and regulatory features that have been released for Microsoft Dynamics NAV 2015. 

     The cumulative update includes hotfixes that apply to all countries and hotfixes specific to the following local versions:

    •   AU - Australia
    •   AT - Austria
    •   BE - Belgium
    •   CH – Switzerland
    •   DE - Germany
    •   DK - Denmark
    •   ES - Spain
    •   FI  - Finland
    •   FR - France
    •   IS - Iceland
    •   IT - Italy
    •   NA - North America
    •   NL - Netherlands
    •   NO - Norway
    •   NZ - New Zealand
    •   RU – Russia
    •   SE - Sweden
    •   UK - United Kingdom

    Where to find Cumulative Update 1

    You can download the cumulative update from KB 3013215  – Cumulative Update 1 for Microsoft Dynamics NAV 2015 (Build 38457). The cumulative update was temporarily unavailable for download, but it is now available again. The new set of download packages contain the DVD image and the Application folder only. The files in the new download packages have the exact same build number as the files in the original download. The new download will give you the same options for patching both new and current installations of Microsoft Dynamics NAV 2015. You can either install the new image or you can unpack the image and copy/paste files from the DVD folder structure.

    Upgrade Toolkit for Upgrading Data from Microsoft Dynamics NAV 2009 R2 or SP1 to Microsoft Dynamics NAV 2015

    The cumulative update includes an upgrade toolkit for upgrading a Microsoft Dynamics NAV 2009 R2 or Microsoft Dynamics NAV 2009 SP1 database to Microsoft Dynamics NAV 2015. The upgrade toolkit includes several application objects in FOB files that simplify the upgrade process for those of you coming from Microsoft Dynamics NAV 2009 R2 or Microsoft Dynamics NAV 2009 SP1. For more information, see the attached whitepaper.

     

    ---- This blog post was updated on 13. November 2014 ---- 

     

  • Microsoft Dynamics NAV Team Blog

    Cumulative Update 13 for Microsoft Dynamics NAV 2013 R2 has been released

    • 5 Comments

    Cumulative Update 13 includes all application and platform hotfixes and regulatory features that have been released for Microsoft Dynamics NAV 2013 R2.

     The cumulative update includes hotfixes that apply to all countries and hotfixes specific to the following local versions:

    •   AU - Australia
    •   AT - Austria
    •   BE - Belgium
    •   CH – Switzerland
    •   CZ – Czech Republic
    •   DE - Germany
    •   DK - Denmark
    •   ES - Spain
    •   FI  - Finland
    •   FR - France
    •   IS - Iceland
    •   IT - Italy
    •   NA - North America
    •   NL - Netherlands
    •   NO - Norway
    •   NZ - New Zealand
    •   RU – Russia
    •   SE - Sweden
    •   UK - United Kingdom

    Where to find Cumulative Update 13

    You can download the cumulative update from KB 3013214  – Cumulative Update 13 for Microsoft Dynamics NAV 2013 R2 (Build 38455). 

    For a full list of all hotfixes included in cumulative updates for Microsoft Dynamics NAV 2013 R2, see the following CustomerSource and PartnerSource pages:

    CustomerSource:

    PartnerSource

    For more information about cumulative updates for Microsoft Dynamics NAV 2013 R2, see Announcement of update rollups for Microsoft Dynamics NAV 2013 R2.

  • Microsoft Dynamics NAV Team Blog

    Analysis by dimensions to check performance in the Manufacturing

    • 1 Comments

    This is a topic where we could benefit of analyzing our performance in the manufacturing área by using dimensions. Here, we had different inquiries where I believe it is good to explain what is our view about. As SCM individual we can benefit of using dimensions to have a different view of the Manufacturing área at an aggregated level:

    • Check variances posted to G/L
    • Analyze scrap and determine corrective actions
    • Analyze capacity or operation times posted against expected

    From a dummy level perspective, a dimension is the "label" we add to our entries so we could later analyze this at an aggregated level instead. The way we are using dimensions when we are posting is what we are trying to clarify here.

    First, let me clarify the acronyms I am using here:

    • PO – Production Order
    • POL – Production Order Line
    • POC – Production Order Component
    • POD – Production Order Dimension
    • POLD – Production Order Line Dimension
    • POCD – Production Order Component Dimension
    • ID – Item Dimension

    Now, let me clarify the different scenarios we might be facing here when analyzing manufacturing with dimensions:

    1. PO has dimensions and Refresh
      1. POL: POLD should have POD + ID. If POD and ID contain the same Dimension Code then value from POD is used.
      2. POC: POCD should have POLD + ID. If POLD and ID contain the same Dimension Code then value from POLD is used
    2. PO doesn’t have any dimension and Refresh
      1. POL: POLD should have ID.
      2. POC: POCD should have POLD + ID. If POLD and ID contain the same Dimension Code then value from POLD is used.
    3. User changes POD (value only) and gets confirmation dialog for each updated dimension, if the line(s) should be updated (POLD)
      1. POL: POLD should have POD + ID. If POD and ID contain the same Dimension Code then value from POD is used.
      2. POC: POCD should have POLD + ID. If POLD and ID contain the same Dimension Code then value from POLD is used.
    4. User changes POLD (value only) and gets confirmation dialog for each updated dimension, if the components should be updated (POCD)
      1. POC: POCD should have POLD + ID. If POLD and ID contain the same Dimension Code then value from POLD is used.
    5. User deletes POD and gets confirmation dialog for each deleted dimension, if the line(s) should be updated (POLD)
      1. POL: POLD should keep all dimensions except deleted one
      2. POC: POCD should keep all dimensions except deleted one
    6. User deletes POLD and gets confirmation dialog for each deleted dimension, if the components should be updated (POCD)
      1. POC: POCD should keep all dimensions except deleted one

     Now, what about if I have a different customer process when analyzing the performance in my Manufacturing area? You still can use Default Dimension Priorities to define your own priorities here. That is under Financial Management module.

  • Microsoft Dynamics NAV Team Blog

    Zetadocs Express support for Microsoft Dynamics NAV 2015 is here!

    • 17 Comments

    Equisys announced today, that Zetadocs Express now supports Microsoft Dynamics NAV 2015 and the new Microsoft Dynamics NAV Tablet Client.

    Take a tablet

    Microsoft Dynamics NAV 2015 adds a new touch optimised Tablet client, introduced to improve control of the user experience on various sized tablets (7” is the minimum size really), and is the preferred client for tablets compared to the Web client in a browser.

    The Tablet client is also available as an app on Apple iTunes, Google Play and the Windows Store. Functionality between tablets is largely the same, except iPads do not allow direct access to the file system. However, with Zetadocs Express on the iPad, you can still easily capture photos with the camera or the camera roll. Other tablet operating systems allow access to the tablet file system in order to choose files and other documents on the go.

    Once captured they are then stored permanently in the electronic document archive and shown in context in the Document FactBox.

     

    Works with the Microsoft Dynamics NAV you have

     

    The Tablet client now increases the number of Microsoft Dynamics NAV clients to three; with a Web client and the traditional Windows client (RTC), and Zetadocs Express has them all covered.

     

    In fact, Zetadocs Express offers broad platform support, from the very latest version of Microsoft Dynamics NAV 2015, all the way back to Microsoft Dynamics NAV 2009 SP1 and everything in between.

     

    Proven quality with CfMD

     

    Version 7 of Zetadocs for Microsoft Dynamics NAV was one of the first software solutions worldwide to be awarded Certified for Microsoft Dynamics (CfMD) for Microsoft Dynamics NAV 2015. The Certified for Microsoft Dynamics (CfMD) logo is version specific, giving Microsoft Dynamics customers the confidence that the add-on solution they have chosen has met the comprehensive testing guidelines updated with each version of Microsoft Dynamics NAV.

     

    Download Zetadocs Express now!

     

    Zetadocs Express is a no-cost downloadable document management module for Microsoft Dynamics NAV, download it now and try out mobile document management with the Microsoft Dynamics NAV 2015 tablet client today!

     

  • Microsoft Dynamics NAV Team Blog

    Report Execution Insights

    • 5 Comments

    With the release of Microsoft Dynamics NAV 2015, the way reports are executed has changed. In Microsoft Dynamics NAV 2015, reports can use a built-in RDLC layout (as before), a built-in Word layout, or a custom layout, which can be based on RDLC or Word. Built-in layouts are part of the report object, while custom layouts are stored in table 9650 Custom Report Layout of the database. The new behavior relies on a few new functions in codeunit 1. Additionally, Microsoft Dynamics NAV 2015 introduces the capability to schedule a report for execution later. This functionality also relies on codeunit 1 triggers, as well as a few new C/AL functions.

    Report Execution

    This section explains what happens behind the scenes when a report is executed. A report is executed when any of the following happen:

    • From the client, a user chooses Preview, Print, or Microsoft Excel, Microsoft Word, or PDF on the report request page.
    • C/AL code executes the following functions:
      • RUN or RUNMODAL without a request page.
      • SAVEAS, SAVEASEXCEL, SAVEASPDF, SAVEASWORD, or SAVEASXML.

    Report Execution Flow

    The following figure illustrates the sequence of interactions between the platform and codeunit 1 functions when a report is executed.

    1. The report execution calls the HASCUSTOMLAYOUT function in codeunit 1 to determine whether the particular report is currently set up to use a custom RDLC or custom Word layout.

      If the report does not use a custom layout (that is, the function result is 0), then the report will use the default built-in layout, which can be either RDLC or Word as specified by the DefaultLayout property of the report object.

      Note: This is function is called before the request page is shown to the user because some of the Print button options on the request page depend on whether the report uses and RDLC layout or Word layout.

    2. If the report is set up to use a custom Word layout or a built-in Word layout, then the MERGEDOCUMENT function is called to handle the report execution.
    3. If the report is set up to use a custom RDLC layout, then the REPORTGETCUSTOMRDLC function is called to handle the report execution. The function returns the custom RDLC in a text string as XML. 

    Word Report Layout Execution

    The execution of reports that use Word layouts consists of two parts: design time and run time.

    • Design time

    To enable the user to map report dataset fields to the Word document that defines the layout, the system must generate an XML document (schema) that can be imported into Word. This XML document is generated by the REPORT.WORDXMLPART function. You must use Word 2013 (or later) for XML mapping. However, you can use Word 2010 for basic editing of the layout, such as changing font type or size.

    • Run time

    When report is executed, the report data output is merged with the Word layout to produce the final report. The report data output is in XML format which has the same form as the output of the REPORT.SAVEASXML function. The merge operation uses the .NET Framework assembly Microsoft.Dynamics.Nav.DocumentReport. The merge operation happens on the Microsoft Dynamics NAV Server and it uses additional.NET Framework components, such as Open XML SDK 2.5. Word is not required on the computer that is running Microsoft Dynamics NAV Server. If the user has requested to view the report as a PDF document, then the Word document is converted from a .docx file type to a .pdf file type by the .NET Framework assembly Microsoft.Dynamics.Nav.PdfWriter.WordToPdf.

    The following figure illustrates the different components that are involved in the Word layout authoring and merging:

     

    As mentioned in the previous section, the Word layout documents are handled by the following function in codeunit 1:

    MergeWordLayout(

      ReportID:Integer;

      ReportAction:SaveAsPdf,SaveAsWord,SaveAsExcel,Preview,Print';

      InStrXmlData:InStream;

      FileName:Text);

    As you can see, the function has to handle all report actions, including printing. Although SaveAsExcel is included in the code, a function call with this parameter will result in an error message that states that this function is not available.

    Note: FileName is used for SaveAsPdf and SaveAsWord. However, it is also used for server-side printing, in which case, it specifies the name of the server-side printer. Client-side printing is done through Word.

    Report Scheduling

    In Microsoft Dynamics NAV 2015, a report can be scheduled for executing later from the Job Queue. This functionality relies on a new codeunit 1 function and a set of new C/AL functions that support the delayed report execution. When a report is run from the client, it can be run by calling either the RUN or RUNMODAL function. The RUNMODAL function is used when the system expects the report to be executed in the current context, in other words, when the results are needed immediately. This is the case, for example, with the Copy Document action that is invoked from a new sales order. Reports that are executed by the RUNMODAL function cannot be scheduled. The user can only schedule reports that are executed by the RUN function.

    It is important to note that most document reports are run by using the Report Selection feature, which uses the RUNMODAL command to execute reports in sequence. Therefore, when printing, for example, a Sales Invoice, the user will not see a Schedule option on the report request page. However, if the Sales Invoice report is run directly from Object Designer in the development environment, the request page will include the Schedule option, as illustrated in the following figure.

     

    When the user chooses Schedule on the request page, the report is not executed immediately. Instead, the codeunit 1 function ReportScheduler@79(ReportId:Integer;RequestPageXml:Text):Boolean is called, where the ReportId parameter specifies the report’s ID and the RequestPageXml parameter specifies the request page parameters as an XML string. This function creates a new record in table 472 Job Queue Entry where it stores the RequestPageXml parameter value (the Job Queue Category Code field is left blank). Before the function inserts the new record in the Job Queue Entry table, page 682 Schedule a Report opens in the client and enables the user to choose the report output type and when to run the report. The following figure illustrates an example of the Schedule a Report page for the report 111 Customer Top 10.

    Report Inbox

    After the Job Queue processes an entry for a report, if the output type is Word, Excel, or PDF, the Job Queue will create an entry for the report in table 477 Report Inbox table. In the client, the entry will appear in the user’s Role Center in the Report Inbox part. Because there is only one Report Inbox table, which is shared by all users, the Report Inbox part is filtered on the user’s ID.

    C/AL Functions Used by Job Queue for Reports

    When the Job Queue processes the report request, it uses on the following new C/AL functions:

    • REPORT.SAVEAS(ReportID,RequestPageXml,ReportFormat::Pdf,OutStr [,RecRef]);
      • This function is a more general version of the SAVEASPDF function, for example. The RequestPageXml parameter specifies a string of request page parameters as XML. The ReportFormat parameter specifies the output file type as PDF, Excel, Word, or XML.
      • It stores the report to an outstream, so there is no need for an intermediate file on the server.
      • It accepts an optional parameter of type RecordRef, in case you want to run the report on a specific record, such as a sales invoice header.
    • REPORT.EXECUTE(ReportID,RequestPageXml [,RecRef]);
      • This function is used to execute processing-only reports (batch jobs), which do not have an output.
    • REPORT.PRINT(ReportID,RequestPageXml,PrinterName [,RecRef]);
      • This function prints the report to a specified printer.
      • Printing reports from the Job Queue occurs on the computer that is running Microsoft Dynamics NAV Server. Any printers that you want to use for printing reports must be set up server computer for login account that is used by the Microsoft Dynamics NAV Server instance.
      • To schedule a report to print, on the Schedule a Report page, the user sets the Report Output Type field to Print, and then selects the Printer Name field to choose the printer from a list of server printers. The list includes the printers that are set up for the login account on the Microsoft Dynamics NAV Server computer. If the default printer on the user’s computer matches a printer on the server computer, then that printer is automatically selected in the list. If the Printer Name field is left blank, then the default printer on the server computer is used.

    Important: We do not recommend that you set up print-to-file drivers (such as Microsoft XPS Document Writer or PDF printer) on the server computer because using them to print reports can block the Job Queue. Microsoft Dynamics NAV cannot distinguish between print-to-file drivers and physical printers. If the user selects a print-to-file driver, the driver will open a file dialog box on the server computer, which will stop the printer job on the server and subsequently block the Job Queue. Eventually (perhaps after several hours), the Job Queue will time out and continue.

    • RequestPageXml:= REPORT.RUNREQUESTPAGE(ReportID [,RequestPageXml]).
      • This function opens the report request page that includes the OK and Cancel buttons, but does not run the report. It returns an XML string that contains the request page parameters that are entered on the request page. If you want to edit previously stored request page data, you can supply the old data as an optional parameter. 
  • Microsoft Dynamics NAV Team Blog

    ClickOnce template in Dynamics NAV 2015 still contain references to SQL Server 2012

    • 2 Comments

    When you deploy ClickOnce for Dynamics NAV 2015, there is an inconsistency related to SQL Server 2014 support tools. The product DVD does have SQL Server installation files in the Prerequisite Components folder:
    - \Microsoft Report Viewer 2014\ReportViewer.msi
    - \Microsoft Report Viewer 2014\SQLSysClrTypes.msi

    The ClickOnce template to be found in the folder \ClickOnceInstallerTools\Program Files\Microsoft Dynamics NAV\80\ClickOnce Installer Tools\TemplateFiles\NAVClientInstallation.html still refers to SQL Server 2012.

    The Microsoft Report Viewer 2014 and the CLR Types for Microsoft SQL Server 2014 will not be officially released until Visual Studio 2014 ships. Until that happens the partners have these two options for resolving this issue:

    1. Either the partner can take the .msi files from the NAV 2015 installation media and place these on a files hare and update the ClickOnce landing page accordingly
    2. Or the partner can modify the configuration file for the RTC client to load the 2012 version of the assemblies. This is done by adding the following section to the file: Microsoft.Dynamics.Nav.Client.exe.config, which is included in the ClickOnce application package. The section is:

    <dependentAssembly>
      <assemblyIdentity name="Microsoft.ReportViewer.WinForms" publicKeyToken="89845dcd8080cc91" culture="neutral"/>
      <bindingRedirect oldVersion="12.0.0.0" newVersion="11.0.0.0"/>
    </dependentAssembly>

    For an example of how to add the dependentAssembly configuration element, please refer to this page on msdn: http://msdn.microsoft.com/en-us/library/0ash1ksb(v=vs.110).aspx

    For the time being, this is sufficient to deploy ClickOnce for Dynamics NAV 2015.

    Kindest regards,

    Marco Mels
    Support Escalation Engineer, CSS
    Microsoft

    These postings are provided "AS IS" with no warranties and confer no rights. You assume all risk for your use. The Netherlands

  • Microsoft Dynamics NAV Team Blog

    Adding an image to a Role Center page to fill the content area on tablets

    • 0 Comments

    With the introduction of the new Microsoft Dynamics NAV Tablet client, developers are looking for ways to create simple Role Centers that are ideal for use on small-screen mobile devices. If your Role Center has a few cues but no content, adding a company logo is one simple way to make it look great and personal! This blog post explains how that can be done in a few simple steps.

    Note that this feature is implemented only for the Role Center pages in the Microsoft Dynamics NAV Tablet client.

    Step 1: Set up the Role Center page that is used by the Microsoft Dynamics NAV Tablet client

    As an example I will modify the existing Order Processor Role Center page and remove all content parts. The modified page will now look as illustrated below.

    Note that the content page must contain either image or content parts. Cues are considered navigation elements which is why the SO Processor Activities part or any other part containing cues can only be added to the Role Center page in this particular scenario.

    When the page is opened in the Microsoft Dynamics NAV Tablet client, it should look as illustrated below.

    The page presented above does not look ideal, does it? So how do we make it more appealing? The answer is simple; by adding a company logo and make it shine.

    Step 2: Add an image to the content area of the Role Center page

    The developer needs a table, or more specifically a table field of type BLOB, to store an image. In this post, the Company Information table (79) is used because it has a Picture field that stores a company logo. In a real-life scenario, a dedicated table is a better solution. Because the Role Center page can contain only groups and parts, the second object that the developer needs is the card part page that will contain an image. The snippet below represents a sample page. Notice that the image has the ShowCaption property set to No. It indicates to the tablet client that such an image should fill the entire screen. Such behaviour is only implemented for Role Center pages in the tablet client.

    OBJECT Page [Desired Id] Company Logo

    {

      OBJECT-PROPERTIES

      {

        […]

      }

      PROPERTIES

      {

        SourceTable=Table79;

        PageType=CardPart;

      }

      CONTROLS

      {

        { 1   ;0   ;Container ;

                    ContainerType=ContentArea }

     

        { 2   ;1   ;Field     ;

                    SourceExpr=Picture;

                    ShowCaption=No }

      }

      CODE

      {

        […]

      }

    }

    The last step is to modify the selected Role Center page and add the part that hosts the page created earlier. The part must be added to the RoleCenterArea, as illustration below.

    Step 3: Upload the desired image to be used as logo

    In case the Company Information table is used to store the image, the simplest way to upload an image is to open the Company Information page (1) in edit mode and then select an image to be displayed on the Role Center page.

    Now when the Role Center page is opened, it will look like the page presented in the following picture. It is simple and looks great.

    Notes

    The image width and height is set to be 100% in CSS and that impacts how the image will look on a page. There are a few important things to be aware of:

    1. The image will scale to the available width of the content area and scale accordingly to its original ratio. That behaviour requires using an image that will look great on supported screen sizes and will not need to have vertical scrollbars.
    2. Because the image will grow or shrink, it is essential to upload an image of the desired resolution so that a user will not experience a decreased image quality caused by scaling. It is important to balance quality versus loading time.
    3. The image presented in the illustration above has size of 1800 x 1200 and fits Surface RT and iPad screens perfectly (the image is scaled down).
  • Microsoft Dynamics NAV Team Blog

    How to get Microsoft Dynamics NAV for tablets to connect using a self-signed certificate

    • 11 Comments

    Overview

    This blog post helps you connect Microsoft Dynamics NAV for tablets using a self-signed certificate. The targets for the blog post are the following apps:

    • Dynamics NAV for iPad
    • Dynamics NAV for Android
    • Dynamics NAV for modern Windows

    The Internet Information Services Manager (IIS) needs a trusted certificate that holds the private key for https. iOS and Android need the https certificate to be trusted by a root certificate.

    In this blog post, you will be creating one certificate that is used for both the IIS to enable https and to install on your device. Follow the steps below and replace the following string: <your site name> with the name of the site. You can either use a real name like www.abc.com, or use your pc name. It must match the first part of the URL that you have specified. Currently the PowerShell script New-SelfSignedCertificateEx supports Windows 8 and Windows Server 2012 and newer.

    Steps

    For the Microsoft Dynamics NAV Web server, do the following:

    1. Download and save the PowerShell script from https://gallery.technet.microsoft.com/scriptcenter/Self-signed-certificate-5920a7c6#content.
    2. Create the certificate:
      1. Open a PowerShell prompt with the option As administrator.
      2. Go to the directory where you saved the New-SelfSignedCertificateEx.ps1 file.
      3. Run the following command: Import-Module .\New-SelfSignedCertificateEx.ps1.
      4. Then run the following command: New-SelfSignedCertificateEx –Subject “CN=<your site name>” –IsCA $true –Exportable –StoreLocation LocalMachine –StoreName My.
      5. Manage the certificate:
        1. Open the mmc.exe.
        2. Go to the File menu, and then choose Add/Remove Snap-in...
        3. Select Certificates.
        4. Choose Add.
        5. Select the computer account.
        6. Choose Finish and then OK.
        7. Locate and copy the certificate you just created in the personal/certificates folder.
        8. Paste the certificate into the Trusted Root Certification Authorities/Certificates folder.
        9. Select the certificate, right-click and export the certificate.
        10. Select the No, do not export the private key option.
        11. Choose Next.
        12. Select DER encoded binary x.509 (.cer).
        13. Specify a location and filename and finish the wizard.
        14. Enable https: In IIS Manager, create a binding for https using the certificate you added.

    Next

    For iOS, do the following:

    1. Use the iPhone Configuration Utility tool from Apple http://support.apple.com/downloads/#iphone or mail the certificate you exported.
    2. Run the certificate file and install the certificate.
    3. You are now ready to start the Dynamics NAV app.

    For Windows, do the following:

    1. If you run the client on the same box as the web server, then you are all set to go.
    2. Copy the certificate you exported to the tablet, install the certificate and place the certificate in the Trusted root certification authorities folder of the local machine.

    For Android, do the following:

    1. Copy or mail the certificate that you exported.
    2. Run the certificate file and install the certificate.
    3. You are now ready to start the Dynamics NAV app.

    This should help you get up and running using self-signed certificates. Be aware that Microsoft Dynamics NAV for tablets does not support Always Ask certificates.

  • Microsoft Dynamics NAV Team Blog

    Extensibility for the Microsoft Dynamics NAV Tablet Client

    • 8 Comments

    Get in touch

    With Microsoft Dynamics NAV 2015, you will be able to run your Microsoft Dynamics NAV application on tablets. The touch interface on these devices opens for a few new cool scenarios. One of the obvious usage of touch is to allow users to write directly on the tablet, for example to sign documents.

    In this blog post, I will walk you through how to develop a client control add-in with JavaScript that you will be able to add to any Microsoft Dynamics NAV page. This add-in shows a box in which the user can write with a tablet pen or just with his finger. It also demonstrates how to save the image into a Microsoft Dynamics NAV table as a BLOB.

    If you are not familiar with JavaScript client add-ins or if you just need a refresher, take a look at this walkthrough for your classic ‘Hello World’ example.

    I am referring to this add-in as the ‘Signature Add-in’ and to the graphical data as ‘the signature’, but it could really be any type of hand-drawn graphics.

    So, let’s get started.

    Creating the C# class library

    In Visual Studio, create a new C# class library project and add a reference to the Microsoft.Dynamics.Framework.UI.Extensibility.dll assembly. You will find this assembly in a directory similar to C:\Program Files (x86)\Microsoft Dynamics NAV\80\RoleTailored Client.

    If you are already familiar with Microsoft Dynamics NAV HTML/JavaScript add-ins, you know that the purpose of this class library is merely to specify the interface and make the C/AL compiler happy. It does not contain any actual executing code.

    On the server side, besides the usual AddInReady event, we will need two more events; one to write the signature data: the SaveSignature and one to read the signature from the Microsoft Dynamics NAV table to trigger an update on the page; the UpdateSignature.

    On the client side, that is in the JavaScript code, we also need a method to actually draw the graphics and we also want to be able to clear the content.

    To specify this API, create a single public interface looking like this:

     

    namespace SignatureAddIn

    {

        using Microsoft.Dynamics.Framework.UI.Extensibility;

     

        /// <summary>

        /// Interface definition for the signature add-in.

        /// </summary>

        [ControlAddInExport("SignatureControl")]

        public interface ISignatureAddIn

        {

            [ApplicationVisible]

            event ApplicationEventHandler AddInReady;

     

            [ApplicationVisible]

            event ApplicationEventHandler UpdateSignature;

           

            [ApplicationVisible]

            event SaveSignatureEventHandler SaveSignature;

     

            [ApplicationVisible]

            void ClearSignature();

     

            [ApplicationVisible]

            void PutSignature(string signatureData);

        }

     

        public delegate void SaveSignatureEventHandler(string signatureData);

    }

    Notice that the SaveSignatureEventHandler delegate takes a string parameter, which will contain the actual serialized data representing the image.

    Build your assembly to make sure you did not forget a semi-colon somewhere.

    Next, you will need to sign your assembly, obtain its public key token and copy it to the client add-ins folder. To do that, follow the steps as described in the walkthrough.

     

    Creating the manifest file

    In the manifest of an add-in, which is just regular XML file, we specify the resources that the control will use. The client side code consists of one single JavaScript file signature.js and use a single CSS file to style the HTML. We will also add a call to an initialization method in our script. The manifest is a good place to do that as the framework ensures that it gets called only when the browser is ready.

    That makes our manifest look like this:

    <?xml version="1.0" encoding="utf-8" ?>

    <Manifest>

      <Resources>

        <Script>signature.js</Script>

        <StyleSheet>signature.css</StyleSheet>

      </Resources>

      <ScriptUrls>

      </ScriptUrls>

      <Script>

          <![CDATA[

              init();

          ]]>

      </Script>

     

      <RequestedHeight>200</RequestedHeight>

      <RequestedWidth>700</RequestedWidth>

      <VerticalStretch>false</VerticalStretch>

      <HorizontalStretch>false</HorizontalStretch>

    </Manifest>

     

    Creating the CSS file

    No big deal here, just create a file named signature.css (the name needs to match the one in the manifest) with the following content:

     

    .signatureArea {

        width: 300px;

    }

     

    .signatureCanvas {

        border: solid;

        border-width: 1px;

        border-color: #777777;  

        background-color: #fff;

        width: 100%;

    }

     

    .signatureButton {

      width: 100px;

      height: 40px;

      color: white;

      background-color: #666666;

      font-size: 12pt;

      outline: 0;

      border-color: white;

    }

    Feel free to play with the styles, this will only affect your add-in and will not affect the Microsoft Dynamics NAV pages whatsoever.

    The interesting part

    All of what has been described so far is boilerplate stuff, which you will have to do for any Microsoft Dynamics NAV HTML client add-in. We are now getting to the interesting piece, which is the JavaScript code.

    Create a file named signature.js. Again here, the name has to match the one you declared in the manifest.

    Let’s start with the implementation of the interface contract that we previously defined in the C# class library:

    var signature;

     

    function init() {

     

        signature = new ns.SignatureControl();

        signature.init();

        RaiseAddInReady();

    }

     

     

    // Event will be fired when the control add-in is ready for communication through its API.

    function RaiseAddInReady() {

        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('AddInReady');

    }

     

    // Event raised when the update signature has been called.

    function RaiseUpdateSignature() {

        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('UpdateSignature');

    }

     

    // Event raised when the save signature has been called.

    function RaiseSaveSignature(signatureData) {

        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('SaveSignature', [signatureData]);

    }

     

     

    function PutSignature(signatureData) {

        signature.updateSignature(signatureData);

    }

     

    function ClearSignature() {

        signature.clearSignature();

    }

     

    As you can see the SignatureControl object in the ns namespace is doing all the work, so let’s take a closer look at it.

    (function (ns) {

     

        ns.SignatureControl = function () {

            var canvas,

                ctx;

     

            function init() {

                createControlElements();

                wireButtonEvents();

                wireTouchEvents();

                ctx = canvas.getContext("2d");

            }

     

         …

    Here we declare the SignatureControl class in the ns namespace and the init()method. The createControlElements() creates the various HTML elements that the control is made of.

           function createControlElements() {

                var signatureArea = document.createElement("div"),

                    canvasDiv = document.createElement("div"),

                    buttonsContainer = document.createElement("div"),

                    buttonClear = document.createElement("button"),

                    buttonAccept = document.createElement("button"),

                    buttonDraw = document.createElement("button");

     

                canvas = document.createElement("canvas"),

                canvas.id = "signatureCanvas";

                canvas.clientWidth = "100%";

                canvas.clientHeight = "100%";

                canvas.className = "signatureCanvas";

     

                buttonClear.id = "btnClear";

                buttonClear.textContent = "Clear";

                buttonClear.className = "signatureButton";

     

                buttonAccept.id = "btnAccept";

                buttonAccept.textContent = "Accept";

                buttonAccept.className = "signatureButton";

     

                buttonDraw.id = "btnDraw";

                buttonDraw.textContent = "Draw";

                buttonDraw.className = "signatureButton";

     

                canvasDiv.appendChild(canvas);

                buttonsContainer.appendChild(buttonDraw);

                buttonsContainer.appendChild(buttonAccept);

                buttonsContainer.appendChild(buttonClear);

     

                signatureArea.className = "signatureArea";

                signatureArea.appendChild(canvasDiv);

                signatureArea.appendChild(buttonsContainer);

     

                document.getElementById("controlAddIn").appendChild(signatureArea);

            }

    Besides plain old divs and buttons, the canvas is where we will actually be able to draw. Canvas has been supported in most browsers for a while and you can read more about it here.

    The control has three buttons. One to accept the signature, which will save it to the database, one to clear the field and one to redraw the signature from the database, mostly for test purposes, as you would probably not need it in most real-life scenarios. Let’s wire these buttons so do something useful:

    function wireButtonEvents() {

        var btnClear = document.getElementById("btnClear"),

            btnAccept = document.getElementById("btnAccept"),

            btnDraw = document.getElementById("btnDraw");

     

        btnClear.addEventListener("click", function () {

            ctx.clearRect(0, 0, canvas.width, canvas.height);

        }, false);

     

        btnAccept.addEventListener("click", function () {

            var signatureImage = getSignatureImage();

            ctx.clearRect(0, 0, canvas.width, canvas.height);

            RaiseSaveSignature(signatureImage);

        }, false);

     

        btnDraw.addEventListener("click", function () {

            RaiseUpdateSignature();

        }, false);

    }

    Notice that we use the drawing context ctx, that we obtained during initialization to clear the content of the canvas. We will see what the getSignatureImage() exactly does to obtain the data in a sec but before that let’s wire the touch events.

    The touch events

    In order to be able draw, we want to react to touch events. In this example, we also hook up mouse events, which is convenient if you want to test your add-in on a non-touch device with an old-fashioned mouse.

    function wireTouchEvents() {

        canvas.addEventListener("mousedown", pointerDown, false);

        canvas.addEventListener("touchstart", pointerDown, false);

        canvas.addEventListener("mouseup", pointerUp, false);

        canvas.addEventListener("touchend", pointerUp, false);

    }

    As you can see, touchstart is the equivalent of a mousedown, while a touchend is the counterpart of a mouseup.

    Once we have detected a touchstart, the trick is to start listening to touchmove and draw in the canvas to the current position of the ‘touching’. Once we get a touchend, we will then stop the listening and the drawing:

    function pointerDown(evt) {

        ctx.beginPath();

        ctx.moveTo(evt.offsetX, evt.offsetY);

        canvas.addEventListener("mousemove", paint, false);

        canvas.addEventListener("touchmove", paint, false);

    }

     

    function pointerUp(evt) {

        canvas.removeEventListener("mousemove", paint);

        canvas.removeEventListener("touchmove", paint);

        paint(evt);

    }

     

    function paint(evt) {

        ctx.lineTo(evt.offsetX, evt.offsetY);

        ctx.stroke();

    }

    Canvas image data

    We want to be able to serialize and de-serialize the image data from the canvas, so we can send it back and forth to the server in a string. The HTML canvas has built-in functionalities to do that through the context:

    function updateSignature(signatureData) {

        var img = new Image();

        img.src = signatureData;

        ctx.clearRect(0, 0, canvas.width, canvas.height);

        ctx.drawImage(img, 0, 0);

    }

     

    function getSignatureImage() {

        return canvas.toDataURL();

    }

     

    function clearSignature() {

        ctx.clearRect(0, 0, canvas.width, canvas.height);

    }

     

    return {

        init: init,

        updateSignature : updateSignature,

        getSignatureImage: getSignatureImage,

        clearSignature: clearSignature

    };

     

    The toDataURL() method converts the image into a (rather long) URL encoded string containing all the pixels. To convert it back, we only need to create an image and set its src property to this URL encoded string and pass this image to the method drawImage on the canvas context. This is pretty convenient as it allows us to use a simple string rather than more complex data structure such as arrays.

    We are now done with the JavaScript part and the entire file looks like this:

    var signature;

     

    function init() {

        signature = new ns.SignatureControl();

        signature.init();

        RaiseAddInReady();

    }

     

    // Event will be fired when the control add-in is ready for communication through its API.

    function RaiseAddInReady() {

        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('AddInReady');

    }

     

    // Event raised when the update signature has been called.

    function RaiseUpdateSignature() {

        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('UpdateSignature');

    }

     

    // Event raised when the save signature has been called.

    function RaiseSaveSignature(signatureData) {

        Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('SaveSignature', [signatureData]);

    }

     

     

    function PutSignature(signatureData) {

        signature.updateSignature(signatureData);

    }

     

    function ClearSignature() {

        signature.clearSignature();

    }

     

    (function (ns) {

     

        ns.SignatureControl = function () {

            var canvas,

                ctx;

     

            function init() {

                createControlElements();

                wireButtonEvents();

                wireTouchEvents();

                ctx = canvas.getContext("2d");

            }

     

            function createControlElements() {

                var signatureArea = document.createElement("div"),

                    canvasDiv = document.createElement("div"),

                    buttonsContainer = document.createElement("div"),

                    buttonClear = document.createElement("button"),

                    buttonAccept = document.createElement("button"),

                    buttonDraw = document.createElement("button");

     

                canvas = document.createElement("canvas"),

                canvas.id = "signatureCanvas";

                canvas.clientWidth = "100%";

                canvas.clientHeight = "100%";

                canvas.className = "signatureCanvas";

     

                buttonClear.id = "btnClear";

                buttonClear.textContent = "Clear";

                buttonClear.className = "signatureButton";

     

                buttonAccept.id = "btnAccept";

                buttonAccept.textContent = "Accept";

                buttonAccept.className = "signatureButton";

     

                buttonDraw.id = "btnDraw";

                buttonDraw.textContent = "Draw";

                buttonDraw.className = "signatureButton";

     

                canvasDiv.appendChild(canvas);

                buttonsContainer.appendChild(buttonDraw);

                buttonsContainer.appendChild(buttonAccept);

                buttonsContainer.appendChild(buttonClear);

     

                signatureArea.className = "signatureArea";

                signatureArea.appendChild(canvasDiv);

                signatureArea.appendChild(buttonsContainer);

     

                document.getElementById("controlAddIn").appendChild(signatureArea);

            }

     

            function wireTouchEvents() {

                canvas.addEventListener("mousedown", pointerDown, false);

                canvas.addEventListener("touchstart", pointerDown, false);

                canvas.addEventListener("mouseup", pointerUp, false);

                canvas.addEventListener("touchend", pointerUp, false);

            }

     

     

            function pointerDown(evt) {

                ctx.beginPath();

                ctx.moveTo(evt.offsetX, evt.offsetY);

                canvas.addEventListener("mousemove", paint, false);

                canvas.addEventListener("touchmove", paint, false);

            }

     

            function pointerUp(evt) {

                canvas.removeEventListener("mousemove", paint);

                canvas.removeEventListener("touchmove", paint);

                paint(evt);

            }

     

            function paint(evt) {

                ctx.lineTo(evt.offsetX, evt.offsetY);

                ctx.stroke();

            }

     

            function wireButtonEvents() {

                var btnClear = document.getElementById("btnClear"),

                    btnAccept = document.getElementById("btnAccept"),

                    btnDraw = document.getElementById("btnDraw");

     

                btnClear.addEventListener("click", function () {

                    ctx.clearRect(0, 0, canvas.width, canvas.height);

                }, false);

     

                btnAccept.addEventListener("click", function () {

                    var signatureImage = getSignatureImage();

                    ctx.clearRect(0, 0, canvas.width, canvas.height);

                    RaiseSaveSignature(signatureImage);

                }, false);

     

                btnDraw.addEventListener("click", function () {

                    RaiseUpdateSignature();

                }, false);

            }

     

            function updateSignature(signatureData) {

                var img = new Image();

                img.src = signatureData;

                ctx.clearRect(0, 0, canvas.width, canvas.height);

                ctx.drawImage(img, 0, 0);

            }

     

            function getSignatureImage() {

                return canvas.toDataURL();

            }

     

            function clearSignature() {

                ctx.clearRect(0, 0, canvas.width, canvas.height);

            }

     

            return {

                init: init,

                updateSignature : updateSignature,

                getSignatureImage: getSignatureImage,

                clearSignature: clearSignature

            };

        };

    })(this.ns = this.ns || {});

    Packaging your add-in

    Now that we have all the parts of the component, we need to zip it together and import it in Microsoft Dynamics NAV. This is again as you would do for any other add-in.

    Create a zip file with the following structure:

     

    Put the manifest at the root, the JavaScript file in the script folder and the CSS file in the Stylesheet folder.

    Open any of the Microsoft Dynamics NAV clients (Windows, Web or Tablet) and go to the Control Add-ins page. Create a new entry named SignatureControl and enter the public key token that you saved earlier. Import the zip file.

     

    The C/SIDE side of things

    Now that our add-in is sitting comfortably within the confines of the Microsoft Dynamics NAV database, we need to add it to page. But before that, we want a place to save the signature image data. In this fabricated example, I will add the signature to the Sales Invoice card page from the Mini app (1304) which is based on the Sales Header table.

    1. In Object Designer, open the Sales Header table and add BLOB field called ‘SignatureImage’.
    2. Add the actual control page by opening page 1304 and add the control into a separate group.

    3.  

    By now you should be able to fire up this page and see how our control looks like. To do that open the client of your choice in the mini app. Navigate to the Sales Invoices and open the Sales Invoice card page.

    You should see the signature control. Try to draw in with the mouse or with your finger if you are on a touch enabled device.

    Even the clear button works already and allows you to delete your doodles.

    The last part that we are missing is to save and retrieve the pixels to the Microsoft Dynamics NAV database. To do that we need to write a bit of C/AL code.

    The C/AL code

    If you recall how we defined the add-in interface, we have three triggers to take care of: AddInReady, UpdateSignature and SignatureSaved.

    Nothing surprising here. The really interesting methods are SaveSignature and GetDataUriFromImage.

    This is where the conversion from between the URL encoded image string and a Microsoft Dynamics NAV BLOB occurs.

    The most convenient way to do this is to use the power of .NET for regular expressions matching and memory streams.

    So, let’s create a SaveSignature method and add the following .NET type variables to the locals:

    The URL encoded representation of the image contains some goo around the actual pixel information. With .NET regular expressions, we strip the header by matching it and preserving the rest.

    What is left is a base 64 encoded string, which we can convert to a byte array using the .net Convert utility class. We then pass it to the memory stream and save it to the Microsoft Dynamics NAV table as a BLOB.

    Obtaining the encoded URI is obviously the reverse operation. This is somewhat simpler; after reading the BLOB, we just need to re-add the header.

    Finally, we want to update the drawing, when we navigate the records:

    That’s it!

    Now you should be able to save the graphics and when you close and re-open the page or navigate through the Sales Invoices, the picture gets updated accordingly.

    Even though the most obvious usage scenarios are on the tablet, this add-in works on all three clients (Windows, Web and Tablet). 

    NOTE: To copy the code samples, see Extensibility for the Microsoft Dynamics NAV Tablet Client on MSDN.

  • Microsoft Dynamics NAV Team Blog

    Cumulative Update 19 for Microsoft Dynamics NAV 2013 has been released

    • 0 Comments

    Cumulative update 19 includes all application and platform hotfixes and regulatory features that have been released for Microsoft Dynamics NAV 2013.

    The cumulative update includes hotfixes that apply to all countries and hotfixes specific to the following local versions: 

    • AU - Australia
    • AT - Austria
    • BE - Belgium
    • CH - Switzerland
    • DE - Germany
    • DK - Denmark
    • ES - Spain
    • FI - Finland
    • FR - France
    • IS - Iceland
    • IT - Italy
    • NA - North America
    • NL - Netherlands
    • NO - Norway
    • NZ - New Zealand
    • SE - Sweden
    • UK - United Kingdom

    Where to find cumulative update 19

    You can download the cumulative update from KB 3000200 - Cumulative Update 19 for Microsoft Dynamics NAV 2013 (Build 38052).

    For a full list of all hotfixes included in cumulative updates for Microsoft Dynamics NAV 2013, see the following CustomerSource and PartnerSource pages:

    CustomerSource:

    PartnerSource:

    More Information

    For a list of all released cumulative updates, see Released Cumulative Updates for Microsoft Dynamics NAV 2013.

  • Microsoft Dynamics NAV Team Blog

    Cumulative Update 12 for Microsoft Dynamics NAV 2013 R2 has been released

    • 6 Comments

    Cumulative update 12 includes all application and platform hotfixes and regulatory features that have been released for Microsoft Dynamics NAV 2013 R2.

     The cumulative update includes hotfixes that apply to all countries and hotfixes specific to the following local versions:

    •   AU - Australia
    •   AT - Austria
    •   BE - Belgium
    •   CH – Switzerland
    •   CZ – Czech Republic
    •   DE - Germany
    •   DK - Denmark
    •   ES - Spain
    •   FI  - Finland
    •   FR - France
    •   IS - Iceland
    •   IT - Italy
    •   NA - North America
    •   NL - Netherlands
    •   NO - Norway
    •   NZ - New Zealand
    •   RU – Russia
    •   SE - Sweden
    •   UK - United Kingdom

    Where to find cumulative update 12

    You can download the cumulative update from KB 3000199  – Cumulative Update 12 for Microsoft Dynamics NAV 2013 R2 (Build 38053). 

    For a full list of all hotfixes included in cumulative updates for Microsoft Dynamics NAV 2013 R2, see the following CustomerSource and PartnerSource pages:

    CustomerSource:

    PartnerSource

    More Information

     For more information about cumulative updates for Microsoft Dynamics NAV 2013 R2, see Announcement of update rollups for Microsoft Dynamics NAV 2013 R2.

Page 2 of 47 (693 items) 12345»