Dynamics CRM 2013の機能と構成を触りながら覚えてき行きます。
第2回も前回に引き続き受注を扱います。
ちょっとプログラミングよりのアプローチなので、使い方が知りたいかは読みとばすか、斜め読みしてください。
Dynamics CRM 2013で受注を作成する場合の必須データを確認してみます。
まず概要項目の「名前」と「価格表」が必須となります。
見込み顧客も必須となります。
見込顧客には「取引企業」または「取引担当者」が登録できるようです。
そして製品が必要です。
(製品は先に概要などの必須項目を埋めた後で無いと入力できないようです。)
価格表が必須ということで、製品は価格表から選ぶ必要があるのかなと思いましたが、「リスト外製品」として価格表に関係なくデータを入れることもできます。
リスト外商品と価格表から選択した商品のデータベース上の違いを確認してみます。
受注に紐づく製品はSalesOrderDetailBaseテーブルで確認できます。
SalesOrderDetailBaseを見るとリスト外商品はProductIDを持ちません。その代わりに製品名を「ProductDescription」に保持しています。
価格表から選んだ商品はProductIDで紐付いており、ProductDescriptionはNULLです。
IsProductOverriddenがリスト外製品は1なのも違いました。
無視する製品? リスト外フラグみたいなものかなぁ(推測)。
最低限の項目を理解した上でC#からデータを登録してみましょう。
以前に取引担当者(Contact)を保存する簡単なサンプルを紹介しましたが、今回は必須項目として別のテーブル(価格表や担当者など)を関連付ける必要があります。
実装までに少し苦労しましたが、ポータルから登録したデータを取得して中身を覗くことで解決作がわかりました。
テスト用のコードはこんな感じ(サンプルはSoapLoggerの一部書き換えです)。
SoapLoggerOrganizationService slos = new SoapLoggerOrganizationService(serverConfig.OrganizationUri, service, output); // デバッグ用salesOrderを取得 var sales_order_query = new QueryExpression("salesorder"); sales_order_query.ColumnSet = new ColumnSet(true); var sales_order_list = slos.RetrieveMultiple(sales_order_query);
例えば「見込み顧客」は以下のようにCoustomerIdカラムにEntityReference型で入っていることがわかります。
このEntityReferenceに気が付かずしばらくエラーを繰り返していました。
EntityReference型セットしてSalesOrderを保存するコードは以下。
SoapLoggerOrganizationService slos = new SoapLoggerOrganizationService(serverConfig.OrganizationUri, service, output); // デバッグ用salesOrderを取得 var sales_order_query = new QueryExpression("salesorder"); sales_order_query.ColumnSet = new ColumnSet(true); var sales_order_list = slos.RetrieveMultiple(sales_order_query); // 価格表を取得 var pricelevel_query = new QueryExpression("pricelevel"); pricelevel_query.ColumnSet = new ColumnSet(true); var pricelevel_list = slos.RetrieveMultiple(pricelevel_query); PriceLevel pl = pricelevel_list[1] as PriceLevel; // 担当を取得 var contact_query = new QueryExpression("contact"); contact_query.ColumnSet = new ColumnSet(true); var contact_list = slos.RetrieveMultiple(contact_query); Contact contact = contact_list[0] as Contact; // 製品を生成(既存製品データではなく、外部製品として作成) SalesOrderDetail detail = new SalesOrderDetail() { Quantity = 2, PricePerUnit = new Money(1980), ProductDescription = "サンプル商品 from C#", IsPriceOverridden = true }; List<SalesOrderDetail> list = new List<SalesOrderDetail>(); list.Add(detail); SalesOrder order = new SalesOrder() { order_details = list, Name = "サンプル受注 from C#", PriceLevelId = pl.ToEntityReference(), CustomerId = contact.ToEntityReference() }; slos.Create(order);
ContactやPriceLevelクラスのToEntityReferenceメソッドでEntityReferenceを取り出しています。
書いてみればこれだけなのですが、これが苦労しました。
ちなみに上記通信のSoapXMLのBODY部分は以下のようになっています。
そろそろ読むのが辛い内容に・・・
<s:Body> <Create xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services"> <entity xmlns:b="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <b:Attributes xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic"> <b:KeyValuePairOfstringanyType> <c:key>name</c:key> <c:value i:type="d:string" xmlns:d="http://www.w3.org/2001/XMLSchema">サンプル受注 from C#</c:value> </b:KeyValuePairOfstringanyType> <b:KeyValuePairOfstringanyType> <c:key>pricelevelid</c:key> <c:value i:type="b:EntityReference"> <b:Id>9f3e1627-efcd-e311-9697-d89d67790688</b:Id> <b:LogicalName>pricelevel</b:LogicalName> <b:Name i:nil="true"/> </c:value> </b:KeyValuePairOfstringanyType> <b:KeyValuePairOfstringanyType> <c:key>customerid</c:key> <c:value i:type="b:EntityReference"> <b:Id>30c661ef-2dd4-e311-abc5-d89d67764dcc</b:Id> <b:LogicalName>contact</b:LogicalName> <b:Name i:nil="true"/> </c:value> </b:KeyValuePairOfstringanyType> </b:Attributes> <b:EntityState i:nil="true"/> <b:FormattedValues xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic"> <b:Id>00000000-0000-0000-0000-000000000000</b:Id> <b:LogicalName>salesorder</b:LogicalName> <b:RelatedEntities xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic"> <b:KeyValuePairOfRelationshipEntityCollectionX_PsK4FkN> <c:key> <b:PrimaryEntityRole i:nil="true"/> <b:SchemaName>order_details</b:SchemaName> </c:key> <c:value> <b:Entities> <b:Entity> <b:Attributes> <b:KeyValuePairOfstringanyType> <c:key>quantity</c:key> <c:value i:type="d:decimal" xmlns:d="http://www.w3.org/2001/XMLSchema">2</c:value> </b:KeyValuePairOfstringanyType> <b:KeyValuePairOfstringanyType> <c:key>priceperunit</c:key> <c:value i:type="b:Money"> <b:Value>1980</b:Value> </c:value> </b:KeyValuePairOfstringanyType> <b:KeyValuePairOfstringanyType> <c:key>productdescription</c:key> <c:value i:type="d:string" xmlns:d="http://www.w3.org/2001/XMLSchema"> サンプル商品 from C# </c:value> </b:KeyValuePairOfstringanyType> <b:KeyValuePairOfstringanyType> <c:key> ispriceoverridden </c:key> <c:value i:type="d:boolean" xmlns:d="http://www.w3.org/2001/XMLSchema"> true </c:value> </b:KeyValuePairOfstringanyType> </b:Attributes> <b:EntityState i:nil="true"/> <b:FormattedValues/> <b:Id>00000000-0000-0000-0000-000000000000</b:Id> <b:LogicalName>salesorderdetail</b:LogicalName> <b:RelatedEntities/> </b:Entity> </b:Entities> <b:EntityName>salesorderdetail</b:EntityName> <b:MinActiveRowVersion i:nil="true"/> <b:MoreRecords>false</b:MoreRecords> <b:PagingCookie i:nil="true"/> <b:TotalRecordCount>0</b:TotalRecordCount> <b:TotalRecordCountLimitExceeded>false</b:TotalRecordCountLimitExceeded> </c:value> </b:KeyValuePairOfRelationshipEntityCollectionX_PsK4FkN> </b:RelatedEntities> </entity> </Create> </s:Body>
Please give us your valuable comment