概要
今回は、Deep Insertをするための処理を作成します。
前回の記事:Deep Insertを使ったデータの登録(1)
次回の記事:Deep Insertを使ったデータの登録(3)
Deep Insertをするためには、ODataのDPC拡張クラスでCREATE_DEEP_ENTITYメソッドを実装します。
Deep Insertをするとき、Fioriアプリケーション側から構造の中にテーブルを持った型でデータを渡します。(これをDeepな構造という)
この形で渡されたとき、自動的にCREATE_ENTITYではなくCREATE_DEEP_ENTITYが呼ばれます。
ステップ
- Deep Insert用の処理を実装
- Deep Insertのテスト
Deep Insert用の処理を実装
DPC拡張クラスで以下の処理を実装します。
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY
METHOD /iwbep/if_mgw_appl_srv_runtime~create_deep_entity.
* Deep entityの型
DATA: BEGIN OF ls_salesorder.
INCLUDE TYPE zcl_z_mob58_04_salesor_mpc_ext=>ts_salesorder.
DATA: tosalesorderitem TYPE zcl_z_mob58_04_salesor_mpc_ext=>tt_salesorderitem,
END OF ls_salesorder.
DATA: ls_headerdata TYPE bapi_epm_so_header,
lt_itemdata TYPE TABLE OF bapi_epm_so_item,
ls_itemdata TYPE bapi_epm_so_item,
lv_so_id TYPE bapi_epm_so_id,
lt_return TYPE TABLE OF bapiret2.
"EntitySet名により分岐
CASE iv_entity_set_name.
WHEN 'SalesOrderSet'.
"アプリケーションから渡されたデータを読み込み
io_data_provider->read_entry_data(
IMPORTING
es_data = ls_salesorder
).
"ヘッダをBAPI受け渡し用の構造にセット
MOVE-CORRESPONDING ls_salesorder TO ls_headerdata.
"明細をBAPI受け渡し用のテーブルにセット
LOOP AT ls_salesorder-tosalesorderitem INTO DATA(ls_item).
MOVE-CORRESPONDING ls_item TO ls_itemdata.
"delivery_dateにタイムスタンプを設定する
GET TIME STAMP FIELD ls_itemdata-delivery_date.
APPEND ls_itemdata TO lt_itemdata.
ENDLOOP.
CALL FUNCTION 'BAPI_EPM_SO_CREATE'
EXPORTING
headerdata = ls_headerdata
* persist_to_db = abap_true
IMPORTING
salesorderid = lv_so_id
TABLES
itemdata = lt_itemdata
return = lt_return.
"エラーハンドリング
READ TABLE lt_return WITH KEY type = 'E' TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
mo_context->get_message_container( )->add_messages_from_bapi(
EXPORTING
it_bapi_messages = lt_return " Return parameter table
).
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = mo_context->get_message_container( ).
ENDIF.
"登録された受注の情報を取得
CLEAR: ls_headerdata, lt_itemdata, ls_salesorder.
CALL FUNCTION 'BAPI_EPM_SO_GET_DETAIL'
EXPORTING
so_id = lv_so_id
IMPORTING
headerdata = ls_headerdata
TABLES
itemdata = lt_itemdata
* RETURN =
.
"登録された情報を設定してアプリケーションへ返す
MOVE-CORRESPONDING ls_headerdata TO ls_salesorder.
me->copy_data_to_ref(
EXPORTING
is_data = ls_salesorder
CHANGING
cr_data = er_deep_entity
).
WHEN OTHERS.
ENDCASE.
ENDMETHOD.
先頭で定義したls_salesorderという構造は、アプリケーションからDeepな構造でデータを受け取るためのものです。
大まかな処理の流れは以下のようになっています。
①アプリケーションから渡されたデータ(Deepな構造)を読み込み
②BAPIで受注を登録
③登録された情報を取得してアプリケーションに返す
このメソッドは同じODataサービスに属するすべてのEntity Setが利用する可能性があるため、Entity Setの名前によって処理を分岐させています。
Deep Insertのテスト
Deep Insertで受注を登録してみます。
トランザクション:/IWFND/GW_CLIENTを起動します。
①登録用のデータのコピー元として、ヘッダ+明細を取得する
Request URIに以下のように入力します。
/sap/opu/odata/SAP/<サービス名>/SalesOrderSet('500000001')?$expand=ToSalesOrderItem&$format=json
②登録用のデータを作成する
レスポンスデータをコピーして、以下の形に編集します。
2件の明細を持つデータとなっています。
値未設定の項目は、BAPIの仕様上登録時に設定されているとエラーになるためブランクにしています。
{
"SoId": "",
"CreatedBy": "",
"ChangedBy": "",
"CreatedByBp": false,
"ChangedByBp": false,
"Note": "2019.3.17 MOV58",
"BuyerId": "100000005",
"BuyerName": "TECUM",
"CurrencyCode": "EUR",
"LifecycleStatus": "",
"BillingStatus": "",
"DeliveryStatus": "",
"ToSalesOrderItem": [{
"SoId": "",
"SoItemPos": "",
"ProductId": "HT-1040",
"Note": "EPM DG: SO ID 0500000002 Item 0000000010",
"CurrencyCode": "",
"GrossAmount": "2963.10",
"GrossAmountExt": "2963.1000",
"NetAmount": "2490.00",
"NetAmountExt": "2490.0000",
"TaxAmount": "473.10",
"TaxAmountExt": "473.1000",
"Quantity": "3",
"QuantityUnit": "EA"
},
{
"SoId": "",
"SoItemPos": "",
"ProductId": "HT-1041",
"Note": "EPM DG: SO ID 0500000002 Item 0000000010",
"CurrencyCode": "",
"GrossAmount" : "583.10",
"GrossAmountExt" : "583.1000",
"NetAmount" : "490.00",
"NetAmountExt" : "490.0000",
"TaxAmount" : "93.10",
"TaxAmountExt" : "93.1000",
"Quantity": "1",
"QuantityUnit": "EA"
} ]
}
③POSTメソッドで登録する
②で編集したデータを左側のRequestの部分に貼り付けます。
Request URIに以下のように入力して、POSTメソッドを実行します。
/sap/opu/odata/SAP/<サービス名>/SalesOrderSet
トラブルシューティング
エラーになった場合はまずCREATE_DEEP_ENTITYのメソッドに入る前と入った後、どちらでエラーになっているかを確認します。メソッドに外部デバッガを置き、POSTを実行したときにメソッドが呼ばれれば後者、呼ばれなければ前者です。
-
CREATE_DEEP_ENTITYに入る前のエラーの場合
-
Entity Setのプロパティで登録を許可しているか
-
URIを正しく指定しているか
-
登録データの形式は正しいか(データ型、あるいはJSONフォーマットが正しいか)
-
CREATE_DEEP_ENTITYに入った後のエラーの場合
-
基本的にはBAPIのエラーなので、BAPIから返ってくるメッセージを確認する
更新の場合はどうするか
データ登録の場合はCREATE_DEEP_ENTITYですが、親子関係のあるデータを更新したい場合はどうすればよいのでしょうか?
UPDATE_DEEP_ENTITYというメソッドはなく、以下のスレッドによれば2通りのやり方があるようです。
https://archive.sap.com/discussions/thread/3908823
①CREATE_DEEP_ENTITYを使う
メソッドの中で登録か更新かを判断して対応する
例:キーが渡されれば更新、渡されなければ登録
②$batch Processingを使う
複数のリクエストをまとめて処理する方法で、CHANGESET_BEGINというメソッドでまとめる単位を判断し、CHANGESET_PROCESSというメソッドで更新処理を行う
参考:https://archive.sap.com/documents/docs/DOC-57113
別の機会に、$batch Processingの実装もしてみたいと思います。