Thursday, September 27, 2018

Adding new design and mapping with print management setup in Dynamics 365 finance and operation without overlay PU15 for existing Standard Report


Adding new design and mapping with print management setup in Dynamics 365 finance and operation without overlay PU15 for existing Standard Report

Sample: Purchase Order Confirmation
Requirement: Adding new fields in to purchase Order confirmation report and report layout need to change as per end user template. End user wants to tag new report design in to print management setup for vendor.

Steps:
è Create new project with our customize model and package
è Navigate to Table PurchPurchaseOrderTmp, right click -> Create Extension and rename
è Added newly field as shown below

è As per BP, All newly created mapped to field group & relation and Assign with Labels
è Duplicate Report (PurchPurchaseOrder) and rename it

è Make necessary design change and field mapping to SSRS report design
Sample:


è Add new class for extension (Existing class: PurchPurchaseOrderDP),
For field mapping for newly created fields
Using Chain of Command

è Rebuild project [Make sure sync on build should be TRUE]
è Check as of now, Print management setup lookup is listing with only one design for purchase order confirmation for the document type(Purchase Order)


è Adding new report design in to  Print management report format lookup list
Create new class for extension of PrintMgmtReportFormatPopulator and method addDocuments by using chain of command


è Rebuild project [Make sure sync on build should be TRUE]
è Navigate to /Account Payable/Setup/Form/Form Setup/General Tab/Print Management

è Map new design in print management setup as per end user requirement.


Dynamics 365 for finance and operations  - Project .axpp file shared  link:
https://1drv.ms/f/s!Asi_SJ2dXQ3Bqhbljy1VC2gb6nyH


Tuesday, September 25, 2018

Customization Analysis Report in Dynamics 365 for finance and operations

Customization Analysis Report (CAR)

What is the Customization Analysis Report?

The Customization Analysis Report is a tool that analyzes your customization and extension models, and runs a predefined set of best practice rules. The report is one of the requirements of the solution certification process. The report is in the form of a Microsoft Excel workbook.

Sample:

xppbp.exe -metadata=<local packages folder> -all -model=<ModelName> -xmlLog=C:\BPCheckLogcd.xml -module=<PackageName> -car=<reportlocation>
Example:

xppbp.exe -metadata=C:\Packages -all -model="MyAppSuiteCustomizations" -xmlLog=C:\temp\BPCheckLogcd.xml -module="ApplicationSuite" -car=c:\temp\CAReport.xlsx

Issue List with proposed fix (MS) details:

New Best Practices in Dynamics 365 for finance and operations

Reference:

https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/dev-tools/author-best-practice-rules 

Authoring Best Practice checks that use XML based input
http://www.agermark.com/2017/01/authoring-best-practice-checks-that-use.html

Reference Content from agermark.com


Authoring Best Practice checks that use XML based input
In AX7 you can pretty easily write and deploy your own Best Practice checks. The process of doing so is described in this article on the wiki.

Some of the standard Best Practice checks use XML files as input. These XML files are found under your local packages folder, in ..\PackagesLocalDirectory\Bin\BPExtensions\RuleXml

The following is an example of how you can write your own Best Practice check that uses an XML file as input. The check itself is used to check the naming of table extensions. We want to check that a certain prefix is part of the name, and that it is put in the correct place in the overall name. The prefix to look for is specified in the XML file.

The file is stored in ..\PackagesLocalDirectory\Bin\BPExtensions\RuleXml and the name is MVPProductPrefix.xml. The name is important, as a reference is made to it from the code.

Your Best Practice class needs to extend either DetectorWithXMLDataFile or MetadataDetectorWithXMLDataFile depending on the type of your check. In this case we extend MetadataDetectorWithXMLDataFile since we will be looking at table extension names.

Included in your solution you need to add a data contract class for the XML file. This class must extend from RulePatternsBase.
The framework and the base classes will then do the rest of the work with loading the XML file, de-serialize it and caching it.

Here is the code:
namespace MVP.AX.BestPracticeCheckExtensions
{
    using System;
    using System.Text.RegularExpressions;
    using Microsoft.Dynamics.AX.Framework.BestPractices.Extensions;
    using Microsoft.Dynamics.AX.Metadata.Upgrade.Common;
    using System.Runtime.Serialization;

    [BestPracticeRule(
        InvalidExtensionnameDiagnosticItem.DiagnosticMoniker,
        typeof(Messages),
        InvalidExtensionnameDiagnosticItem.DiagnosticMoniker + "Description",
        BestPracticeCheckerTargets.TableExtension),
     RuleAttributes("MVPProductPrefix.xml")]
    public class TableExtensionNameCheck : MetadataDetectorWithXMLDataFile<Microsoft.Dynamics.AX.Metadata.MetaModel.AxTableExtension, EGProductPrefix>
    {
        /// <summary>
        /// This method is called with the top level table extensions - everything else is ignored.
        /// </summary>
        /// <param name="tableExtension">A tableExtension instance to check for BP violations.</param>
        protected override void RunChecksOn(Microsoft.Dynamics.AX.Metadata.MetaModel.AxTableExtension tableExtension)
        {
            visitTableName(tableExtension.Name);
        }
       
        private void visitTableName(string tableName)
        {
            string requiredPrefix = base.RulePatterns.Prefix;
            string dotExtensionPattern = @"\w+." + requiredPrefix + "Extension";
            var match = Regex.IsMatch(tableName, dotExtensionPattern);

            if (!match)
            {
                // Didn't fint the correct pattern in the table extension name
                // Build a diagnostic ...
                InvalidExtensionnameDiagnosticItem diagnostic = new InvalidExtensionnameDiagnosticItem(
                    ModelElementPathBuilder.CreatePathForTable(tableName),
                    "TableExtension",
                    null,
                    tableName);
               
                // ... and report the error.
                this.ExtensionContext.AddErrorMessage(diagnostic);
            }
        }
    }

    [Serializable, DataContract(Name = "MVPProductPrefix", Namespace = "")]
    public class MVPProductPrefix : RulePatternsBase
    {
        /// <summary>
        /// This class is the data contract for the XML file 
        /// </summary>
       
        // Fields
        [DataMember(Name="Prefix")]
        public string Prefix;
    }
}

And here is the code for the diagnostic item:
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml.Linq;
using Microsoft.Dynamics.AX.Metadata.XppCompiler;

namespace MVP.AX.BestPracticeCheckExtensions
{
    /// <summary>
    /// Class that describes the error where invalid extension names are invalid
    /// </summary>
    [DataContract]
    class InvalidExtensionnameDiagnosticItem : CustomDiagnosticItem
    {
        private const string InvalidExtensionnameKey = "Extensionname";
        public const string DiagnosticMoniker = "InvalidExtensionname";

        public InvalidExtensionnameDiagnosticItem(string path, string elementType, TextPosition textPosition, string invalidExtensionname)
            : base(path, elementType, textPosition, DiagnosticType.BestPractices, Severity.Warning, DiagnosticMoniker, Messages.InvalidExtensionname, invalidExtensionname)
        {
            // Validate parameters.
            if (string.IsNullOrWhiteSpace(invalidExtensionname))
            {
                throw new ArgumentNullException("invalidExtensionname");
            }

            this.InvalidExtensionName = invalidExtensionname;
        }

        public InvalidExtensionnameDiagnosticItem(Stack<Ast> context, TextPosition textPosition, string invalidExtensionname)
            : base(context, textPosition, DiagnosticType.BestPractices, Severity.Warning, DiagnosticMoniker, Messages.InvalidExtensionname, invalidExtensionname)
        {
            // Validate parameters.
            if (string.IsNullOrWhiteSpace(invalidExtensionname))
            {
                throw new ArgumentNullException("invalidExtensionname");
            }

            this.InvalidExtensionName = invalidExtensionname;
        }

        [DataMember]
        public string InvalidExtensionName { get; private set; }

        // Serialization support
        public InvalidExtensionnameDiagnosticItem(XElement element)
            : base(element)
        {
        }

        /// <summary>
        /// Hydrate the diagnostic item from the given XML element.
        /// </summary>
        /// <param name="itemSpecificNode">The XML element containing the diagnostic.</param>
        protected override void ReadItemSpecificFields(System.Xml.Linq.XElement itemSpecificNode)
        {
            this.InvalidExtensionName = base.ReadCustomField(itemSpecificNode, InvalidExtensionnameKey);
        }

        /// <summary>
        /// Write the state into the given XML element.
        /// </summary>
        /// <param name="itemSpecificNode">The element into which the state is persisted.</param>
        protected override void WriteItemSpecificFields(System.Xml.Linq.XElement itemSpecificNode)
        {
            this.WriteCustomField(itemSpecificNode, InvalidExtensionnameKey, this.InvalidExtensionName);
        }
    }
}


Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...