Wednesday, 28 August 2019

Something went wrong while generating the report Please try again in D365F&O SSRS reports

I was getting the below error while trying to run some SSRS report.

Something went wrong while generating the report Please try again

Reason: Usually we get this error when the parameters are not properly loaded/refreshed when you run the report.

Solution: 

Check out your SSRS report parameters and whether it has been re-added when you restore DataSet  after modifcations in DP Class.
In my case I removed the parameters and re added the data set and restored the data set to readd the parameters to the report.

don't forget to restart the SSRS service.

If you still see the error,  it must be the time out of the report. Optimize the DP and query of the report.


@Rahul

Tuesday, 27 August 2019

Get customer multiple contact details in dynamics 365 F&O X++

In this example I will be showing you how to get a customer contact details  like phone num, email, fax and URL's.

Here, I'm inserting the data in my contract class to use in my API classes.  Pleases change it according to your requirement.


dirPartyLocation.clear();
dirParty = DirPartyTable::findRec(custTable.Party);
        while select dirPartyLocation where dirPartyLocation.Party == dirParty.RecId
            join logisticsElectronicAddress
            where logisticsElectronicAddress.Location == dirPartyLocation.Location
        {
            ContactContract = new ContactContract();
            LogisticsElectronicAddressMethodType logisticsElectronicAddressMethodType  = logisticsElectronicAddress.Type;
            
            logisticsLocation.clear();
            logisticsLocation = LogisticsLocation::find(dirPartyLocation.Location);
            ContactContract.parmDescription(logisticsLocation.Description);
            ContactContract.parmIsPrimary(logisticsElectronicAddress.IsPrimary);
            ContactContract.parmLocator(logisticsElectronicAddress.Locator);
            ContactContract.parmType(enum2Str(LogisticsElectronicAddressMethodType));

            LogisticsElectronicAddressRole logisticsElectronicAddressRole;
            select * from logisticsElectronicAddressRole where logisticsElectronicAddressRole.ElectronicAddress == logisticsElectronicAddress.RecId;
            logisticsLocationRole = LogisticsLocationRole::findRec(logisticsElectronicAddressRole.LocationRole);
            if(logisticsElectronicAddressRole)
            {
                ContactContract.parmPurpose(enum2Str(logisticsLocationRole.Type));// Type Invoice, business, home etc

            }

Get Sales Order Address in dynamics 365 F&O X++

In this example I will be showing you how to get a sales order delivery address using below code.

Here, I'm inserting the data in my contract class to use in my API classes.  Pleases change it according to your requirement.

        logisticsPostalAddress = LogisticsPostalAddress::findRecId(salesTable.DELIVERYPOSTALADDRESS);
        if(logisticsPostalAddress)
        {
            select RecId from logisticsLocation index hint
                LogisticsLocationIdx where logisticsLocation.RecId ==  logisticsPostalAddress.Location;

            select RecId from dirPartyLocation where dirPartyLocation.Location == logisticsLocation.RecId;
            
            SalesAddressContract = new SalesAddressContract();
            SalesAddressContract.parmAddressDescription(logisticsLocation.Description);
            SalesAddressContract.parmDeliveryAddressName(DIRPARTYTABLE::findRec(dirPartyLocation.Party).Name);
            SalesAddressContract.parmAddressStreet(logisticsPostalAddress.Street);
            SalesAddressContract.parmAddressCity(logisticsPostalAddress.City);
            SalesAddressContract.parmAddressState(logisticsPostalAddress.State);
            SalesAddressContract.parmAddressCountryRegionId(logisticsPostalAddress.CountryRegionId);
            SalesAddressContract.parmAddressZipCode(logisticsPostalAddress.ZipCode);
            SalesAddressContract.parmAddressCountryRegionId(logisticsPostalAddress.CountryRegionId);
            SalesAddressContract.parmsunTAFMarkForExtAddressCode(logisticsLocation.ExtAddressCode);// Custom field

            addressList.addEnd(SalesAddressContract);

        }

@Rahul

Get customer multiple addresses in dynamics 365 F&O X++

In this example I will be showing you how to get a customer multiple addresses like delivery, invoices, business etc using the below code.

Here, I'm inserting the data in my contract class to use in my API classes.  Pleases change it according to your requirement.


        dirParty = DirPartyTable::findRec(custTable.Party);
        while select  * from logisticsPostalAddress
        exists join * from dirPartyLocation
        where logisticsPostalAddress.Location == dirPartyLocation.Location
            && dirParty.RecId==dirPartyLocation.Party
            && dirPartyLocation.IsPostalAddress == NoYes::Yes

        {
            LogisticsLocationRoleType   logisticsLocationRoleType;
         

            select RecId from logisticsLocation index hint
                LogisticsLocationIdx where logisticsLocation.RecId ==  logisticsPostalAddress.Location;

            dirPartyLocation = DirPartyLocation::findByPartyLocation(dirParty.RecId, logisticsLocation.RecId);

            select * from dirPartyLocationRole where dirPartyLocationRole.PartyLocation == dirPartyLocation.RecId;
         
            select * from logisticsLocationRole  where logisticsLocationRole.RecId == dirPartyLocationRole.LocationRole;

            logisticsLocationRoleType = logisticsLocationRole.Type;
            AddressContract.parmAddressCity(logisticsPostalAddress.City);
            AddressContract.parmAddressCountryRegionId(logisticsPostalAddress.CountryRegionId);
            AddressContract.parmAddressDescription(logisticsLocation.Description);
            AddressContract.parmAddressState(logisticsPostalAddress.State);
            AddressContract.parmAddressStreet(logisticsPostalAddress.Street);
            AddressContract.parmAddressType(enum2Str(logisticsLocationRoleType));
            AddressContract.parmAddressZipCode(logisticsPostalAddress.ZipCode);
            AddressContract.parmIsPrimary(dirPartyLocation.IsPrimary);
            AddressContract.parmPurpose();
            addressList.addEnd(AddressContract);
        }

Solution 2

static void RetrieveCustomerAddressBasedOnRole(Args _args)
{
    CustTable               custTable;
    DirPartyTable           dirPartyTable;
    DirPartyLocation        dirPartyLocation;
    DirPartyLocationRole    dirPartyLocationRole;
    LogisticsLocation       logisticsLocation;
    LogisticsLocationRole   logisticsLocationRole;
    LogisticsPostalAddress  logisticsPostalAddress;
   
   
    while select custTable
            where   custTable.AccountNum == /* YOUR ACCOUNT */
        join dirPartyTable
                where   dirPartyTable.RecId == custTable.Party
        join dirPartyLocation
                where   dirPartyLocation.Party == custTable.Party
            join dirPartyLocationRole
                    where   dirPartyLocationRole.PartyLocation == dirPartyLocation.RecId
                join logisticsLocationRole
                        where   logisticsLocationRole.RecId == dirPartyLocationRole.LocationRole
                        &&      logisticsLocationRole.Type == /* YOUR ROLE - LogisticsLocationRoleType::Delivery*/   
            join logisticsLocation
                    where   logisticsLocation.RecId == dirPartyLocation.Location
                join logisticsPostalAddress
                        where   logisticsPostalAddress.Location == logisticsLocation.RecId
    {
        info(strFmt("%1", logisticsPostalAddress.Address));           
    }

}  

Data entity methods execution sequence in Dynamics 365 F&O X++

Here is a sequence of method’s calls during export:

1. initValue
2. validateField
3. validateWrite
4. update
4.1. doUpdate
4.1.1. persistEntity
4.1.1.1. doPersistEntity
4.1.1.1.1. initializeDataSources
4.1.1.1.1.1. initializeEntityDataSource
Note: initializeDataSource is called once for each DataSource in Entity.
4.1.1.1.2. mapEntityToDataSources
Note: initializeDataSource is called once for each DataSource in Entity.
4.1.1.1.3. saveDataSources
4.1.1.1.3.1. updateEntityDataSource
4.1.1.1.4. mapEntityToDataSource (maybe for another record)
4.1.1.1.5. saveDataSources
4.1.1.1.5.1. updateEntityDataSource for update operation and (insertEntityDataSource for insert)
4.1.1.1.5.1.1. mapDataSourceToEntity
4.1.1.1.5.1.2. doSaveDataSource
4.1.1.1.5.1.2.1. updateDataSource
4.1.1.1.5.1.2.1.1. preupInsertDataSource
4.1.1.1.5.1.2.1.1.1. validateWrite of table
5.0 postLoad


Here are some method’s calls during Import:


defaultCTQuery
copyCustomStagingToTarget
postGetStagingData
preTargetProcessSetBased
postTargetProcess

Update Data entity staging table data prior to insert into the target table dynamics 365 F&O X++

Sometimes we get a requirement to update the data before it gets inserted into the staging table.
Here I'm using "postGetStagingData" method to update the data before it gets inserted into the staging table.


[ExtensionOf(tableStr(DemandForecastEntity))]
final public class DemandForecastEntity_Extension
{
    public static void postGetStagingData(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
    {
        DemandForecastEntityStaging demandForecastEntityStaging ;
        InventDimCombination inventDimCombination;
        InventDim                     inventDim;

        while select forupdate demandForecastEntityStaging where demandForecastEntityStaging .DefinitionGroup == _dmfDefinitionGroupExecution.DefinitionGroup
                && demandForecastEntityStaging .ExecutionId == _dmfDefinitionGroupExecution.ExecutionId
                && demandForecastEntityStaging .TransferStatus == DMFTransferStatus::NotStarted
        {

            inventDimCombination.clear();
            inventDim.clear();

            select firstonly inventDimCombination
            where inventDimCombination.ItemId == demandForecastEntityStaging .ItemNumber
            join inventDim
            where inventDim.inventDimId == inventDimCombination.InventDimId;

            if(inventDimCombination)
            {
                ttsbegin;
                demandForecastEntityStaging .ProductConfigurationId = inventDim.configId;
                demandForecastEntityStaging .ProductColorId = inventDim.InventColorId;
                demandForecastEntityStaging .ProductSizeId = inventDim.InventSizeId;
                demandForecastEntityStaging .ProductStyleId = inventDim.InventStyleId;
                demandForecastEntityStaging .doUpdate();
                ttscommit;
            }
        }
    }

}

 In the same way you can use "PostTargetProcess" method if you want to update the data before it gets inserted into the target tables.

This method is automatically called by the DMFEntityWriter class in the end of processRecords() method when all records are transferred from staging to target. It is not available from override method drop down on Data Entity because it is static and is called via reflection.

Please note that it can be done only in data management scenarios but not via OData because OData updates\inserts records row by row and there is no post event\method to use.

/// <summary
/// Executes the logic once after processing the target data.
/// </summary>
/// <param name= “_dmfDefinitionGroupExecution">
/// The definition group that should be processed.
/// </param>
public static void postTargetProcess(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
{
    //check if import job is finished
    if (_dmfDefinitionGroupExecution.StagingStatus == DMFBatchJobStatus::Finished)
    {
        MyStaging myStaging;
 
        //select all staging records that were processed by current execution job without errors.
        while select myStaging
            where myStaging.DefinitionGroup == _dmfDefinitionGroupExecution.DefinitionGroup
               && myStaging.ExecutionId     == _dmfDefinitionGroupExecution.ExecutionId
               && myStaging.TransferStatus  == DMFTransferStatus::Completed
        {
            //here you can find newly created records and update\post them.
        }
    }
}

@Rahul 

Thursday, 22 August 2019

Get default financial dimension values through X++ code

Below is the way to get defaultdimensions of a record. In this example I'm using customer account .
In the same way you can try for other records(sales orders, purchase order etc)

Example 1
------------

        DimensionAttributeValueSetStorage           dimStorage;

// DimensionDefault is a RecId that combines all Dimension Values
            dimStorage = DimensionAttributeValueSetStorage::find(custTable.DefaultDimension);
            for (i= 1 ; i<= dimStorage.elements() ; i++)
            {
                // Change the string "CostCenter" to whatever financial dimension you want
                if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "Brand")
                {
                    info(dimStorage.getDisplayValueByIndex(i));
                }
                // Change the string "CostCenter" to whatever financial dimension you want
                if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "Channel")
                {
                    info(dimStorage.getDisplayValueByIndex(i));
                }
                // Change the string "CostCenter" to whatever financial dimension you want
                if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "Customer")
                {
                    info(dimStorage.getDisplayValueByIndex(i));
                }
                // Change the string "CostCenter" to whatever financial dimension you want
                if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name == "Department")
                {
                    info(dimStorage.getDisplayValueByIndex(i));
                }
                // Change the string "CostCenter" to whatever financial dimension you want
                if(DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name ==        "ProductCategory")
                {
                    info(dimStorage.getDisplayValueByIndex(i));
                }
            }

Example 2
--------------

ProjTable                                       ProjTable;
DimensionAttributeValueSet           DimensionAttributeValueSet;
DimensionAttributeValueSetItem    DimensionAttributeValueSetItem;
DimensionAttributeValue                DimensionAttributeValue;
DimensionAttribute                         DimensionAttribute;

while select * from ProjTable
        where ProjTable.ProjId == "10005"    //  To display value for ProjectId "10005" only
join RecId from DimensionAttributeValueSet
        where  DimensionAttributeValueSet.RecId == ProjTable.DefaultDimension
join RecId, DisplayValue from DimensionAttributeValueSetItem
        where DimensionAttributeValueSetItem.DimensionAttributeValueSet == DimensionAttributeValueSet.RecId
join RecId from DimensionAttributeValue
        where DimensionAttributeValue.RecId == DimensionAttributeValueSetItem.DimensionAttributeValue
join RecId, Name from DimensionAttribute
        where DimensionAttribute.RecId == DimensionAttributeValue.DimensionAttribute
    {
        info(DimensionAttribute.Name+"----"+ DimensionAttributeValueSetItem.DisplayValue);
    }

Run SQL directly from X++

Below is the way to run SQL query directly from AX X++.

To retrieve data:

Since this example uses a Connecion class, data is retrieved from the database where Axapta is currently connected.

void Sample_1(void)

{
      Connection Con = new Connection();
      Statement Stmt = Con.createStatement();
      ResultSet R =Stmt.executeQuery(‘SELECT VALUE FROM SQLSYSTEMVARIABLES’);

      while ( R.next() )
     {
           print R.getString(1);
      }
}

Manipulating data (deletion/updation/ selection):

void Sample_2(void)
{
     str sql;
     Connection conn;
     SqlStatementExecutePermission permission;
      ;

         sql =         "SELECT custinvoicejour.invoiceid,custinvoicejour.SALESID,custinvoicejour.DATAAREAID,custinvoicejour.INVOICEAMOUNT, CUSTTABLE.ACCOUNTNUM, " +
            "custinvoicejour.InvoiceDate,CUSTTABLE.SUNTAFFORECASTCHANNELID "+
            "FROM custinvoicejour inner join CUSTTABLE "+
    "ON custinvoicejour.INVOICEACCOUNT = CUSTTABLE.ACCOUNTNUM ";

         permission = new SqlStatementExecutePermission(sql);
         conn = new Connection();
         permission = new SqlStatementExecutePermission(sql);
          permission.assert();
        conn.createStatement().executeUpdate(sql);
       // the permissions needs to be reverted back to original condition.
       CodeAccessPermission::revertAssert();
}

@Rahul

Thursday, 15 August 2019

Unable to cast transparent proxy to type 'SoapUtility.aifServices.aifPackingSlipService'. in Dynamics 365 Finance & Operations SOAP/API JSON

I was getting the error while trying to create an endpoint to create packing slip through SOAP. I did lot of research and could not find the right solution for this issue.

After breaking my head about 1 day and then I realized that I copied the code from sales order integration and forgot to update some variable. Due to that I was getting this error.

In the below example you can see that I'm using sales order create channel for packing slip. That's not correct.


It worked after making the below change.


Adding a newline into a string in C# and X++

Below is the sample code we can use for  adding a newline after every occurrence of "@" symbol in the string in C#   using System...