Rails MWS オーダーのキャンセル

# はじめに
Rails + MWSでAmazonのオーダーのキャンセル処理をする方法を紹介します。

MWSでオーダーをキャンセルするには[SubmitFeed](http://docs.developer.amazonservices.com/ja_JP/feeds/Feeds_SubmitFeed.html)を使用します。
このSubmitFeedは指定するFeedTypeによって色々な情報を更新することができます。
今回はオーダーのキャンセルということで、**_POST_ORDER_ACKNOWLEDGEMENT_DATA_**というフィードタイプを指定します。

[FeedType一覧](http://docs.developer.amazonservices.com/ja_JP/feeds/Feeds_FeedType.html)

## 補足
厳密にいうとオーダーのキャンセルができるフィードタイプは以下の2種類になります。

- _POST_ORDER_ACKNOWLEDGEMENT_DATA_
- _POST_PAYMENT_ADJUSTMENT_DATA_

_POST_PAYMENT_ADJUSTMENT_DATA_は公式リファレンスにもある通り、キャンセル目的で使うのであれば「注文の一部キャンセル」に使用するそうです。
正直僕にはまだ使いどころが想像できません。（返金はこのフィードタイプで行います）

# フィードの解説
Amazonが提供してくれている_POST_ORDER_ACKNOWLEDGEMENT_DATA_フィードの例は以下のような感じです。
Messageのブロックがオーダーの単位ですね。

```xml
<?xml version="1.0"?>
<AmazonEnvelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
 <Header>
   <DocumentVersion>1.01</DocumentVersion>
   <MerchantIdentifier>M__45765</MerchantIdentifier>
 </Header>
 <MessageType>OrderAcknowledgement</MessageType>
 <Message>
   <MessageID>1</MessageID>
   <OperationType>Update</OperationType>
   <OrderAcknowledgement>
     <AmazonOrderID>503-4691292-7715199</AmazonOrderID>
     <StatusCode>Success</StatusCode>
   </OrderAcknowledgement>
 </Message>
 <Message>
   <MessageID>2</MessageID>
   <OperationType>Update</OperationType>
   <OrderAcknowledgement>
     <AmazonOrderID>503-5507100-9985598</AmazonOrderID>
     <StatusCode>Success</StatusCode>
   </OrderAcknowledgement>
 </Message>
</AmazonEnvelope>
```

オーダーをキャンセするす場合のMessageの中身はこんな感じです。

```xml
 <Message>
   <MessageID>1</MessageID>
   <OperationType>Update</OperationType>
   <OrderAcknowledgement>
     <AmazonOrderID>{AmazonOrderID}</AmazonOrderID>
     <StatusCode>Failure</StatusCode>
     <Item>
       <AmazonOrderItemCode>{AmazonOrderItemCode}</AmazonOrderItemCode>
       <CancelReason>{CancelReason}</CancelReason>
     </Item>
   </OrderAcknowledgement>
 </Message>
```

軽く説明すると、
キャンセルするにはStatusCodeにFailureを指定する必要があります。
また、キャンセル理由を指定するにはItemブロックを作成してOrderItemごとに指定する必要があります。

セラーセントラルから手動でキャンセルする時にはオーダー単位でキャンセル理由を指定してキャンセル処理をしますよね？
MWSからキャンセルを行う場合は上のXMLでいうところのItemブロックは実は任意です。
つまりキャンセル理由は本当は不要なんですねー。
キャンセル理由なしでキャンセルするの怖いので実際やったことはないですけどね:angel:

ちなみにCancelReasonは以下から選んでください。

- NoInventory										- ShippingAddressUndeliverable
- CustomerExchange
- BuyerCanceled
- GeneralAdjustment
- CarrierCreditDecision
- RiskAssessmentInformationNotValid
- CarrierCoverageFailure
- CustomerReturn
- MerchandiseNotReceived

# 実装

## 事前準備
[Rails MWS APIを利用するまでの事前準備](https://qiita.com/ayies128/items/7ce8530574122dfec507)
こちらよりpeddlerのclientインスタンスを作成できる状態にしておいてください:point_up:

## フィードのサブミット
peddlerのclientインスタンスを使用すればフィードのサブミットはめちゃくちゃ簡単です。
これだけですからね。

```rb
client = MWS.feeds(
  primary_marketplace_id: 'primary_marketplace_id',
  aws_access_key_id: '',
  aws_secret_access_key: 'aws_secret_access_key',
  merchant_id: 'merchant_id',
  auth_token: 'auth_token'
)
feed = 'サブミットするフィードの内容'
client.submit_feed(feed,'_POST_ORDER_ACKNOWLEDGEMENT_DATA_')
```

## フィードの作成
問題はフィードの作成が少し難しいというところです。
XML作るのとかめんどくさいですしね。
いつも[builder](https://github.com/jimweirich/builder)というgemを使用しているのでそれを使った実装を紹介します。
脳死でこのメソッドをコピペしたらいいんじゃないでしょうか？

```rb
def self.feed_generate(seller_id, datas)
  feed = ''
  xml = Builder::XmlMarkup.new(target: feed)
  xml.instruct!

  xml.AmazonEnvelope do
    xml.Header do
      xml.DocumentVersion('1.01')
      xml.MerchantIdentifier(seller_id)
    end
    xml.MessageType('OrderAcknowledgement')
    index = 1
    datas.each do |data|
      xml.Message do
        xml.MessageID(index.to_s)
        xml.OperationType('Update')
        xml.OrderAcknowledgement do
          xml.AmazonOrderID(data[:order_id])
          xml.StatusCode('Failure')
          xml.Item do
            xml.AmazonOrderItemCode(data[:order_item_id])
            xml.CancelReason(data[:cancel_reason])
          end
        end
      end
      index += 1
    end
  end
  feed
end
```

# 終わりに
やってみるとそんなに難しいことはないんですねえ。
注意すべきとことは、このフィードタイプでは例え1つしかOrderItemを指定していなくても、
オーダーが丸っとキャンセルされるというところですかね...

ブログで見る方はこちら
[http://nabesys.com/article/2018/08/03587/](http://nabesys.com/article/2018/08/03587/)