Salesforce REST API の複合（Composite）リソースで注文管理へ注文を作成してみる

※ これから記載する事項は、私が所属する会社とは一切関係のない事柄です。


今回は Salesforce REST API の複合リソースを利用して注文管理のための注文を作成して行きたいと思います。詳細は「[注文管理へのデータのインポート](https://developer.salesforce.com/docs/atlas.ja-jp.244.0.order_management_developer_guide_html.meta/order_management_developer_guide_html/order_management_importing_data_into_data_mgmt.htm)」をご覧ください。


## Salesforce REST API の複合リソースとは？

一度に複数の要求を行うことでクライアントとサーバ間の往復回数を最小限に抑え、アプリケーションのパフォーマンスを高めます。複合リソースには下記の４つのタイプ（Composite、Batch、SObject Tree、SObject collections）がありますが、詳しくは SevenstarsRock さんの「[Salesforce REST API 複合リソースを使えるようになろう!](https://qiita.com/SevenstarsRock/items/2645dab1c019fd394217)」や[公式ヘルプ](https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/using_composite_resources.htm)をご確認ください。



## 注文管理の事前知識

* [注文概要オブジェクト](https://developer.salesforce.com/docs/atlas.ja-jp.244.0.object_reference.meta/object_reference/sforce_api_objects_ordersummary.htm)は[注文オブジェクト](https://developer.salesforce.com/docs/atlas.ja-jp.244.0.object_reference.meta/object_reference/sforce_api_objects_order.htm)が作成 or 更新された事をトリガーとしてフロー内で「[注文管理のフローコアアクション: 注文概要を作成](https://help.salesforce.com/s/articleView?id=sf.flow_ref_elements_om_actions_create_order_summary.htm&type=5)」を利用して作成されます。_なので注文概要を直接作成することはしません。_
* 注文概要オブジェクトには管理対象注文（Managed）と未管理注文（Unmanaged）があります。過去の注文や外部システムで管理される注文は未管理注文として登録します。



## 注文を作成してみる


今回は SObject Tree を利用して必要最低限の情報量で注文のみとユーザ情報も含んだ注文の２つを作成していきたいと思います。SObject Tree では１回の要求で最大２００件のレコードを作成でき、さらに５階層下の子オブジェクトまで作成できます。（[ヘルプ](https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/resources_composite_sobject_tree.htm)）


### 前提

* 注文作成のために必要となるオブジェクトは[ヘルプ](https://developer.salesforce.com/docs/atlas.ja-jp.244.0.order_management_developer_guide_html.meta/order_management_developer_guide_html/order_management_importing_data_into_data_mgmt.htm)内の「注文管理でのインポート時のデータ要件」を参照してください
* 下記のオブジェクトはすでに作成されている状態であるとします
    * 販売チャネル（SalesChannel）
    * 商品（Product2）
    * 注文配送方法（OrderDeliveryMethod）
    * （注文のみの場合）取引先（Account）の作成
* 複合リソース API を呼ぶ際にアクセストークンが必要ですが、取得方法については「[OAuth 2.0 ユーザ名パスワードフロー](https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_username_password_flow.htm&type=5)」であれば「[Salesforce Bulk API 2.0 を使ってみる](https://qiita.com/syunyama/items/51fc2bc368de9265e8ec#1-%E6%8E%A5%E7%B6%9A%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%A8%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%83%88%E3%83%BC%E3%82%AF%E3%83%B3%E3%81%AE%E5%8F%96%E5%BE%97)」と同様なので参考にしてみてください。



### 注文のみの作成

SObject Tree ではリクエストする際にルート（一番親となる）となるオブジェクトを指定する必要がありますが、顧客（取引先＝Account）を作成しない場合はルートは注文（Order）として登録します。
下記のようなリクエストで注文をルートとしたオブジェクト群を作成します。（[ヘルプ](https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/resources_composite_sobject_tree.htm)）

```http:リクエスト
POST /services/data/v57.0/composite/tree/Order HTTP/1.1
Host: XXXXXXX.my.salesforce.com
Content-Type: application/json
Authorization: Bearer {アクセストークン}
```

今回は注文作成のためのリクエストボディは下記のようにしました。（[リクエストボディに関するヘルプ](https://developer.salesforce.com/docs/atlas.ja-jp.api_rest.meta/api_rest/requests_composite_sobject_tree.htm)）

```json:リクエストボディ
{
    "records": [
        {
            "attributes": {
                "type": "Order",
                "referenceId": "refOrder1"
            },
            "AccountId": "0015h00001NF0j6AAD",
            "EffectiveDate": "2023-01-01",
            "OrderedDate": "2023-01-01",
            "SalesChannelId": "0bI5h000000TWD8EAO",
            "Status": "Draft",
            "OrderDeliveryGroups": {
                "records": [
                    {
                        "attributes": {
                            "type": "OrderDeliveryGroup",
                            "referenceId": "refOrderDeliveryGroup1"
                        },
                        "DeliverToCity": "東京都",
                        "DeliverToCountry": "日本",
                        "DeliverToName": "株式会社テスト",
                        "DeliverToPostalCode": "1000001",
                        "DeliverToState": "千代田区",
                        "DeliverToStreet": "千代田区１−１−１",
                        "OrderDeliveryMethodId": "2Dm5h000000PKLLCA4"
                    }
                ]
            },
            "OrderItems": {
                "records": [
                    {
                        "attributes": {
                            "type": "OrderItem",
                            "referenceId": "refOrderItem1"
                        },
                        "Quantity": 3,
                        "Product2id": "01t5h000009UUhpAAG",
                        "OrderDeliveryGroupId": "@{refOrderDeliveryGroup1.id}",
                        "Type": "Order Product",
                        "UnitPrice": 600,
                        "ListPrice": 800
                    }
                ]
            }
        }
    ]
}
```




### ユーザ情報も含んだ注文

ここでは顧客も同時に作成するので、顧客（取引先＝Account）をルートとして登録します。
下記のようなリクエストで顧客をルートとしたオブジェクト群を作成します。

```http:リクエスト
POST /services/data/v57.0/composite/tree/Account HTTP/1.1
Host: XXXXXXX.my.salesforce.com
Content-Type: application/json
Authorization: Bearer {アクセストークン}
```


今回は注文作成のためのリクエストボディは下記のようにしました。若干情報量を増やしてあります。

```json:リクエストボディ
{
  "records": [
      {
          "attributes": {
              "type": "Account",
              "referenceId": "refAccount1"
          },
          "AccountNumber": "123456789",
          "BillingCity": "東京都",
          "BillingCountry": "日本",
          "BillingPostalCode": "1000001",
          "BillingState": "千代田区",
          "BillingStreet": "千代田区１−１−１",
          "Name": "株式会社テスト",
          "CardPaymentMethods": {
              "records": [
                  {
                      "attributes": {
                          "type": "CardPaymentMethod",
                          "referenceId": "refCardPaymentMethod1"
                      },
                      "CardCategory": "CreditCard",
                      "CardType": "Visa",
                      "CardHolderName": "Taro Yamada",
                      "ExpiryMonth": "01",
                      "ExpiryYear": "2025",
                      "InputCardNumber": "*********1235",
                      "ProcessingMode": "External",
                      "Status": "InActive"
                  }
              ]
          },
          "Orders": {
              "records": [
                  {
                      "attributes": {
                          "type": "Order",
                          "referenceId": "refOrder1"
                      },
                      "BillingCity": "東京都",
                      "BillingCountry": "日本",
                      "BillingPostalCode": "1000001",
                      "BillingEmailAddress": "sample@example.com",
                      "BillingState": "千代田区",
                      "BillingStreet": "千代田区１−１−１",
                      "EffectiveDate": "2023-01-01",
                      "Name": "株式会社テスト",
                      "OrderedDate": "2023-01-01",
                      "OrderReferenceNumber": "123456789",
                      "SalesChannelId": "0bI5h000000TWD8EAO",
                      "Status": "Draft",
                      "OrderDeliveryGroups": {
                          "records": [
                              {
                                  "attributes": {
                                      "type": "OrderDeliveryGroup",
                                      "referenceId": "refOrderDeliveryGroup1"
                                  },
                                  "DeliverToCity": "東京都",
                                  "DeliverToCountry": "日本",
                                  "DeliverToName": "株式会社テスト",
                                  "DeliverToPostalCode": "1000001",
                                  "DeliverToState": "千代田区",
                                  "DeliverToStreet": "千代田区１−１−１",
                                  "EmailAddress": "sample@example.com",
                                  "OrderDeliveryMethodId": "2Dm5h000000PKLLCA4"
                              }
                          ]
                      },
                      "OrderItems": {
                          "records": [
                              {
                                  "attributes": {
                                      "type": "OrderItem",
                                      "referenceId": "refOrderItem1"
                                  },
                                  "Description": "GoBar Tart Cherry Hi Protein, 2oz 6 Pack",
                                  "Quantity": 3,
                                  "Product2id": "01t5h000009UUhpAAG",
                                  "OrderDeliveryGroupId": "@{refOrderDeliveryGroup1.id}",
                                  "TotalLineAmount": 2100,
                                  "Type": "Order Product",
                                  "UnitPrice": 700,
                                  "ListPrice": 800
                              }
                          ]
                      }
                  }
              ]
          }
      }
  ]
}
```



## 作成時の注意点

* 作成するオブジェクトに対して[権限](https://help.salesforce.com/s/articleView?id=sf.users_profiles_object_perms.htm&type=5)があり、さらに[項目へのアクセス](https://help.salesforce.com/s/articleView?id=sf.customize_fieldaccess.htm&type=5)がある必要があります
* オブジェクト作成時に[重複管理](https://help.salesforce.com/s/articleView?id=sf.duplicate_prevention_map_of_tasks.htm&type=5)にも注意しましょう
* オブジェクトが作成されたことによりフローが開始される場合はフロー内でエラーが出ないように注意しましょう