Wednesday, 21 June 2023

Join view as a Second / Secondary data source in D365 F&O or AX 2012

 In this post I am going to discuss about how to add View as a Secondary data source in form and use it in the grid.


1. Create a form with table as a Root data source.



2. Create a Grid with this data source.



3. Form view, notice that right now  the invoice number field is a Display method and we are going to get it by using view



4. Create a AOT query and View for that query


add simple query to a view

View 

5. Add View as a Secondary data source


6. Join the view with required data source in this I am joining with VendPackingSlipTransInvoice Data source, you can join with any data source you want

7. Go to the VendPackingSlipTransInvoice data source and override the init method of the datsource

8. Add a link between the fields you want to provide the link.

9. Use datasource 






Tuesday, 20 June 2023

How to change the purchase order state to Draft?

 The following post is used to show, how to change the Purchase order to the "Draft" state. Sometimes to update simple fields it might check for the versioning state of the purchase order and it will through the following error "Changes to the document are only allowed in state Draft because change management is activated". For this case, you can use the following code.


/// <summary>

    /// Change the purchase order state to draft

    /// </summary>

    /// <param name = "_purchTable">Purchase order buffer</param>

    protected void changeState(PurchTable _purchTable)

    {

        if (_purchTable.ChangeRequestRequired && _purchTable.DocumentState >= VersioningDocumentState::Approved)

        {

            VersioningPurchaseOrder::newPurchaseOrder(_purchTable).createChangeRequest();

        }

    }

Friday, 24 March 2023

How to Create or copy product attributes using X++ code

 The post is about copying the product attributes from one product to another, you can use it to create new attributes as well.

/// <summary>

    /// Copy the product categories

    /// </summary>

    /// <param name = "_origProduct">Origin product</param>

    /// <param name = "_newProduct">New product</param>

    public void updateProductCategories(EcoResProduct _origProduct, EcoResProduct _newProduct)

    {

        EcoResProductCategory   ecoResProductCategory, ecoResProductCategoryOrig;

        EcoResProductRecId      newEcoResProductRecId = _newProduct.RecId;


        delete_from ecoResProductCategory

            where ecoResProductCategory.Product == newEcoResProductRecId;


        RefRecId  origProductRecId, newProductRecId,     productInstanceRecIdNew, ecoResTextValueRecId_AfterInsert;        

        

        EcoResCategory                     ecoResCategory;

        EcoResCategoryAttributeLookup      ecoResCategoryAttributeLookup;

        

        EcoResAttribute                    ecoResAttribute;

        EcoResAttributeValue               ecoResAttributeValue, ecoResAttributeValue_ForInsert;

        EcoResProductInstanceValue         ecoResProductInstanceValue, ecoResProductInstanceValueNew;

        EcoResTextValue                    ecoResTextValue, ecoResTextValue_ForInsert;

        

        if (_origProduct && _newProduct)        

        {            

            origProductRecId = _origProduct.RecId;

            newProductRecId = _newProduct.RecId;

            

            if (origProductRecId != newProductRecId)            

            {              

                ttsBegin;


                ecoResProductInstanceValueNew.Product = newProductRecId;


                new OverwriteSystemFieldsPermission().assert();


                ecoResProductInstanceValueNew.overwriteSystemfields(true);

                ecoResProductInstanceValueNew.(fieldNum(EcoResProductInstanceValue, InstanceRelationType)) = tableName2id(tableStr(EcoResProductInstanceValue));

                ecoResProductInstanceValueNew.insert();


                ecoResProductInstanceValueNew.overwriteSystemfields(false);

                CodeAccessPermission::revertAssert();

                ttsCommit;

                

                if (ecoResProductInstanceValueNew)                

                {

                    productInstanceRecIdNew = ecoResProductInstanceValueNew.RecId;

                    

                    while select ecoResProductCategoryOrig

                            where ecoResProductCategoryOrig.Product == origProductRecId

                        join ecoResCategory 

                            where ecoResCategory.RecId == ecoResProductCategoryOrig.Category

                    {

                        ttsbegin;

                        ecoResProductCategory.Product           = newProductRecId;                   

                        ecoResProductCategory.Category          = ecoResProductCategoryOrig.Category;

                        ecoResProductCategory.CategoryHierarchy = ecoResProductCategoryOrig.CategoryHierarchy;

                        ecoResProductCategory.insert();                       

                        ttscommit;

                        if (ecoResProductCategory)                        

                        {

                            while select ecoResCategoryAttributeLookup where ecoResCategoryAttributeLookup.Category == ecoResCategory.RecId  

                                        join ecoResAttribute where ecoResAttribute.RecId == ecoResCategoryAttributeLookup.Attribute

                            

                            {

                                select firstonly ecoResAttributeValue 

                                        where ecoResAttributeValue.Attribute == ecoResAttribute.RecId

                                    join ecoResProductInstanceValue 

                                        where ecoResProductInstanceValue.RecId == ecoResAttributeValue.InstanceValue 

                                        && ecoResProductInstanceValue.Product == origProductRecId

                                    join ecoResTextValue 

                                        where ecoResTextValue.RecId == ecoResAttributeValue.Value;

                                

                                if (ecoResAttributeValue.Attribute > 0)                                 

                                {

                                    ecoResTextValue_ForInsert.TextValue = ecoResTextValue.TextValue;

                                    new OverwriteSystemFieldsPermission().assert();

                                    ecoResTextValue_ForInsert.overwriteSystemfields(true);

                                    ecoResTextValue_ForInsert.(fieldNum(EcoResTextValue, InstanceRelationType)) = tableName2id(tableStr(EcoResTextValue));

                                    ecoResTextValue_ForInsert.insert();

                                    ecoResTextValue_ForInsert.overwriteSystemfields(false);

                                    CodeAccessPermission::revertAssert();

                                   

                                }

                                

                                if (ecoResTextValue_ForInsert)                                

                                {

                                    ecoResTextValueRecId_AfterInsert = ecoResTextValue_ForInsert.RecId;  

                                                                       

                                    ecoResAttributeValue_ForInsert.Attribute     = ecoResAttributeValue.Attribute;    

                                    ecoResAttributeValue_ForInsert.InstanceValue = productInstanceRecIdNew;      

                                    ecoResAttributeValue_ForInsert.Value         = ecoResTextValueRecId_AfterInsert;     

                                    ecoResAttributeValue_ForInsert.insert();

                                    

                                    

                                }

                            }  

                        }

                    }   

                }                

            }                       

        }

        

    }

Thursday, 23 March 2023

How to Create or Copy product using X++?

In this post I would like to show you how to create a Released product using X++. I have used the EcoResProductV2Entity to create the product. The reason for this is, by using the Entity default validations will be triggered and the references will be created automatically. If you want to use the table directly use EcoResProductMaster and create the product. Dont use EcoResDistinctProduct. If you use EcoResDistinctProduct latter it will difficult to create the product variants. It will check for Product master.


The hierarchy is, 

EcoResProductMaster,

EcoResProduct,

EcoResDistinctProduct.


internal final class ReleasedProductCopy

{

    /// <summary>

    /// Copy the selected product

    /// </summary>

    /// <param name = "_inventTable">Old product InventTable buffer</param>

    /// <param name = "_prodNameCon">Product name and search name container</param>

    public void copyProduct(InventTable _inventTable, container _prodNameCon)

    {        

        EcoResProduct                               product, origProduct;

        EcoResDescription                           productDesciption;

        EcoResDistinctProductVariant                ecoResDistinctProductVariant;

        EcoResProductName                           productName = conPeek(_prodNameCon, 1);

        

        if (_inventTable.RecId)

        {

            origProduct                             = _inventTable.Product();

            productDesciption                       = origProduct.productDescription();


            ttsbegin;

                   

            product = this.createNewProduct(origProduct, _prodNameCon);

        

            if (product)

            {

                //Create or update all language translations

                this.createOrUpdateTranslation(origProduct, product, productName, productDesciption);


                //Release the created master prodcut

                this.releaseProduct(product); 

               

                if (origProduct.productSubtype() == EcoResProductSubtype::ProductMaster)

                {

                    


                    //Create product variants

                    ecoResDistinctProductVariant = this.createProductVariants(origProduct, product);

                }


                //Update the released prodcut information

                this.createRetailKit(origProduct, product, ecoResDistinctProductVariant);

               

                Info(strFmt("@ItemCopy:NewProductInfo", product.DisplayProductNumber));

            }


            ttscommit;

        }

        

    }


    /// <summary>

    /// Create a new product from the exiting product

    /// </summary>

    /// <param name = "_origProduct">Origin product buffer</param>

    /// <param name = "_prodNameSearchName">Product name and Search name buffer</param>

    /// <returns>New product buffer</returns>

    public EcoResProduct createNewProduct(EcoResProduct _origProduct, container _prodNameSearchName)

    {

        EcoResProductV2Entity                       ecoResProductEntity;

        EcoResProductDimensionGroup                 ecoResProductDimensionGroup;

        EcoResStorageDimensionGroup                 ecoResStorageDimensionGroup;

        EcoResTrackingDimensionGroup                ecoResTrackingDimensionGroup;

        EcoResProductDimensionGroupProduct          ecoResProductDimensionGroupProduct;

        EcoResStorageDimensionGroupProduct          ecoResStorageDimensionGroupProduct;

        EcoResTrackingDimensionGroupProduct         ecoResTrackingDimensionGroupProduct;

        EcoResProductMasterModelingPolicy           ecoResProductMasterModelingPolicy;

        EcoResCategory                              ecoResCategory;

        EcoResProductCategory                       ecoResProductCategory;

        EcoResProduct                                origProduct;

        EcoResProductMaster                         ecoResProductMaster;

        WHSEcoResProductTransportationCodes         wHSEcoResProductTransportationCodes;

        EcoResProductServiceWarranty                ecoResProductServiceWarranty;

        EcoResDescription                           productDesciption;

        

        NumberSequenceReference                     numberSequenceReference = EcoResProductParameters::numRefProductNumber();

        NumberSequenceTable                         numberSequenceTable = numberSequenceReference.numberSequenceTable();

        NumberSeq                                   numberSeq   = NumberSeq::newGetNumFromId(numberSequenceTable.RecId);



        origProduct                             = _origProduct;

        productDesciption                       = origProduct.productDescription();


        select firstonly Name, RecId from ecoResProductDimensionGroup

            join ecoResProductDimensionGroupProduct

             where ecoResProductDimensionGroupProduct.ProductDimensionGroup == ecoResProductDimensionGroup.RecId

                && ecoResProductDimensionGroupProduct.Product == origProduct.RecId;


        select firstonly Name, RecId from ecoResStorageDimensionGroup

            join ecoResStorageDimensionGroupProduct

             where ecoResStorageDimensionGroupProduct.StorageDimensionGroup == ecoResStorageDimensionGroup.RecId

                && ecoResStorageDimensionGroupProduct.Product == origProduct.RecId;


        select firstonly Name, RecId from ecoResTrackingDimensionGroup

            join ecoResTrackingDimensionGroupProduct

             where ecoResTrackingDimensionGroupProduct.TrackingDimensionGroup == ecoResTrackingDimensionGroup.RecId

                && ecoResTrackingDimensionGroupProduct.Product == origProduct.RecId;


        select firstonly ecoResProductMaster

            where ecoResProductMaster.RecId == origProduct.RecId;


        select firstonly ecoResProductMasterModelingPolicy

            where ecoResProductMasterModelingPolicy.ProductMaster == ecoResProductMaster.RecId;


        select firstonly Name from ecoResCategory

            join ecoResProductCategory

            where ecoResProductCategory.Product == origProduct.RecId;


        select firstonly STCCCode, HarmonizedCode, NMFCCode from wHSEcoResProductTransportationCodes

            where wHSEcoResProductTransportationCodes.Product == origProduct.RecId;


        select firstonly ecoResProductServiceWarranty

            where ecoResProductServiceWarranty.DistinctProduct == origProduct.RecId;


        ecoResProductEntity.ProductNumber                           = numberSeq.num();

        ecoResProductEntity.ProductName                             = conPeek(_prodNameSearchName, 1);

        ecoResProductEntity.ProductSearchName                       = conPeek(_prodNameSearchName, 2);

        ecoResProductEntity.ProductDescription                      = productDesciption;

        ecoResProductEntity.ProductType                             = origProduct.ProductType;

        ecoResProductEntity.ProductSubType                          = origProduct.productSubtype();

        ecoResProductEntity.VariantConfigurationTechnology          = ecoResProductMaster.VariantConfigurationTechnology;

        ecoResProductEntity.ProductDimensionGroupName               = ecoResProductDimensionGroup.Name;

        ecoResProductEntitY.StorageDimensionGroupName               = ecoResStorageDimensionGroup.Name;

        ecoResProductEntity.TrackingDimensionGroupName              = ecoResTrackingDimensionGroup.Name;

        ecoResProductEntity.ServiceType                             = origProduct.ServiceType;

        ecoResProductEntity.IsCatchWeightProduct                    = origProduct.PdsCWProduct;

        ecoResProductEntity.IsProductVariantUnitConversionEnabled   = ecoResProductMaster.IsProductVariantUnitConversionEnabled;

        ecoResProductEntity.ProductColorGroupId                     = ecoResProductMaster.RetailColorGroupId;

        ecoResProductEntity.ProductSizeGroupId                      = ecoResProductMaster.RetailSizeGroupId;

        ecoResProductEntity.ProductStyleGroupId                     = ecoResProductMaster.RetailStyleGroupId;

        ecoResProductEntity.AreIdenticalConfigurationsAllowed       = ecoResProductMasterModelingPolicy.IsReuseConfigurationEnabled;

        ecoResProductEntity.IsAutomaticVariantGenerationEnabled     = ecoResProductMasterModelingPolicy.IsVariantGenerationEnabled;

        ecoResProductEntity.RetailProductCategoryName               = ecoResCategory.Name;

        ecoResProductEntity.STCCCode                                = wHSEcoResProductTransportationCodes.STCCCode;

        ecoResProductEntity.HarmonizedSystemCode                    = wHSEcoResProductTransportationCodes.HarmonizedCode;

        ecoResProductEntity.NMFCCode                                = wHSEcoResProductTransportationCodes.NMFCCode;

        ecoResProductEntity.WarrantyDurationTime                    = ecoResProductServiceWarranty.DurationTime;

        ecoResProductEntity.WarrantyDurationTimeUnit                = ecoResProductServiceWarranty.DurationTimeUnit;

        

        ecoResProductEntity.insert();


        EcoResProductNumber productNumber = ecoResProductEntity.ProductNumber;

        

        return EcoResProduct::findByProductNumber(productNumber);

    }


    /// <summary>

    /// Create new product variant

    /// </summary>

    /// <param name = "_oldProduct">source product</param>

    /// <param name = "_newProduct">Destination product</param>

    /// <returns>New variant buffer</returns>

    public EcoResDistinctProductVariant createProductVariants(EcoResProduct _oldProduct, EcoResProduct _newProduct)

    {

        EcoResConfiguration                     ecoResConfiguration;

        EcoResProductMasterConfiguration        ecoResProductMasterConfiguration;

        EcoResDistinctProductVariant            ecoResDistinctProductVariant;

        EcoResProductVariantConfiguration       ecoResProductVariantConfiguration;

        EcoResProductMasterColor                ecoResProductMasterColor, ecoResProductMasterColorOld;

        EcoResProductMasterStyle                ecoResProductMasterStyle, ecoResProductMasterStyleOld;

        EcoResProductMasterSize                 ecoResProductMasterSize, ecoResProductMasterSizeOld;        

        

        RefRecId                            ecoResDistinctProductVariantRecId;

        EcoResProductReleaseManagerBase     releaseManager;

        container productDimensions;


        select firstonly RecId from ecoResConfiguration

            where ecoResConfiguration.Name == _newProduct.DisplayProductNumber;


        if (!ecoResConfiguration.RecId)

        {

            ecoResConfiguration.Name = _newProduct.DisplayProductNumber;

            ecoResConfiguration.insert();

        }


        select firstonly RecId from ecoResProductMasterConfiguration

            where ecoResProductMasterConfiguration.ConfigProductMaster == _newProduct.RecId

                && ecoResProductMasterConfiguration.Configuration == ecoResConfiguration.RecId;


        if (!ecoResProductMasterConfiguration.RecId)

        {

            ecoResProductMasterConfiguration.ConfigProductMaster = _newProduct.RecId;

            ecoResProductMasterConfiguration.Configuration = ecoResConfiguration.RecId;

            ecoResProductMasterConfiguration.ConfigProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, ConfigId));

            ecoResProductMasterConfiguration.insert();

        }

        

        select firstonly ecoResProductMasterColorOlD

            where ecoResProductMasterColorOld.ColorProductMaster == _oldProduct.RecId;

        

        //Color assigned to product master

        ecoResProductMasterColor.clear();

        ecoResProductMasterColor.initValue();

        ecoResProductMasterColor.Color = ecoResProductMasterColorOld.Color;

        ecoResProductMasterColor.ColorProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventColorId));

        ecoResProductMasterColor.ColorProductMaster = _newProduct.RecId;

        ecoResProductMasterColor.insert();


        select firstonly ecoResProductMasterStyleOld

            where ecoResProductMasterStyleOld.StyleProductMaster == _oldProduct.RecId;


        //Style assigned to product master

        ecoResProductMasterStyle.clear();

        ecoResProductMasterStyle.initValue();

        ecoResProductMasterStyle.Style = ecoResProductMasterStyleOld.Style;

        ecoResProductMasterStyle.StyleProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventStyleId));

        ecoResProductMasterStyle.StyleProductMaster = _newProduct.RecId;

        ecoResProductMasterStyle.insert();


        select firstonly ecoResProductMasterSizeOld

            where ecoResProductMasterSizeOld.SizeProductMaster == _oldProduct.RecId;


        //Size assigned to product master

        ecoResProductMasterSize.clear();

        ecoResProductMasterSize.initValue();

        ecoResProductMasterSize.Size = ecoResProductMasterSizeOld.Size;

        ecoResProductMasterSize.SizeProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, InventSizeId));

        ecoResProductMasterSize.SizeProductMaster = _newProduct.RecId;

        ecoResProductMasterSize.insert();


        EcoResDistinctProduct ecoResDistinctProduct;


        select firstonly ecoResDistinctProduct

            where ecoResDistinctProduct.RecId == _oldProduct.RecId;


        productDimensions = EcoResProductVariantDimValue::getDimensionValuesContainerForConfiguration(ecoResConfiguration.Name);


        //Product variant

        ecoResDistinctProductVariant.clear();

        ecoResDistinctProductVariant.initValue();

        ecoResDistinctProductVariant.DisplayProductNumber = EcoResProductNumberBuilderVariant::buildFromProductNumberAndDimensions(

                                                            _newProduct.productNumber(),

                                                            productDimensions);

        

        ecoResDistinctProductVariant.ProductType    = _newProduct.ProductType;

        ecoResDistinctProductVariant.ProductMaster  = _newProduct.RecId; 


        //Product variant configuration

        ecoResProductVariantConfiguration.clear();

        ecoResProductVariantConfiguration.initValue();

        ecoResProductVariantConfiguration.initFromDistinctProductVariant(ecoResDistinctProductVariant);

        ecoResProductVariantConfiguration.ProductDimensionAttribute = EcoResProductDimensionAttribute::inventDimFieldId2DimensionAttributeRecId(fieldNum(InventDim, ConfigId));

        ecoResProductVariantConfiguration.Configuration = ecoResConfiguration.RecId;

        

        ecoResDistinctProductVariantRecId = EcoResProductVariantManager::createProductVariant(_newProduct.RecId, ecoResDistinctProductVariant.DisplayProductNumber, productDimensions);


        //Find newly created Product Variant

        ecoResDistinctProductVariant = ecoResDistinctProductVariant::find(ecoResDistinctProductVariantRecId);


        //Now release the Product variant

        releaseManager = EcoResProductReleaseManagerBase::newFromProduct(ecoResDistinctProductVariant);

        releaseManager.release();


        return ecoResDistinctProductVariant;

    }


    /// <summary>

    /// Copy or update translation

    /// </summary>

    /// <param name = "_ecoResProdcutSource">Source product</param>

    /// <param name = "_ecoResProdcutDestination">Destination product</param>

    /// <param name = "_productName">Product name</param>

    /// <param name = "_productDesciption">Product description</param>

    public void createOrUpdateTranslation(EcoResProduct         _ecoResProdcutSource, 

                                            EcoResProduct       _ecoResProdcutDestination,

                                            EcoResProductName   _productName,

                                            EcoResDescription   _productDesciption)

    {

        //Create one or more translations

        EcoResProductTranslation::createOrUpdateTranslation(_ecoResProdcutDestination.RecId, _productName, _productDesciption);


        EcoResProductRecId          newproductRecId = _ecoResProdcutDestination.RecId;

        EcoResProductTranslation    ecoResProductTranslation, ecoResProductTranslationOld;

        LanguageId                  systemLanguageId = SystemParameters::getSystemLanguageId();

       

        insert_recordset ecoResProductTranslation(Description,LanguageId ,Name ,Product)

            select Description,LanguageId ,Name , newproductRecId from ecoResProductTranslationOld

                where ecoResProductTranslationOld.LanguageId != systemLanguageId

                    && ecoResProductTranslationOld.Product == _ecoResProdcutSource.RecId;

    }


    /// <summary>

    /// Release the new product in current company

    /// </summary>

    /// <param name = "_ecoResProdcut">new Ecoresporduct buffer</param>

    public void releaseProduct(EcoResProduct _ecoResProdcut)

    {

        EcoResProductReleaseSessionManager          productReleaseSessionManager;

        EcoResReleaseSessionRecId                   releaseSessionRecId;

        Args                                        args;

        CompanyInfo                                 companyInfo = CompanyInfo::find();


        // Release the master product for the current company

        productReleaseSessionManager    = EcoResProductReleaseSessionManager::newReleaseSession();

        releaseSessionRecId             = productReleaseSessionManager.parmReleaseSessionRecId();


        productReleaseSessionManager.addProduct(_ecoResProdcut.RecId);

        productReleaseSessionManager.addLegalEntityForProduct(companyInfo.RecId, _ecoResProdcut.RecId);


        args = new Args(formStr(EcoResProductRelease));

        args.record(EcoResReleaseSession::find(releaseSessionRecId));


        // the first boolean parameter is for showing a log for errors

        // the second boolean parameter is for executing the release with a batch

        if (EcoResProductReleaseSessionBatch::runJob(args, true, false))

        {

            productReleaseSessionManager.cleanUp();

        }

    }


/// <summary>

    /// Create retail kit

    /// </summary>

    /// <param name = "_origProduct">Origin item number</param>

    /// <param name = "_newProduct">New item number</param>

    /// <param name = "_ecoResDistinctProductVariant">Product variant</param>

    public void createRetailKit(EcoResProduct _origProduct, EcoResProduct _newProduct, EcoResDistinctProductVariant _ecoResDistinctProductVariant)

    {

        RetailKit                       retailKit, retailKitOld;

        RetailKitComponent              retailKitComponent, retailKitComponentOrig;

        RetailKitVariantComponent       retailKitVariantComponent, retailKitVariantComponentOld;

        EcoResDistinctProductRecId      newKitVariant;


        newKitVariant = _newProduct.RecId;   

        

        select firstonly retailKitOld

                    where retailKitOld.ProductMaster == _origProduct.RecId;


        if (retailKitOld)

        {

            retailKit.data(retailKitOld);

            retailKit.ProductMaster = _newProduct.RecId;

            retailKit.insert();


            if (retailKit)

            {

                while select retailKitComponentOrig

                    join retailKitVariantComponentOld

                        where retailKitComponentOrig.Kit == retailKitOld.RecId

                        && retailKitVariantComponentOld.ComponentRecId == retailKitComponentOrig.RecId

                {       

                    buf2Buf(retailKitComponentOrig, retailKitComponent);

                    retailKitComponent.Kit = retailKit.RecId;

                    retailKitComponent.insert();


                    if (retailKitComponent)

                    {

                        buf2Buf(retailKitVariantComponentOld, retailKitVariantComponent);

                        retailKitVariantComponent.ComponentRecId = retailKitComponent.RecId;

                        retailKitVariantComponent.KitVariant = _ecoResDistinctProductVariant.RecId;

                        retailKitVariantComponent.insert();

                    }

                }

            }

        }


    }

}

Wednesday, 10 June 2020

Convert to Upper case using X++ in D365 AX

the following function is used to convert the string to upper case.

str myString = xyz1234;


myString  = strUpr(myString );

o/p: XYZ1234.

Monday, 30 July 2018

Tips to solve the AIF time out issues.

When integrating with other environments using AX 2012 we may get Time out issue for long running select queries or long running objects. these kind of issues or very common in Integrations. To solve these issues we can follow different approaches. the approaches are mentioned bellow.

  1. Changing the Binding Time out values
  2. Passing the data through the staging tables.
  3. Splitting the data into the multiple small scenario.
 Changing the Binding Time out values:


The main approach is to change the Send Time out (or any time out in binding that causing the issue) in Binding.This can be accomplishes in the web config for AX 2012. This is can be accomplished by opening the inbound port configuration file. go to System administrator > Setup > Service and Application Integration Framework > Inbound Ports, disable the port you want to configure and click the Configure button. The binding configuration (Web.Config) will open in the WCF Client or in a normal Notepad. 
The view of the client will be similar to this
The configuration window will be like this if you open it in WCF client.

the time out can be modified here by selecting the binding on the left side pan and then select the Parameter for which you want to increase the time out. let's say Send Time out the text box has values 00:10:00 it follows the hours:Minutes:seconds pattern. if you want to increase the time out to 30 min then you have to apply the value 00:30:00 as shown bellow

 This is one way and you can change the AX Client config file also. the client config file can be Located in the drive where it is loadee--> Drive:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin directory,  fiel name Ax32.exe.config XML Config file.
The file can be opened in Note pad or NotePad++ there you can fine the Bindings and then edit them. 

Using Client configuration window:

The client configurations can also be set in the Microsoft Dynamics Ax Configurations. This is the AX tool will help to configure the client. this can be opened from Windows start menu. once the form is opened we need to select the Connection tab and then select he particular configuration and click on configure Services. Then it will open a window there we can edited all the Binding configuration time Outs.
the view will be like this.

we have to select the bindings


and then we have to select he AIF related bindings. there you can set the timeout what you want. to be assure change the Query service binding and GenericDocumentService Binding also.

Passing the data through the staging tables:

If you are fetching the data from different tables by using the Joins some classes or peace of code will take more than 10 min. in this case you could use a staging table to load the data. And my suggestion is create a staging table all fields as string type. when loading the data only convert the values into the strings it will help you when you retrieving the data from the staging table to AIF service.
The staging table will take less than 10 min based on the number of records in that table. if you still face the same time issue then clear the cache on the process, Usage data, Caches. This method will be very useful when you are dealing with a large amount of data, in my case i had 1 Lakh records and with 64 columns in that and sent in XML format.
Splitting the data into the multiple small scenario:

If all the above process are failed then you have to split the data into multiple sets and then you have to return them. this could be more  complex design compared with the above solutions. you have to call the different services for different data, or else you have to create  conditional XML generation for certain number of records and then you have to call the remaining this could be a complex design.

After all loading the data into the Staging would be the better solution.


Tuesday, 13 March 2018

How to export Data into the CSV File with Cross Company

In this post we will go through the exporting the data into the CSV file using X++.

For this you can use a class or Job,

public static void main(Args _args)
{
   // take the commaio class used for CSV formate
    Commaio                     file;
    container                   line,companies; // to store the data need to exported and company information
    InventTable                 inventTable;
    ItemGroupId                 itemGroupId;
    Name                        itemGroupName;
    ItemName                    itemName;
    InventModelGroupItem        invModGrp;
    str                         invmodeGroupId,filename,strdatetime;
    date                        currentDate = today();

    str                         product_class,product_class_desc,master_product,master_product_desc,product_name;
    str                         product_name_desc,product_desc,product_id,search_name,hazard,pricing_strategy,packaging_group;
    str                         weight,net_weight,purchase_stopped,sales_stopped,inventory_stopped,rckpit,item_model_number;

    int                         row; // for how many records exported
    #File
    ;
    strdatetime = date2Str(currentDate,321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2,DateSeparator::Hyphen,DateYear::Digits4); //  for current date
    filename = "G:\\PRODUCT_CSV_"+ strdatetime +".csv"; // file name
    file = new Commaio(filename , #io_write); // file permissions
    //file.outFieldDelimiter(';'); //delimeter
    if( !file || file.status() != IO_Status::Ok) // checking the file
    {
        throw error("File Cannot be opened");
    }
    companies = ["230","320"];
    while select crossCompany:companies * from inventTable
    {
        invModGrp = InventModelGroupItem::findByItemIdLegalEntity(inventTable.ItemId,                          inventTable.dataAreaId,false);
        invmodeGroupId = invModGrp.ModelGroupId;
            if((invmodeGroupId == "FIN") || (invmodeGroupId == "RAW"))
            {
                product_class = (inventTable.itemGroupId()?inventTable.itemGroup().ItemGroupId:'');
                product_class_desc = (inventTable.itemGroupId()?inventTable.itemGroup().Name:'')?                          (inventTable.itemGroupId()?inventTable.itemGroup().Name:''):'NA';
                master_product = 'MP-'+inventTable.RES_MasterProduct;
                master_product_desc = inventTable.RES_MasterProduct;
                itemName = inventTable.itemName();
                line = [product_class,product_class_desc,master_product,master_product_desc];
                file.writeExp(line);
                row++;
            }
    }
    info(strFmt("Completed, total number of rows exported:  %1",row));
}

Monday, 12 March 2018

How to Give The FIle IO Permissions in AX 2012

Some Times we need to give the File IO Permissions to Read or Write the File.
These situations can be occur when we are running a file in Client and that need server permissions.
the following code will help you to do that.

public static void main(Args _args)
{

    Set permissionSet;
    WinAPIServer winAPIServer;
    str fileName;
    int size;
    RES_PROS_BatchJobProductExcelExport bjex;
    str                         strdatetime;
    date                        currentDate;
    ;

    currentDate = today();
    strdatetime = date2Str(currentDate,321,DateDay::Digits2,DateSeparator::Hyphen,DateMonth::Digits2,DateSeparator::Hyphen,DateYear::Digits4);
    fileName = "C:\\filenPath.xlsx";

    permissionSet =  new Set(Types::Class);
    //get file write permission for createFile
    permissionSet.add(new FileIoPermission(fileName,'w'));
    //get file read/write permission for getFileSize and closeHandle
    permissionSet.add(new FileIoPermission('','rw'));
    CodeAccessPermission::assertMultiple(permissionSet);

        //invoke protected APIs
    WinAPIServer::createFile(fileName);
    size = WinAPIServer::FileSize(fileName);

    bjex = new RES_PROS_BatchJobProductExcelExport();
    bjex.run();

}

the above code can help you.

Tuesday, 6 March 2018

How to create a Batch Job to export Data to XML Using Class and job.

The Batch Job can be created in Different manners. I am explaining one way for it.
Steps:
1) Create a class for the logic what you want you want to do.
2) Add this class with the Batch Job.
3) run the Batch Job.

Note: If you want to run the batch job in the client mode to one more step needed.
4) run the batch job in client mode.

Step:1


I am creating a simple class for export data into XML.
go to classes node in the AOT. create a New Class name it. Open Class Declaration
and extend it to the  RunBaseBatch class.

class Batch4Demo extends RunBaseBatch
{}

after this override the run method of the class. Right click on the class in the AOT go to Override and select run method. in this run methode write your own logic like as shown bellow.
public void run()
{
    XmlDocument doc;
    XmlElement nodeXml;
    XmlElement nodeTable;
    XmlElement nodeAccount;
    XmlElement nodeName;
    CustTable   custTable;
    #define.filename(@'C:\\Users\nagan020\Desktop\productsXML.xml')
    ;
    doc = XmlDocument::newBlank();
    nodeXml = doc.createElement('xml');

    doc.appendChild(nodeXml);
     //Determines the runtime
    if (xSession::isCLRSession())
    {
        info('Running in a CLR session.');
    }
    else
    {
        info('Running in an interpreter session.');

        //Determines the tier
        if (isRunningOnServer())
        {
            info('Running on the AOS.');
        }
        else
        {
            info('Running on the Client.');
        }
    }

    while select custTable
    {
        nodeTable = doc.createElement(tablestr(CustTable));
        nodeTable.setAttribute(fieldstr(CustTable, RecId),int2str(custTable.RecId));
        nodeXml.appendChild(nodeTable);
        nodeAccount = doc.createElement(fieldstr(CustTable, AccountNum));
        nodeAccount.appendChild(doc.createTextNode(custTable.AccountNum));
        nodeTable.appendChild(nodeAccount);
        nodeName = doc.createElement(fieldstr(CustTable,CustGroup));
        nodeName.appendChild(doc.createTextNode(custTable.CustGroup));
        nodeTable.appendChild(nodeName);
      }
    doc.save(#filename);
    info(strFmt("File %1 created.", #filename));
}

after this override pack and unpack methods.
public container pack()
    {
        return conNull();
    }
public boolean unpack(container packedClass)
    {
        return true;
    }
now create a main method foe the class and call the run method in that 
(this is very important with out main you cant run the class) 
right click and add new method write following code.
public static void main(Args _args)
{
    Batch4Demo  b = new Batch4Demo ();
   b.run();
 }

Step:2

Create a Job in the Job Node of AOT write the following code in it.
static void Job_ScheduleBatch2(Args _args)
{
    BatchHeader batHeader;
    BatchInfo batInfo;
    RunBaseBatch rbbTask;
    str sParmCaption = "My Demonstration (b351)";
    ;
    rbbTask = new Batch4Dem0();
    batInfo = rbbTask .batchInfo();
    batInfo .parmCaption(sParmCaption);
    batInfo .parmGroupId(""); // The "Empty batch group".
    batHeader = BatchHeader ::construct();
    batHeader .addTask(rbbTask);
    batHeader .save();
    info(strFmt("'%1' batch has been scheduled.", sParmCaption));
}

Step:3

Now Compile the Job And Class. run the Batch Job by pressing F5.
Before running Generate the IL code. Go to Build and click on Generate Incremental CIL..
It will create a Batch job in the Batch Jobs Form you can view it by going into the 
following path
System Administration --> Inquiries --> BatchJobs --> Batch Jobs.
You should see the status as waiting---> Executing --> Ended in the status column
of the Batch Jobs form.
Now the above batch job will run only on the server.
If you want to make it run on the Client. follow bellow steps.

Step:4

Override the method  runsImpersonated. Right click on the Batch4Demo class and override the above method write the following code in it. 
public boolean runsImpersonated()
{
    // false means that the batch must run on a client.
    return false;
}
Now run the class as mentioned above.
After running it we have to add it to the client section to do this.
Go to Organization administration --> Basic Or Periodic --> Batch Processing.
open the form and you can see batch group and private check box option.
in the group option select empty group( Because in the above code we have selected empty in the batch group). uncheck the private. now click ok. the batch job will run.

Happy Daxing.......

Monday, 5 March 2018

How to Export Data into the XML using X++ in AX 2012.

To Export the data into the XML file using X++ use the bellow code.

public void xmlGeneration(Args _args)
{
    XmlDocument doc;
    XmlElement nodeXml;
    XmlElement nodeTable;
    XmlElement nodeAccount;
    XmlElement nodeName;
    CustTable   custTable;
    #define.filename(@'C:\\Users\nagan020\Desktop\productsXML.xml')
    ;
    doc = XmlDocument::newBlank();
    nodeXml = doc.createElement('xml');

    doc.appendChild(nodeXml);
     //Determines the runtime
    if (xSession::isCLRSession())
    {
        info('Running in a CLR session.');
    }
    else
    {
        info('Running in an interpreter session.');

        //Determines the tier
        if (isRunningOnServer())
        {
            info('Running on the AOS.');
        }
        else
        {
            info('Running on the Client.');
        }
    }

    while select custTable
    {
        nodeTable = doc.createElement(tablestr(CustTable));
        nodeTable.setAttribute(fieldstr(CustTable, RecId),int2str(custTable.RecId));
        nodeXml.appendChild(nodeTable);
        nodeAccount = doc.createElement(fieldstr(CustTable, AccountNum));
        nodeAccount.appendChild(doc.createTextNode(custTable.AccountNum));
        nodeTable.appendChild(nodeAccount);
        nodeName = doc.createElement(fieldstr(CustTable,CustGroup));
        nodeName.appendChild(doc.createTextNode(custTable.CustGroup));
        nodeTable.appendChild(nodeName);
      }
    doc.save(#filename);
    info(strFmt("File %1 created.", #filename));
}

Hope this will help...
Happy Daxing...