Thursday, May 3, 2018

Custom service to create Sales order with lines in Dynamics 365 and testing it

As you might know, 'composite entities' are not supported in Odata and are meant only to be used in Data management.

Which means we cannot use a single service or single odata endpoint to create a SO and also that there can be only asynchronous way to leverage it.

What if we have to create a synchronous service to create Sales order in D365?
Yes, there are standard entities for Sales order header and sales order line, which can be used separately.

But in that case, it will be the responsibility of the caller to:
-Call the header service first. 
-Check if header is inserted correctly 
-Call line service.

Even with this approach there are certain limitations:
-What if any one of the sales line fails, and is not created in D365?
It has to be rolled back. Then what happens to the Header which was already created in the previous call?
A new delete request must be sent to delete the header.

If the caller of the service will not be able to do this complete roll back , during any error or if they are not fine making 3 separate calls to create SO.

We can go for custom service in such cases, as it gives these benefits:
-Roll back capability, as we can write code to handle this.
-Give a single endpoint, to the caller to consume, which means through a single endpoint the complete sales order along with lines can be created.

What are all needed for this?
Firstly creating a contract class.
One header contract class and an line contract class.
Header contract class must also accept the list of line contract object class to support 1:N scenario.

Below is an example for a simple contract classes:
Header contract class, that has two methods:
-Customer account number for which sales order has to be created.
-A method that accepts the list of sales line contract class objects.


Line contract class:
-A method for 'Item number'
-A method of the 'Qty'

Then a service class that has all the logic to accept this contract classes and create a SO in D365.

class CreateSOService extends SysOperationServiceBase
{
    public str createSO(SalesOrderHeaderContract  _contract)
    {
        str                                 result;
        SalesTable                    salesTable;
        SalesLine                      salesLine;
        SalesId                          salesId;
        NumberSeq                   numberSeq;
        ListEnumerator              salesLineListEnumerator  = _contract.parmSalesOrderLinesList().getEnumerator();
        SalesOrderLineContract   salesOrderLineContract;
            
        try
        {           
            ttsbegin;
            numberSeq = NumberSeq::newGetNumFromId(SalesParameters::numRefSalesId().NumberSequenceId);
            salesId = numberSeq.num();
            salesTable.SalesId = salesId;
            salesTable.initValue();
            salesTable.CustAccount = _contract.parmCustAccount();
            salesTable.initFromCustTable();
            salesTable.LanguageId = "en-us";

            if(salesTable.validateWrite())
            {
                salesTable.insert();
            } 
            else
            {            
                throw Exception::Error;
            } 

            while(salesLineListEnumerator.moveNext())
            {
                salesOrderLineContract = salesLineListEnumerator.current();
                if(salesOrderLineContract)
                {
                    salesLine.clear();
                    salesLine.initFromSalesTable(salesTable);
                    salesLine.ItemId = salesOrderLineContract.parmItemNumber();
                    salesLine.QtyOrdered = salesOrderLineContract.parmOrderedSalesQty();
                    salesLine.SalesQty = salesOrderLineContract.parmOrderedSalesQty();;
                    
                    if(salesLine.validateWrite())
                    {
                        salesLine.createLine(true, true, true, true, true, true);
                    }
                    else
                    {
                        throw Exception::Error;
                    }
                }
            }
            ttscommit;
            if(SalesTable::exist(salesId))
            {
                result = strfmt("Success: Sales order '%1' is successfully created", salesId);
            }
        }
        catch(Exception::CLRError)
        {
            result =  enum2Str(Exception::CLRError);
        }
        catch(Exception::Error)
        {         
            result = "Insertion failed: Data validation error";
        }
        return result;
    }

}

Now that the required objects are ready.
It can be attached to the service node and then to service group.
Post the build, the service is ready to be consumed, deployed as per below url:
https:[Your organization's root URL]/api/services/service_group_name/service_group_service_name/operation_name

Now, if it has to be tested in any of the tools, apart from writing code and consuming it in any visual studio console applications.
We can use 'Postman' here.

A post request can be created in postman to call the service:

The input can be passed, in the body section, as shown below screenshot.


Upon clicking 'Send', a Sales order along with lines will be created in D365.
The response will be shown on the postman lower body section, as below:


It is the response, which is provided in the service class code, mentioned above.
You can verify if the SO is created in D365.

10 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Hi,
    I'm having issue replicating your steps in Postman. See below my details:
    1. I'm using GET request with path /api/services///
    2. Authorization was done and appropriate valid token was used.
    3. My method in service has 2 parameters. I've provided json in Body tab as follows
    {
    "parameter1" : "parameterValue1"
    "parameter2" : "parameterValue2"
    }

    After running this request I receive below result listing only signature of my method.

    {
    "Parameters": [
    {
    "Name": "parameter1",
    "Type": "String"
    },
    {
    "Name": "parameter2",
    "Type": "DateTime"
    }
    ],
    "Return": {
    "Name": "return",
    "Type": "DocumentDataContract"
    }
    }

    Not sure what I'm doing wrong. Would be appreciated for help.
    Thanks.

    ReplyDelete
    Replies
    1. Change the Postman request type from GET to POST

      Delete
  3. Very good content. I read your blog that was awesome, please doing continue daily post.
    Microsoft Dynamics AX Online Training

    ReplyDelete
  4. Hi,
    i wanted to ask that i am trying to follow this procedure in ON-prime server.
    i am getting authentication error on Postman.
    so is this process only usable on oncloud ?

    ReplyDelete
  5. The information which you have provided in this blog is really useful to everyone. Thanks for sharing.
    D365 Finance and Operations Training
    D365 Operations Training

    ReplyDelete
  6. How Mr Benjamin Lee service grant me a loan!!!

    Hello everyone, I'm Lea Paige Matteo from Zurich Switzerland and want to use this medium to express gratitude to Mr Benjamin service for fulfilling his promise by granting me a loan, I was stuck in a financial situation and needed to refinance and pay my bills as well as start up a Business. I tried seeking for loans from various loan firms both private and corporate organisations but never succeeded and most banks declined my credit request. But as God would have it, I was introduced by a friend named Lisa Rice to this funding service and undergone the due process of obtaining a loan from the company, to my greatest surprise within 5 working days just like my friend Lisa, I was also granted a loan of $216,000.00 So my advise to everyone who desires a loan, "if you must contact any firm with reference to securing a loan online with low interest rate of 1.9% rate and better repayment plans/schedule, please contact this funding service. Besides, he doesn't know that am doing this but due to the joy in me, I'm so happy and wish to let people know more about this great company whom truly give out loans, it is my prayer that GOD should bless them more as they put smiles on peoples faces. You can contact them via email on { 247officedept@gmail.com} or Text through Whatsapp +1-989 394 3740.

    ReplyDelete
  7. Wow...Nice blog shared with us. Print Custom Sale Sheet From PrintMagic as a way to introduce your products and services to prospects and clients the right way. They are an interactive and informative way of getting in touch with clients and business partners and conveying all the pertinent information they need to know to purchase from you. Whether it is a new product you want to introduce, a popular service you are revamping, or simply want to highlight the many successful features of your business, Print Custom Sale Sheet Printing From PrintMagic is an amazing choice to do so!

    ReplyDelete
  8. This blog provides valuable insights into Dynamics 365 Finance and Operations in the UAE. The platform's advanced financial and operational capabilities are crucial for businesses aiming to streamline processes and enhance profitability.

    ReplyDelete
  9. Can you plz tell me how to send multiple sales orders with their lines in single call?iam struggling to do any help would be appreciated

    ReplyDelete

Quick & Easy way to create XSD from Dynamics 365 for finance and operations

If you are looking for an quick & easy way to create XSD (schema) from Dynamics 365 for finance and operations. Below is the way, ...