SAP OData Deep Insertを使ったデータの登録(2)

概要

今回は、Deep Insertをするための処理を作成します。

 

Deep Insertをするためには、ODataのDPC拡張クラスでCREATE_DEEP_ENTITYメソッドを実装します。
Deep Insertをするとき、Fioriアプリケーション側から構造の中にテーブルを持った型でデータを渡します。(これをDeepな構造という)
この形で渡されたとき、自動的にCREATE_ENTITYではなくCREATE_DEEP_ENTITYが呼ばれます。

Deepな構造の例
image.png

ステップ

  • 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
image.png

②登録用のデータを作成する

レスポンスデータをコピーして、以下の形に編集します。
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
image.png

登録された伝票番号が返ってくれば成功です。
image.png

テーブルSNWD_SOを見てみます。
image.png

トラブルシューティング

エラーになった場合はまず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の実装もしてみたいと思います。

posted @ 2019-04-05 10:09  Park_SAP  阅读(328)  评论(0)    收藏  举报