สำหรับนักพัฒนาแล้ว คงหนีไม่พ้นต้องเจอการทำ Integration Apps บล็อกนี้จึงมาแนะนำการ integrate หรือสร้าง api สำหรับเชื่อมต่อกับ Microsoft Dynamics 365 for Finance and Operations (ซึ่ง 2 วิธีการที่จะแนะนำในวันนี้ ใช้บ่อยมาก)
Quick Suggest
ถ้าสนใจอยากรู้เพิ่มเติม ขอแนะนำบทความ
1. OData Service OData
เป็นโปรโตคอลมาตรฐานสำหรับการดึงข้อมูล ที่สามารถเข้าถึงได้ด้วยเทคโนโลยี HTTP และ JSON, OData service จะถูก public และใช้งานได้ทันที เมื่อเรา build application ผ่านเงื่อนไข Data Entities ที่ IsPublic = Yes
วิธีการใช้งานคือ http://[baseURI]/data , รายการที่แสดงขึ้นมาทั้งหมด คือ data entities ที่เราสามารถเรียกใช้งานได้ เช่น หากเราต้องการข้อมูลลูกค้า ก็ / ต่อท้ายได้เลย http://[baseURI]/data/Customers
รองรับคำสั่งตาม OData standards เช่น
- ดูข้อมูลทุก Company ในระบบ
http://[baseURI]/data/Customers?cross-company=true
- ดูข้อมูลเฉพาะ Company ที่เราสนใจ
http://[baseURI]/data/Customers?$filter=dataAreaId eq ‘thmf’&cross-company=true
- กรองข้อมูลฟิลอื่นๆก็ได้เหมือนกัน (กลุ่มลูกค้ารหัส 20)
http://[baseURI]/data/Customers?$filter=dataAreaId eq ‘thmf’ and CustomerGroupId eq ‘20’&cross-company=true
และเชื่อมต่อกับตัวดึงข้อมูล OData ใน Power BI Desktop ได้อีกด้วย สะดวกมาก ๆ
เกือบลืมไปอย่าง แวะมาดูการยืนยันตัวตนในการร้องขอใช้ API กันซักนิด
Authentication
OData Services, JSON-based Custom Service, and REST Metadata Service รองรับการยืนยันตัวตนแบบ OAuth 2.0 ดังนั้นเราต้องมาเตรียมตัวกันก่อน
OAuth — Authorization Code Grant Flow
จาก Flow เราต้องทำการ Register Application ที่ Microsoft Azure Active Directory (AAD) ก่อน เพื่อให้ได้ Authorization token มา (Link)
การ request ทุกครั้งจำเป็นต้อง call 2 ครั้ง ครั้งแรกนำ Authorization token ร้องขอไปยัง Azure AD เพื่อให้ได้ Access token มา (ซึ่งมีเวลาหมดอายุ), ครั้งที่สอง นำ Access token ที่ได้มาแนบไปกับการ request API ที่เราต้องการใช้งาน
-
ลองทดสอบโดยใช้ Postman
Request 1 : Access Token
- POST:
https://login.microsoftonline.com/:tenant_id/oauth2/token
- Params
tenant_id:c4dc70b8–32c4–4443-afde-530521xxxxxx (ได้จาก AAD)
- Body
grant_type:client_credentials
client_id:c8907ca6–09a6–40a6–83ce-e67a4xxxxx (ได้จาก AAD)
client_secret:.Ew2C94l?2elh/rLDszhHFFxxxxxxx (ได้จาก AAD)
resource:[baseURI]
Request 2 : Odata
- GET:
https://[baseURI]/data/Customers?$filter=dataAreaId eq ‘thmf’&$select=CustomerAccount,Name,AddressDescription,FullPrimaryAddress&cross-company=true
- Headers
Authorization:Bearer xxxxxxxxx (จาก access_token Request 1) Content-Type:application/json
- Tests
var json = JSON.parse(responseBody); tests[“Get customer info”] = !json.error && responseBody !== ‘’ && responseBody !== ‘{}’;
ข้อจำกัดของ api คือ URL ที่อยู่ใน VM จะไม่สามารถทดสอบได้ ต้องเป็น URL on-cloud หรือ on premises เท่านั้น
2. JSON-based custom service
เป็น custom service ที่เราสามารถสร้างเองได้จาก X++ classes หรือการเขียนโปรแกรมนั่นเอง มีการรับค่าและรีเทิร์นค่าแบบ JSON (JavaScript Object Notation), ทุก service ที่ถูก custom ขึ้นมา จะถูก deploy เป็น 2 endpoint เสมอ
- SOAP
endpoint https:///soap/services/UserSessionService?wsdl
- JSON endpoint
https:///api/services/UserSessionService/AifUserSessionService/GetUserSessionInfo
ตัวอย่างในวันนี้จะเป็นการสร้าง api อย่างง่ายในการเปิดใบสั่งขาย หรือ sales order มาเริ่มกันเลย
ส่วนประกอบของ Object
Class contract สำหรับดูแลเรื่อง parameter ซึ่งในที่นี้เราให้เป็น List ของรายการสินค้าและจำนวน
[DataContractAttribute]
public class QERP_SalesOrderContract
{
ItemId itemId;
Qty qty;
[DataMemberAttribute]
public ItemId itemId(ItemId _itemId = itemId)
{
itemId = _itemId;
return itemId;
}
[DataMemberAttribute]
public Qty qty(Qty _qty = qty)
{
qty = _qty;
return qty;
}
}
Class info สำหรับ return สถานะและรายละเอียด
[DataContractAttribute]
public class QERP_SalesOrderInfo
{
boolean success;
str message;
[DataMemberAttribute]
public boolean success(boolean _success = success)
{
success = _success;
return success;
}
[DataMemberAttribute]
public str message(str _message = message)
{
message = _message;
return message;
}
}
Class service สำหรับสร้าง sales order
public class QERP_SalesOrderService
{
[AifCollectionTypeAttribute('salesLineList', Types::Class, classStr(QERP_SalesOrderContract)), SysEntryPointAttribute(true)]
public QERP_SalesOrderInfo CreateSalesOrder(DataAreaId dataArea, CustAccount customer, List salesLineList)
{
QERP_SalesOrderInfo messageInfo = new QERP_SalesOrderInfo();
QERP_SalesOrderContract salesLineData;
SalesTable salesTable;
SalesLine salesLine;
NumberSeq numberSeq;
ListIterator literatorset;
ttsbegin;
changecompany(dataArea)
{
numberSeq = NumberSeq::newGetNum(SalesParameters::numRefSalesId());
salesTable.SalesId = numberSeq.num();
salesTable.initValue();
salesTable.CustAccount = customer;
salesTable.initFromCustTable();
salesTable.insert();
literatorset = new ListIterator(salesLineList);
while (literatorset.more())
{
salesLineData = literatorset.value();
salesLine.clear();
salesLine.SalesId = salesTable.SalesId;
salesLine.ItemId = salesLineData.itemId();
salesLine.SalesQty = salesLineData.qty();
salesLine.createLine(NoYes::Yes, // Validate
NoYes::Yes, // initFromSalesTable
NoYes::Yes, // initFromInventTable
NoYes::Yes, // calcInventQty
NoYes::No, // searchMarkup
NoYes::No); // searchPrice
literatorset.next();
}
}
ttscommit;
messageInfo.success(true);
messageInfo.message(strFmt("Sales order '%1' has been created.", salesTable.SalesId));
return messageInfo;
}
}
เมื่อ Build application เราก็จะได้ API เรียบร้อย
ทดสอบ request
ใช้ tools ประเภท SoapUI ก็ได้เหมือนกันนะ
ก้าวเข้าสู่ Digital Business
ดูผลิตภัณฑ์ที่เกี่ยวข้องได้ที่นี่