Tuesday, 11 December 2018

Message: Duplicate type with name 'Dynamics.Ax.Application.XXXX' in assembly 'Dynamics.Ax.Application, Version=6.3.5000.138, Culture=neutral, PublicKeyToken=null'.

Scenario: 

Trying to deploy Inbound custom service using HTTP adapter.

Issue:

IIS Application pool stops automatically and not stay in start mode.

Below is the event viewer 

There was an error during processing of the managed application service auto-start for configuration path: 'MACHINE/WEBROOT/APPHOST/Default Web Site/MicrosoftDynamicsAXAif60'. The error message returned is: 'An initialization error occurred while trying to preload an application.

Exception: System.Configuration.ConfigurationErrorsException

Message: Duplicate type with name 'Dynamics.Ax.Application.xxxxxxx' in assembly 'Dynamics.Ax.Application, Version=6.3.5000.138, Culture=neutral, PublicKeyToken=null'.

StackTrace:    at System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective)
   at System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory()
   at System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai)
   at System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig)
   at System.Web.Compilation.BuildManager.GetPreStartInitMethodsFromReferencedAssemblies()
   at System.Web.Compilation.BuildManager.CallPreStartInitMethods(String preStartInitListPath, Boolean& isRefAssemblyLoaded)
   at System.Web.Compilation.BuildManager.ExecutePreAppStart()
   at System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException)

InnerException: System.BadImageFormatException

Message: Duplicate type with name 'Dynamics.Ax.Application.AMS_ItemImportContract' in assembly 'Dynamics.Ax.Application, Version=6.3.5000.138, Culture=neutral, PublicKeyToken=null'.

StackTrace:    at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
   at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective)'.  The worker process will be marked unhealthy and be shutdown.  The data field contains the error code.


Solution: 

This solution worked for me, but I'm not sure if it works for every one.

1. Goto IIS Manager
2. Click on application pools
3. Select MicosoftDynamicsAXAif60
4. Right click  and select Basic Settings.
5. In the Edit application pool form select .NET CLR version
6. From the drop-down select V2.0xxxx
7. Now start the Application pool.
8. Now goto AX and try to deploy the AIF service.
9. Now change the .NET CLR version back to V4.0xxxx

It has worked for me and hope will work for you also, let me know in the comments.

Hope this will solve the issue.


Thursday, 6 December 2018

Item Service in AX 2012- This document does not support the AxEcoResProductIdentifier class or AxEcoResProductCategory class

Item Service in AX 2012- This document does not support the AxEcoResProductIdentifier class or AxEcoResProductCategory class


This is just my reference, thanks to original post 

In AX 2012's Item service as part of creating an Item/Product through AIF Service if you try to populate entities EcoResProductIdentifier, EcoResProductCategory you may receive these errors: 

This document does not support the AxEcoResProductIdentifier class 
or 
This document does not support the AxEcoResProductCategory class 

You may very well receive these errors after going through the AIF wizard and regenerating the Item Service (InventTable and EcoResProduct), the reason being wizard doesn't generate some code related to all the Tables involved in the AxdQuery.

To fix this, I had to add following code in class -> AxdEcoResProduct-> prepareForSave()

       case classNum(AXEcoResProductIdentifier):
            axecoResProductIdentifier   = _axdStack.top() as AxEcoResProductIdentifier;
            axEcoResProduct             = axecoResProductIdentifier.parentAxBC() as AxEcoResProduct;
            axecoResProductIdentifier.parmProduct(axEcoResProduct.parmRecId());
            return true;       
        
        case classNum(AxEcoResProductCategory):
            axEcoResProductCategory     = _axdStack.top() as AxEcoResProductCategory;
            axEcoResProduct             = axEcoResProductCategory.parentAxBC() as AxEcoResProduct;
            axEcoResProductCategory.parmProduct(axEcoResProduct.parmRecId());
            return true;   

Tuesday, 23 October 2018

Create Credit note using X++ AX2012

In the below example we are going to create a credit note for a Sale order which is already invoiced.

For this, we need to create a class and add the below method.
In this method, we are getting the data from a temp table mkCreditNote or any other source like CSV, WCF etc.
public void postCreditnote( RecId               _creditnoteRecid)
{
    CustInvoiceTrans        custInvoiceTrans;
    SalesCopying            salesCopying;
    boolean                 isCreditNoteCreated,isCreditNotePosted;
    SalesId                 salesid;
    SalesTable              salesTable;
    MKCreditNote           mkCreditNote;
    TmpFrmVirtual           tmpFrmVirtualHeader;
    TmpFrmVirtual           tmpFrmVirtualLines;

    void loadTmpVirtualTableAndCreateCN(CustInvoiceTrans _custInvoiceTrans,MKCreditNote _mkCreditNote,SalesTable _salesTable)
    {
        delete_from tmpFrmVirtualLines;
        tmpFrmVirtualLines.TableNum = _custInvoiceTrans.TableId;
        tmpFrmVirtualLines.RecordNo = _custInvoiceTrans.RecId;
        tmpFrmVirtualLines.Id = _custInvoiceTrans.SalesId;
        tmpFrmVirtualLines.LineNum = _custInvoiceTrans.LineNum;
        tmpFrmVirtualLines.TransDate = _custInvoiceTrans.InvoiceDate;
        tmpFrmVirtualLines.Qty = _mkCreditNote.Qty;

        tmpFrmVirtualLines.write();

        salesCopying = SalesCopying::construct(SalesPurchCopy::CreditNoteLines);
        salesCopying.initParameters(_salesTable,
                                    tmpFrmVirtualLines,
                                    tmpFrmVirtualHeader,
                                    1,
                                    true,
                                    false,
                                    true,
                                    true,
                                    false);

        salesCopying.copy();
    }

    select firstOnly salesid, RecId from mkCreditNote
    where mkCreditNote.RecId == _creditnoteRecid;
    if (mkCreditNote.RecId)
    {
        salesTable = SalesTable::find(amsCreditNote.SalesId,false);
        if (salesTable.RecId)
        {
            while select amsCreditNote
                join custInvoiceTrans
                where custInvoiceTrans.SalesId == mkCreditNote.SalesId
                && custInvoiceTrans.ItemId == mkCreditNote.ItemId
                && custInvoiceTrans.InventDimId == mkCreditNote.InventDimId
                && custInvoiceTrans.InventTransId == mkCreditNote.InventTransId
                && amsCreditNote.RecId == _creditnoteRecid
            {
                isCreditNoteCreated = true;
                loadTmpVirtualTableAndCreateCN(custInvoiceTrans,mkCreditNote,salesTable);
            }
        }
    }


}

Monday, 8 October 2018

Pass Date and Real (double) datatype from C# to AIF (Sales order)

This is a tricky thing to do. Let's say you are creating a sales order using AIF and you wanted to test it using WSDL from C#.

Everything until this point seems to be very easy, now let's say you have some custom field of type Real and you want to pass a value to that field.

Here comes the trick, for any real or date type variables we need to explicitly specify that we are passing these field values, then only these values will appear in the inbound XML file.

Now how do we do that?
Below is the code sample, as you can see there are two lines for adding MK_PurchPrice. One we will specify that this filed value is going to pass by using MK_PurchPriceSpecified = true and the second line is the actual value. i.e MK_PruchPrice = xxxx

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using createSalesOrderAIF.ServiceReference1;

namespace createSalesOrderAIF
{
    class Program
    {
        static void Main(string[] args)
        {
            var line = new AxdEntity_SalesLine()
            {
                MK_PurchPriceSpecified = true,
                MK_PurchPrice = Convert.ToDecimal(100.20),
                ItemId = "2476619",
                SalesQty = 20,
                SalesUnit = "ea",
                SalesPriceSpecified = true,
                SalesPrice = 200
               
            };

            var order = new AxdEntity_SalesTable()
            {
                CustAccount = "C5001",
                PurchOrderFormNum = "xyz",
                MK_VendAccount = "V1310",
               
                ReceiptDateRequestedSpecified = true,            
                ReceiptDateRequested = DateTime.Now.Date,
                MKTotalGSTSpecified = true,
                MKTotalGST = Convert.ToDecimal(20.10),
                MK_PurchInvoiceId = "Inv_25",
                SalesLine = new AxdEntity_SalesLine[] { line }
            };

            var orderList = new AxdEntity_SalesTable[] { order };
            var callContext = new CallContext() { Company = "ZW01" };
            var client = new SalesOrderServiceClient();

            try
            {
                client.create(callContext, orderList);
                client.Close();
            }
            catch
            {
                client.Abort();
                throw;
            }
        }
    }
}

Thursday, 4 October 2018

Using Delegates in the new Dynamics 365 AX (AX 7)

Here we are going to see how we can use the "Delegates".

Background: 
delegates: X++ delegates expose the publisher-subscriber pattern where a delegate defines a clear contract in a publisher class. It is a great way of encapsulating a piece of code. Delegates were introduced in AX 2012 couple of years back. With the new AX release, delegates are the recommended way for customizing standard AX classes.

Example
Now we will see an example of how we can use delegates in the new D365 to develop customizations. 

here we will see how to customise standard AX sales order confirmation process. To keep it simple we will the change value of a field in confirmation journal table. The idea here is how to develop delegates and call them.

Confirmation journal header data is stored in CustConfirmJour table and it is initialised in the below class method during the sales confirmation posting process. Let’s modify it using delegates.




First we create a new delegate method in this class. This serves the purpose of defining a contract between the delegate instance and the delegate handler. There is no business logic inside the delegate method. Also notice that the delegates have return type as Void. In order to access the result value we have to pass EventHandlerResult object as a parameter.
 
 

 
Now we modify the actual method, declare the Event handler result object and call the delegate with the parameters in the method which we need to customise . The only customization in this method is 2 lines of code as highlighted below:
 
 

 
The class structure looks as below:



 Now we create the event handler method and this is where MS has done really nice stuff in moving the AX development environment to Visual Studio. Right click on the delegate method and copy the handler method definition.


Create a new class which will be used to subscribe to the delegate. So we create a new class, let call is salesConfirmJournalExt and paste the copied clipboard text
 
 

The delegate handler definition is automatically added with the below information:
 
 

Now we can add our custom code in this method. I just changed the purchase order field value and added some Infolog. Note that I am actually not returning anything in this method and not using the eventHandlerResult object really.


 So we are done. The see it wokring let's build the solution and confirm a sales order.



During the process the  Infolog messages we added in the delegate handler method are shown 

The confirmation journal has the custom text appended to it in the field we used in our new class method.
 
 

Microsoft strongly recommends to use Delegates for customization due to all the good reasons of having minimum code changes in standard product. So try to use delegates to have a cleaner and manageable solutions.

Monday, 1 October 2018

Importing Product Master into AX 2012 using X++ job

//Importing Product Master into AX 2012 using X++ job
static void UploadProductMaster(Args _args)
{
    CommaTextIO         csvFile;
    container                  readCon;
    counter                     icount,inserted;
    Dialog                      dialog;
    DialogField             dfFileName;
    FileName                 fileName;

    InventTable                            inventTable;
    EcoResProduct                      ecoResProduct;
    EcoResProductMaster          EcoResProductMaster;
    EcoResProductTranslation  ecoResProductTranslation;
    InventModelGroupItem        InventModelGroupItemLoc;

    EcoResDistinctProductVariant                    EcoResDistinctProductVariant;
    EcoResProductDimensionGroupProduct  ecoResProductDimensionGroupProduct;
    EcoResStorageDimensionGroupItem         ecoResStorageDimensionGroupItem;
    EcoResTrackingDimensionGroupItem       ecoResTrackingDimensionGroupItem;
    EcoResStorageDimensionGroupProduct   ecoResStorageDimensionGroupProduct;
    EcoResTrackingDimensionGroupProduct ecoResTrackingDimensionGroupProduct;

    InventTableModule           inventTableModule;
    inventItemGroupItem         inventItemGroupItem;
    InventItemSetupSupplyType   inventItemSetupSupplyType;
    ecoResProductIdentifier     ecoResProductIdentifier;


    ItemId                      itemID ;
    str       name,Description,itemtype,productDimensionGroup,StorageDimensionGroup,TrackingDimensiongroup,modelGroupId,itemGroupId,unit,price,searchname;

    inserted =0;
    #File


    dialog = new Dialog("Pick the file");
    dfFileName = dialog.addField(extendedTypeStr("FilenameOpen"));
    dialog.filenameLookupFilter(["All files", #AllFiles]);


    if (dialog.run())
    {
        csvFile = new CommaTextIo(dfFileName.value(), 'r');
        csvFile.inFieldDelimiter(',');
        readCon = csvFile.read();
        ttsBegin;
        while(csvFile.status() == IO_Status::OK)
        {
            readCon = csvFile.read();

            if(readCon)
            {
                icount++;

                itemId                = "ABC9";//conPeek(readCon,1);
                name                  = "ABC9name";//conPeek(readCon,2);
                searchname      = "searchname";
                Description      = "DEscription";
                itemtype            = "BOM";
                productDimensionGroup   = "PG_4";//conPeek(readCon,3);
                StorageDimensionGroup   = "PDG_001";//conPeek(readCon,4);
                TrackingDimensiongroup  = "PDG_001";//conPeek(readCon,5);
                modelGroupId    = "FIFO";//conPeek(readCon,6);
                itemGroupId     = "Television";//conPeek(readCon,7);
                unit            = "ea";//conPeek(readCon,8);
                price           = "0";//conPeek(readCon,9);

                 select firstOnly ecoResProduct where EcoResProduct.DisplayProductNumber == itemId;

                if(!ecoResProduct)
                {
                    EcoResProductMaster.initValue();
                    EcoResProductMaster.DisplayProductNumber = itemId;
                    EcoResProductMaster.SearchName = searchname;
                    EcoResProductMaster.ProductType = EcoResProductType::Item;
                    EcoResProductMaster.VariantConfigurationTechnology = EcoResVariantConfigurationTechnologyType::PredefinedVariants;
                    EcoResProductMaster.insert();
                    ecoResProduct= EcoResProductMaster;
                }

                ecoResProductTranslation.Product = ecoResProduct.RecId;
                ecoResProductTranslation.Name = name;
                EcoResProductTranslation.Description = Description;
                ecoResProductTranslation.setDefaultLanguage();
                ecoResProductTranslation.insert();

                EcoResDistinctProductVariant.DisplayProductNumber = itemId ;
                EcoResDistinctProductVariant.ProductMaster = ecoResProduct.RecId;
                EcoResDistinctProductVariant.ProductType = ecoResProduct.ProductType;
                EcoResDistinctProductVariant.insert();

                inventTable.initValue();
                inventTable.initFromEcoResProduct(ecoResProduct);
                inventTable.ItemId = itemId;
                inventTable.NameAlias = ecoResProduct.SearchName;
                if(ItemType == "BOM")
                    inventTable.PmfProductType = PmfProductType::BOM;
                else
                    inventTable.PmfProductType = PmfProductType::None;
                inventTable.insert(true);

                inventTableModule.initValue();
                inventTableModule.ItemId = inventTable.ItemId;
                inventTableModule.ModuleType = ModuleInventPurchSales::Invent;
                InventTableModule.UnitId = unit;
                InventTableModule.Price = any2real(Price);
                inventTableModule.insert();

                inventTableModule.initValue();
                inventTableModule.ItemId = inventTable.ItemId;
                inventTableModule.ModuleType = ModuleInventPurchSales::Purch;
                InventTableModule.UnitId = unit;
                InventTableModule.Price =  any2real(Price);
                inventTableModule.insert();

                inventTableModule.initValue();
                inventTableModule.ItemId = inventTable.ItemId;
                inventTableModule.ModuleType = ModuleInventPurchSales::Sales;
                InventTableModule.UnitId = unit;
                InventTableModule.Price = any2real(Price);
                inventTableModule.insert();

                //Create inventItemLocation
                InventItemLocation::createDefault(inventTable.ItemId);

                // Creates a new item default order type for the product that is released.

                inventItemSetupSupplyType.initValue();
                inventItemSetupSupplyType.ItemId = inventTable.ItemId;
                inventItemSetupSupplyType.ItemDataAreaId = inventTable.DataAreaId;
                inventItemSetupSupplyType.insert();

                //create relationship tables to dimension groups.

                ecoResStorageDimensionGroupProduct = EcoResStorageDimensionGroupProduct::findByProduct(ecoResProduct.RecId);
                ecoResTrackingDimensionGroupProduct = EcoResTrackingDimensionGroupProduct::findByProduct(ecoResProduct.RecId);

                if (ecoResStorageDimensionGroupProduct.RecId)
                {
                    // mandatory storage dimension group for the product
                    ecoResStorageDimensionGroupItem.ItemDataAreaId = inventTable.DataAreaId;
                    ecoResStorageDimensionGroupItem.ItemId = inventTable.ItemId;
                    ecoResStorageDimensionGroupItem.StorageDimensionGroup = ecoResStorageDimensionGroupProduct.StorageDimensionGroup;
                    ecoResStorageDimensionGroupItem.insert();
                }

                if (ecoResTrackingDimensionGroupProduct.RecId)
                {
                    // mandatory tracking dimension group for the product
                    ecoResTrackingDimensionGroupItem.ItemDataAreaId = inventTable.DataAreaId;
                    ecoResTrackingDimensionGroupItem.ItemId = inventTable.ItemId;
                    ecoResTrackingDimensionGroupItem.TrackingDimensionGroup = ecoResTrackingDimensionGroupProduct.TrackingDimensionGroup;
                    ecoResTrackingDimensionGroupItem.insert();
                }


                InventModelGroupItemLoc.ItemDataAreaId = inventTable.dataAreaId;
                InventModelGroupItemLoc.ItemId = inventTable.ItemId;
                InventModelGroupItemLoc.ModelGroupId =modelGroupId;
                InventModelGroupItemLoc.ModelGroupDataAreaId = curext();
                InventModelGroupItemLoc.initValue();
                InventModelGroupItemLoc.insert();

                 //Item group
                inventItemGroupItem.clear();
                inventItemGroupItem.initValue();
                inventItemGroupItem.ItemDataAreaId = inventTable.dataAreaId;
                inventItemGroupItem.ItemId = inventTable.ItemId;
                inventItemGroupItem.ItemGroupId = itemGroupId;
                inventItemGroupItem.ItemGroupDataAreaId = curext();
                inventItemGroupItem.insert();

                //write product to dimension group relation
                ecoResProductDimensionGroupProduct.initFromProduct(ecoResProduct);
                ecoResProductDimensionGroupProduct.ProductDimensionGroup = EcoResProductDimensionGroup::findByDimensionGroupName(productDimensionGroup).RecId;// "PG_4";
                ecoResProductDimensionGroupProduct.insert();

                ecoResStorageDimensionGroupItem.initValue();
                ecoResStorageDimensionGroupItem.ItemDataAreaId = inventTable.dataAreaId;
                ecoResStorageDimensionGroupItem.ItemId = inventTable.ItemId;
                ecoResStorageDimensionGroupItem.StorageDimensionGroup = EcoResStorageDimensionGroup::findByDimensionGroupName(StorageDimensionGroup).RecId;
                ecoResStorageDimensionGroupItem.insert();

                ecoResTrackingDimensionGroupItem.initValue();
                ecoResTrackingDimensionGroupItem.ItemDataAreaId = inventTable.dataAreaId;
                ecoResTrackingDimensionGroupItem.ItemId = inventTable.ItemId;
                ecoResTrackingDimensionGroupItem.TrackingDimensionGroup = EcoResTrackingDimensionGroup::findByDimensionGroupName(TrackingDimensiongroup).RecId;
                ecoResTrackingDimensionGroupItem.insert();

                ecoResProductIdentifier.clear();
                ecoResProductIdentifier.initValue();
                ecoResProductIdentifier.ProductNumber = itemId;
                ecoResProductIdentifier.Product = EcoResProductMaster.RecId; //ecoResProductMaster.RecId;
                ecoResProductIdentifier.insert();

            }

        }
        ttsCommit;
    }

}


Custom service to import product master using WCF service AX 2012.

In this article, we will see how to import a product into Dynamics AX 2012 using WCF custom service. Use this approach only you need to extream customization otherwise, we can use the standard DIXF Product master for details you can check below link.

 "How to import items master data using Data Migration Framework"


Coming to Custom service to import product master. 

1. We need to create a service class which extends SysOperationServiceBase
class MK_ItemMasterService extends SysOperationServiceBase
{
}

2. Add Entry point method which takes contract class as parameter. 

[SysEntryPointAttribute(true)]
public ItemId createProduct(MK_ItemImportContract _itemImport)
{
      InventTable            inventTable,ret;
    try
    {
        ttsBegin;
        inventTable = InventTable::find(_itemImport.parmProductNumber(),true);
        if (inventTable.RecId)
        {
            //update product
            this.update(_itemImport,inventTable);
        }
        else
        {
            //create new product
            ret = this.create(_itemImport);
        }// end of else
        ttsCommit;
    }
    catch
    {
        return "";
    }

    return ret.itemid;

}

3. Now we can create a Data contract class as below.

[DataContractAttribute]
public class MK_ItemImportContract
{
    Str DisplayProductNumber; // = "Bulb60W1",
    //ProductType = AxdEnum_EcoResProductType.Item,
    str SearchName;// = "Bulb60W1"
    str Name;
    str ProductNumber;
    str StorageDimGroup;
    str ProductDimGroup;
    str TrackingDimGroup;
}

4. Add Data member attribute method for all the variables declared in the class like below.

[DataMemberAttribute]
public str parmStorageDimGroup(Str _StorageDimGroup = StorageDimGroup)
{
    StorageDimGroup = _StorageDimGroup;
    return  StorageDimGroup;
}

5. Now it is the time to create a service 

Goto AOT\Services\ and right click and add new 
Name : MK_ItemMasterService
Class: Service class name (MK_ItemMasterService)
Description: "Product Import Service".
External Name: 

6. Add the Operations to Service.
By Expanding the service and right click on Operations and add
Select the method "CreateProduct" and click ok.

7. Create Service Group 
\Service Groups\MK_ItemMasterServices
Name: MK_ItemMasterServices
AutoDeploy: Yes
Description:

add the above-created service (step 6) to this service group.

8. Deploy the service Group.
Right click on Service Group and deploy.
This will create an Inbound service. 
Copy the WSDL URL.

Now it's time to test the above service. For that, we will create a C# console application.

9. Create a C# console application 
Right click on the references and add a service reference 
Past the URL copied from step 8.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MKProductImportService.ServiceReference1;

namespace MKProductImportService
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                MK_ItemMasterServiceClient client = new MK_ItemMasterServiceClient();
                CallContext context = new CallContext();
                context.Company = "CW01";
                Console.WriteLine("Object Created Success!");

                MK_ItemImportContract procuct = new MK_ItemImportContract();
                procuct.parmDisplayProductNumber = "T00003";
                procuct.parmName = "Test3 Procut WCF";
                procuct.parmProductNumber = "T00003";
                procuct.parmStorageDimGroup = "WL";
                procuct.parmTrackingDimGroup = "BS";
                procuct.parmSearchName = "Test3 WCF";

                Console.WriteLine("Lines added Success!");
                string itemid = client.createProduct(context, procuct); // call the create product method

                Console.WriteLine("Item Created:" + itemid);

                Console.WriteLine("Success! !!!");

            }
            catch (Exception e)
            {
                Console.WriteLine(e.InnerException.Message);
            }
            //Console.ReadLine();
        }
    }
}

10. Build and run 

........................


Monday, 10 September 2018

Get temp data from class to form Data source AX 2012 + X++

Get temp data from class to form Data source AX 2012 + X++

In the below example we will see how we can use the temporary table as form datasource.
we can use a temporary table as datasource whether it is of type tempDb or InMemory.

1. Create a temporary table and just need to drag into the form datasource.
2. Create a class to fill the temporary table.

public class MK_ItemDiscountGroup
{
    MK_tmpInventTable          tmpInventTable;
   
    PriceDiscGroup              priceDiscGroup;

}
3. add a method to fill temp data and return tempTable

public MK_tmpInventTable fillTmpData()
{
    InventTable         inventTable;
    InventTableModule   inventTableModule;
    //MK_tmpInventTable  tmpInventTable;
    //RecordInsertList insertList = null;
    //insertList = new RecordInsertList(tablenum(MK_tmpInventTable));
    ttsbegin;
    while select inventTable
        join inventTableModule
        where inventTable.ItemId == inventTableModule.ItemId
        && inventTableModule.ModuleType == ModuleInventPurchSales::Sales
        && inventTableModule.LineDisc == priceDiscGroup.GroupId
    {
       
            tmpInventTable.ItemId = inventTable.ItemId;
            tmpInventTable.NameAlias = inventTable.NameAlias;
            tmpInventTable.Name = inventTable::name(inventTable.ItemId);
            tmpInventTable.LineDisc = inventTableModule.LineDisc;
            tmpInventTable.insert();
       
        //insertList.add(tmpInventTable);

    }

    //insertList.insertDatabase();
    ttscommit;
    return tmpInventTable;


}

4. call this method in init method of form after super.

public void init()
{

     super();
     itemDiscountGroup = MK_ItemDiscountGroup::construct(priceDiscGroup);
    itemDiscountGroup.fillTmpData();
    //if table is of type tempDb, call following method.
    MK_tmpInventTable.linkPhysicalTableInstance(itemDiscountGroup.fillTmpData());
    //Note:// if table is of type InMemory,call following method.

    MK_tmpInventTable.setTmpData(element.insertRecords());
}

// important thing comes here
// if the table is of type InMemory, call following method.

TmpTable.setTmpData(element.insertRecords());

// if the table is of type tempDb, call following method.

TmpTable.linkPhysicalTableInstance(element.insertRecords());

Wednesday, 11 July 2018

How to Use LIKE Operator in select Query X++

It is very common to use Like Operator in SQL 

SELECT column1, column2, ...
FROM table_name
WHERE columnN LIKE pattern;

Now we will see how we can use the Like operator in X++

It is very similar to SQL as shown in the below example. In this example, I'm updating  TrvPartyEmployeeRelationship with HcmWorker table.


static void MK_TrvPartyEmpUpd(Args _args)
{
    DataArea    dataArea;
    TrvPartyEmployeeRelationship    empRelation;
    HcmWorker                       worker;
    HcmPersonnelNumberId            empName;
    while select dataArea
        where dataArea.isVirtual == NoYes::No
    {
        changeCompany(dataArea.id)
        {
            empRelation = null;
            while select forUpdate empRelation
            {
                worker = null;
                empName = "";
                empName = strFmt("%1%2%3","*",empRelation.DEL_EmplId,"*");
                select firstOnly worker 
                where worker.PersonnelNumber like empName;
                if (worker.RecId)
                {
                    ttsBegin;
                    empRelation.selectForUpdate(true);
                    empRelation.Worker = worker.RecId;
                    empRelation.doDelete();
                    ttsCommit;
                    
                }
            }
            
        }
    }
}

Tuesday, 17 April 2018

Generate file name with time and random number X++

static str getFileName(str _fileName)
{
    str             lFileName;
    UtcDateTime     dateTime = DateTimeUtil::getSystemDateTime();
    int             randomNumber;
    str             hours = '';
    str             minutes = '';
    str             seconds = '';
    str             yyyy = '';
    str             mm = '';
    str             dd = '';

    randomNumber = 0;
    randomNumber = xGlobal::randomPositiveInt32();

    hours   = int2str(DateTimeUtil::hour(dateTime));
    minutes = int2str(DateTimeUtil::minute(dateTime));
    seconds = int2str(DateTimeUtil::second(dateTime));
    yyyy    = int2str(DateTimeUtil::year(dateTime));
    mm      = int2str(DateTimeUtil::month(dateTime));
    dd      = int2str(DateTimeUtil::day(dateTime));
   
    hours   = (strLen(hours) == 1) ? '0' + hours : hours ;
    minutes = (strLen(minutes) == 1) ? '0' + minutes : minutes ;
    seconds = (strLen(seconds) == 1) ? '0' + seconds : seconds ;
    mm      = (strLen(mm) == 1) ? '0' + mm : mm ;
    dd      = (strLen(dd) == 1) ? '0' + dd : dd ;
   
    lFileName = strFmt('%1_%2%3%4_%5%6%7_%8.xml',lFileName,yyyy,mm,dd,hours,minutes,seconds,randomNumber);
    return lFileName;

}

Monday, 16 April 2018

SSRS Web Service fix


1.1        Start SSRS Service

1.       From Server, check http://pbi04/Reports from IE
2.       If we received “This page can’t be displayed”
3.       Then Open Reporting Services Configuration Management
4.       Connect to Server – PBI04 and check Report Server is “Start”
5.       Once all Green apply then select PBI04\MSSQLSERVER to all options available to edit
6.       Go to Web Service URL option and click Report Server Web Service URLs to test
7.       If page is not open then following need to check
-                      Open Command Prompt with “Run as Administrator”
-                      Run netstat –an
-                      Check list and see which Local Address has Port 80, if too many lists then
0.0.0.0 ß all IPv4 addresses on the local machine
192.168.xx.xx ß allocated IP address, for example 192.168.29.143
127.0.0.1 ß Localhost
o        Run command: netsh http show iplisten
o        This command will only show with Port 80
-                      More likely specific IP does not have Port 80 (listen) – 192.168.42.178 & 0.0.0.0
-                      Run following to add
o        netsh http add iplisten ipaddress=192.168.42.178:80
o        netsh http add iplisten ipaddress=0.0.0.0:80

Sunday, 15 April 2018

MDM Development Setup and Configuration and Troubleshooting


MDM Development Setup and Configuration and Troubleshooting
1.       All the user account which part of MDM integration is should have been grant with following permissions,
a.       MDS Service Account in computer management
b.      Should be an LogOn user to MDS Database
c.       MDS Database user should have the membership mdm_exec and axmdm_exec permission should be checked
d.      MDS Database user should have the Owned schema are mdm,stg,mdq,dqs
e.      Users should be added to MDS site user with Super user permissions.
2.       All the MDM Database should be associated with an IIS site under Default website, so you verify the same by looking into the web config of the respective MDS IIS site where the MDS Database is configuring to connect between IIS site and MDS Database.
3.       We need to make sure that MDS IIS site is up and running and the user have enough privilege to access the same by browsing the site from IIS. Basically you can verify the permission once you open the MDS site you can see all the feature like System Administration, Integration Management and User Group Permission etc.
4.       Log on to AX machine and open the Dynamics AX Management shell and execute the following command,
a.       Syntax: Set-AXMasterDataManagementMDSSetup –MDSServerName -MDSDatabase

Eg: Set-AXMasterDataManagementMDSSetup –MDSServerName dBI04 -MDSDatabase MDS
5.       Open the Dynamics AX client and make sure that the License configuration has been enabled for the MDM in the following path,
a.       System Administration->License Configuration->Data Import and Export -> MDM
6.       In Dynamics AX client, go to Data Import and Export Menu under Master Data Management select Configure MDM with following parameters,
a.       Server : MDM Database server name Eg: DBI04
b.      Repository : MDM Database Eg: MDS
c.       Service URL : Basically you can find this under MDM IIS site-> Services-> Service.svc and click on browse. Copy the same URL and paste it here.
d.      Click on Test configuration -> If user has all permission the connection should be succeeded.
7.       In Dynamics AX client, go to Publish Entities and Click on Create schema by selecting the required entity, this will basically create the schema in MDS site with new Model and Entity and you can verify the same by looking in to the MDS site. Basically, publishing the entities required Schema permission as I have mentioned above in point 1. Once the Entity schema is created in MDS site, the InMDS checkbox will be checked in the Publish entity form.
8.       In Dynamics AX client, go to Manage Synchronous and  create new Sync group. Go to entities Only published entities will be displayed in lookup, choose the required entity and save. Go to Settings and configure the Push and Pull operation. Finally click on New Schedule and Run the Sync either by batch or normally based on the Push and Pull configuration it sync the data to MDS. Once the sync is completed we’ll get info about the record count that is synced From and To MDS site.
Configuring Customer Interface
Assumption: AOS1 and AOS2 – Customer synchronous through MDM via MDS service. Let’s say AOS1 is the Source and AOS2 is the Destination.
 





By Default, Microsoft Dynamics AX 2012 R3 system contains out of BOX MDM entities they are,
1.       Customer
2.       Vendor
3.       Product
4.       Party
5.       Employee
This section describes about How to configure the standard out of box Customer Interface Sync between two different AOS system using MDS service.
1.       Open AOS1 environment and Dynamics AX client.
2.       Click on Publish Entities under MDM section under DIXF.
3.       Select Customer entity and click on Create Schema. Basically, it requires the following schema owner for the mds_schema_user user,
a.       mdm
b.      stg
c.       mdq
d.      dqs
4.      
Once the entity is published, we’ll get info saying that the “Entity is published successfully” and you can verify the same by looking into the entity in MDS site with same entity name and Model.










5.       Click on Manage Synchronization menu and Click on New to create new Sync group.
6.       After creating Sync group, click on Entity on the respective Sync group, all the Published entities will be displayed in the lookup. Select the Customer entity in the lookup and save the same.
7.       After the selecting the entity, click on settings and select the Synchronization Type, it should Push and Pull.
8.       Open AOS2 environment and Dynamics AX client.
9.       AOS2 environment should also be configured with same MDS server where the AOS1 system is connected.
10.   Once you click on Publish entities menu, you can see that the Customer entity is already Synced with checkbox InMDS is true, it says that already Customer entity is published.
11.   Click on Manage Synchronization menu and Click on New to create new Sync group.
12.   After creating Sync group, click on Entity on the respective Sync group, all the Published entities will be displayed in the lookup. Select the Customer entity in the lookup and save the same.
13.   After the selecting the entity, click on settings and select the Synchronization Type, it should be Pull.
14.   Click on New Schedule on the Sync Group and setup the Batch JOB
15.   Go to AOS1 machine and click on New Schedule on the Sync Group and setup the Batch JOB.

Important Links for the references:

Import and Export file from BLOB storage Account(Azure) in D365 F&O using X++

  Import and Export file from BLOB storage Account in D365 F&O using X++ Import: /// <summary> /// MKInventQualityOrderLineService...