Monday, 28 September 2020

Create a custom web service in D365FO

Hi Folks,

I am writing this blog to create custom web services in D365 FO. It is same like previous version 2012. All you need to do is to create a class and services. Follow the below process to create a custom web service.

Step 1 // Create a contract class for parameters

[DataContractAttribute('GSCustContract')]

class GSCustContract

{

    AccountNum   custNum;

    [DataMemberAttribute('custNum')]

    public AccountNum parmCustNum(AccountNum   _custNum = custNum)

    {

        custNum  = _custNum;        

        return custNum;

    }

    [DataMemberAttribute('AmountPayable')]

    public str parmAmountPayable(str _amountPayable = amountPayable)

    {

        amountPayable  = _amountPayable;        

        return amountPayable;

    }

    [DataMemberAttribute('LastMonthPaid')]

    public str parmLastMonthPaid(str _lastMonthPaid = lastMonthPaid)

    {

        lastMonthPaid  = _lastMonthPaid;        

        return lastMonthPaid;

    }

}

Step 2:

// Create a service  class for business logic

class GSCustServiceClass

{

[AifCollectionTypeAttribute('return', Types::Class, classStr(GSCustContract)), SysEntryPointAttribute(true)]

    public List customerInfo(CustNo _custNo, DataAreaId _dataAreaId)

    {

        List                                result;

        GSCustContract           contract;

        CustTable                           custTable;

        AmountMST getBalance()

        {

            CustTransOpen           custTrans;            

            select sum(AmountMST) from custTrans

                where custTrans.AccountNum      == custTable.AccountNum;

            if (custTrans.AmountMST < 0)

            {

                return 0;

            }

            else

            {

                return abs(custTrans.AmountMST);

            }

        }

        str getLastPaymMonth()

        {

            CustTransOpen           custTrans;            

            select firstonly AccountNum, TCMBillingType, TransDate from custTrans

                where custTrans.AccountNum      == custTable.AccountNum;            

            return subStr(date2Str(custTrans.TransDate, 123, 2, 0, 2, 0, 2), 3, 6);

        }

        

        changecompany(_dataAreaId)

        {

            result                  = new List(Types::Class);

            custTable               = CustTable::find(_custNo);

            contract  = new GSCustContract();

            contract.parmCustNum(_custNo);

            contract.parmAmountPayable(strReplace(num2Str(getBalance()*100, 10, 0, 0,0), " ", "0"));

                contract.parmLastMonthPaid(getLastPaymMonth());

            }

            result.addEnd(contract);

        }

        return result;

    }

Step 3: Now you need to create a element of service type

go to properties and select the service class which we have created in the above step.
Right click the service operations node and click on new service operations button, go to properties of the service operation node and select the method name.

Step 4: Create a service group element.
add a service to the group and select the service name (created in step 3) in the property of the service node.
Step 5: Build your project

Now your web service is ready to use. use below urls for respective services
<D365FO URL>/api/services/<Service group name>/<Service Name>/<Service operation name>
<D365FO URL>/soap/services/<Service group name>?wsdl

How to schedule a batch job of a class with parameter from X++

 Hi Folks,

sometime we received  a requirement to schedule a batch from x++ code runtime. This kind of requirement comes when there is performance issue while running the same class from previous execution.

For example, we need to write a code to update some data while posting a journal. We want journal posting logic to schedule a batch job for update. In this way journal posting will happen separately and it will schedule a batch job which will do the update and execute other business logic from batch service.

Let say I have a service class which accept a contract class parameter.

// service class

class GSPaymentSettlementService extends SysOperationServiceBase

{

    [SysEntryPoint]

    public void paymentSettlement(GSPaymentSettlementContract     _contract)

    {

        // Your business logic 

        }

}


// contract class

[DataContract]

class GSPaymentSettlementContract

{

    Id       id;

    [DataMember, SysOperationControlVisibility(false)]

    public Id parmId(Id _id = id)

    {

        id = _id;

        return id;

    }

}


Now you want to write a logic to schedule a batch job to call the service class and pass the parameter.

you can write below code to achieve this.


            BatchHeader                         batchHeader;

            SysOperationServiceController       controller;

            GSPaymentSettlementContract     dataContract;

            str                                 captiontext;

            

            captiontext = "Procee the bi for " + <passing value>;

            batchHeader = BatchHeader::construct();

            batchHeader.parmCaption(captiontext);


            //create instances of the classes to use as batch tasks

            controller = new SysOperationServiceController( classStr(GSPaymentSettlementService),

                                                            methodStr(GSPaymentSettlementService, paymentSettlement),

                                                            SysOperationExecutionMode::Synchronous);


            controller.parmLoadFromSysLastValue(false);

            dataContract = controller.getDataContractObject('_contract');

            dataContract.parmId(<passing value>);

            batchHeader.addTask(controller);

            batchHeader.save();


// try this it comment me if it provide you a solution.

Friday, 18 September 2020

Find tax value from tax item code and tax group code

//You have to pass these values to the functions whether it comes from PurchLine or SalesLine or any other table.

//Store the result in variable

Tax::calcTaxAmount(purchLine.TaxGroup, purchLine.TaxItemGroup, Systemdateget(), purchLine.CurrencyCode, purchLine.LineAmount, TaxModuleType::Purch);

You have to pass these values to the functions, whether they come from SalesLine or PurchLine 

AX basic functions

 

1. Month Start Date : 
 
TransDate dateInMonth=today();  
         TransDate firstDateOfMonth;  
         firstDateOfMonth = DateStartMth(dateInMonth); 
2. Month End Date :

TransDate dateInMonth=today();  
         TransDate endDateOfMonth;  
         endDateOfMonth= endmth(dateInMonth);

3. Declare a constant :
#Define.MonthName("May")
 Const str monthName = "May";

4. Next month of date:
nextMth(date)
5. Date2Str function
        str        dateStr           = date2Str(this.DueMonthDate,           123, DateDay::Digits2,                                                        DateSeparator::Slash, DateMonth::Digits2,                                                                                   DateSeparator::Slash, DateYear::Digits4);
6. Num2Str function
1.should pass 4 parameters ex:
a = num2str(x,1,2,1,0);
rules:
1st place:1–>shows no effect(minimum no of characters to print)
2nd place:2–>ofter decimal /comma how many characters has to print
3rd place:1–>shows to select either comma or decimal
ex: 1 for point
2 for comma
0 for none


How to sort file data before inserting to target table in DMF in D365 FO

Problem: Many a times we receive requirements where we need to upload a file using DMF with a different order sequence. For example a file has data as below:


client wants that this file should get import with ID column in ascending /descending order.

Solution: To achieve this need to customize data entity as below:

1. Add a field integer field "ImportSequence" to staging table (GSCashStaging table).

2. Add below methods to staging table:

public static container orderByFieldListForImportExport(DMFOperationType _operationType = DMFOperationType::All)

{ container fieldList = conNull();
switch (_operationType)
    {
case DMFOperationType::Import, DMFOperationType::Export:
  fieldList += fieldStr(GSCashStaging, ImportSequence);
     break;

default:
    fieldList += fieldStr(Common, RecId);
    break;
    }

return [fieldList, sortOrder];

 

public static void resolveImportSequence(DMFDefinitionGroupExecution _dmfDefinitionGroup)
{
    GSCashStaging    staging;
    int   importSequence;

    ttsbegin;

    while select forupdate staging
order by staging.ID
  where staging.DefinitionGroup ==_dmfDefinitionGroup.DefinitionGroup     && stagingTable.ExecutionId == _dmfDefinitionGroup.ExecutionId      
  && stagingTable.TransferStatus == DMFTransferStatus::NotStarted                
{
    importSequence++;
    stagingTable.ImportSequence =importSequence;
}
       
    ttscommit;
3. Add below method to data entity
public static void postGetStagingData(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution)
{
GSCashStaging::resolveImportSequence(_dmfDefinitionGroupExecution);
}

4. Rebuild your project and sync it. It will solve the issue.


How to run D365 FO runnable classes from web browser

You can execute the runnable classes from web browser instead of running it from using visual studio. You need to copy the below url and replace it with your D365Fo url, company it and runnable class name.
https://<D365URL>/?cmp=<YourCompanyName>&mi=SysClassRunner&cls=<YourRunnableClassName>

Simillarly you can do more thing like as below:

Open the table/view as well from web browser with below url:
https://<D365URL>/?mi=SysTableBrowser&tableName=<YourTableOrViewName>&cmp=<YourCompanyName>

Run a SSRS report:
https://<D365URL>/?cmp=<YourCompanyName>&mi=Output%3A<YourReportMenuItemName>

Open an Form:
https://<D365URL>/?cmp=<YourCompanyName>&mi=Display%3A<YourFormMenuItemName>

D365FO Entity insert/update issue Update not allowed for field ‘Entity.FieldName’.

Step 1: Make sure fields properties allow edit is yes in Data entity level(In Table level Allow edit is No). Change to Yes in entity fields ...