Integration of D365 using Azure API and logic apps: part 2
I hope you all are doing great and might have gone through my earlier blog on Azure APIm introduction: https://www.blogger.com/blog/post/edit/2520883737187850604/4308148657431504181
This documentation focuses through live examples as to how such a system could be effectively designed and made to work with D365.
Situation: problem statement
We have a 3rd party logistics system who creates
Purchase orders in DAX, validates and creates GRN in AX and subsequently posts
them.
Solution design
a.
A batch job that creates an Azure storage file
in a shared Azure folder.
b.
Custom Ax services pick up the file and creates
Purchase orders in D365
c.
The third party receives the purchase order in
their own system and tries to replicate the same in Ax. For that
I.
It needs to call an Ax defined class that
validates various information for a given purchase order.
II.
In order to do this you can define an
action/method in an exposed entity in D365, which in turns Class method from
Step I. You can call this action from a logic app.
III.
If returns Ok/true, it calls Step IV. Else
validation fails
IV.
It calls another action and pushes a record to a
staging table in Ax
V.
A batch picks up from this staging table and
creates/posts packing slips.
For our discussion’s sake we are concentrating for now on
Azure API and logic apps’ interactions. For creating and managing batches using
Azure folder, could be discussed separately on another blog.
Step 1: the staging table
We can make a staging table that primarily consist of the
following information/fields:
Table name
DEMImportPurchaseGRNTable
Fields
Fieldname |
Field type |
Extends |
Mandatory |
PurchId |
String(20) |
PurchId |
Yes |
LineNum |
Real |
Linenum |
Yes |
Qty |
Real |
Qty |
Yes |
ItemId |
String(20) |
ItemId |
Yes |
ImportId |
String(20) |
Num |
No |
Status |
Enum |
New Enum:
DEMProcessStatus Values:
In-process, Processed, Error |
No |
Properties
I.
Caching: Not_In_Transaction
II.
Table group: Worksheet line
III.
Label: provide suitable label
IV.
Developer documentation: provide suitable
documentation
V.
Set created date time and modified date time
properties to true
Methods
Create
a.
find
b.
exists
c.
logic for obtaining new ImportId
d.
initValue:
this.Status =
DEMProcessStatus::created;
this.ImportId = //call the
Import Id logic defined in step ‘c’ above
Keys
ImportIdIdx:
Field: Import Id
Allow duplicate: false
Set table Clustered Index and Surrogate key = ImportIdIdx
Step 2: method for validating
Create a class: DEMValidateImportGRN.
Validation Method:
Public
static Boolean validatePurchaseOrder(PurchId _purchId, ItemId _itemId, Qty
_qty)
{
If (!PurchTable::exists(_purhId))
checkFailed
(strfmt(“PurchId %1 does not exist”, _purchId));
PurchLine purchLine;
Select firstonly RecId, Qty from
purchLine
Where
purchLine.purchId == _purchId
&&
purchLine.ItemId == _itemId;
If (! purchLine.RecId)
checkFailed(strfmt(“Purchase
order %1 does not have %2 item”, _purchId, _itemId));
if (purchLine.Qty > _qty)
{
checkFailed(strfmt(“Insufficient
inventory for Purchase order %1 does not have %2 item”, _purchId, _itemId));
}
}
Defining the action:
You can select/create an existing/new entity à create a new method
like this:
[SysODataActionAttribute(‘validatePurchaseOrder’, true)]
public static boolean validatePurchaseOrder’ (PurchId _purchId, ItemId _itemId, Qty _qty)
{
return DEMValidateImportGRN:: validatePurchaseOrder(_purchId,
_itemId, _qty);
}
Step 3: populate the staging table for GRN post
In the same class as above, create a method to populate
staging table:
Public static Boolean populateStaging(PurchId _purchId, ItemId
_itemId, Qty _qty)
{
DEMImportPurchaseGRNTable
purchGRNTable;
try
{
purchGRNTable.initValue();
purchGRNTable.PurchId
= _purchId;
purchGRNTable.Qty
= _qty;
purchGRNTable.ItemId
= _itemId;
purchGRNTable.LineNum = //create
your own logic for populating line num; as a reference, please see the
PurchLine à
new line num logic.
purchGRNTable.insert();
return true;
}
Catch(exception::Ex)
{
Return
checkFailed(“insert failed for GRN import”);
}
}
Step 4: the Azure API
Open your https://portal.azure.com à search for available API
management services. Here, you can create your own API or use an already
existing one.
Add new service operation:
Validate purchase Order: validate:
Click on query and add parameters:
Click on save.
Click on outbound processing à
and add the policies:
<inbound>
<set-variable
name=”purchId” value=”@(context.Request.Url.Query.GetValueOrdefault(“purchId”))”>
<set-variable
name=”itemId”
value=”@(context.Request.Url.Query.GetValueOrdefault(“itemId”))”>
<set-variable
name=”qty” value=”@(context.Request.Url.Query.GetValueOrdefault(“qty”))”>
</inbound>
The above logic obtains the supplied ItemId, PurchId and qty
from query parameters.
Now we will call the logic append pass the above parameters:
Inside the <set_url> you can actually set the url of
your logic app.
See how you are creating a JSON object on the fly and
passing on as a response, like this:
{
“purchId”: “P000111”,
“itemId”:”It00001”,
“qty”: 5
}
Step 5: logic app to call your custom code:
You can create a Logic app like this (for more details,
refer to the the previous blog of logic app integration)
a.
Select the following trigger: “when a http
request is received”.
b.
Select the above template for JSON request body
{
“purchId”: “P000111”,
“itemId”:”It00001”,
“qty”: 5
}
c.
Add action: D365 for F&O as an action. Go to
connections and select your desired D365 instance.
d.
Select ‘Compose’ – a JSON template as a next
action:
In the inputs à create a new JSON as:
{
“Result”: ***Bring in the value output from
above action***
}
e.
As a last step create a response action, that
prints the result:
Why 202? It means when your request is ‘Accepted’. 200 means
‘Success, Ok”, etc.
Conclusion:
a.
When you call this logic app from Azure API as
mentioned above, you can get the result outcome as a HTTP request body
Comments
Post a Comment