SAP技術者のサンプルコード置き場

ABAPの動作確認をしたコードと簡単な説明を置いておきます。

SE84でメソッドや属性を探す

こんにちは。 Twitter(@free_croud)の方でいいねを多くいただいたのでブログでもアウトプットします。

SAP GUIABAPクラス(「クラスと特性値」の「クラス」ではない方といえばいいでしょうか)を作成、検索する際には SE24を使用することになりますが、ふと考えました。
「クラスのメソッドや属性を検索するにはどうしたらいいんだろう?」
SE24の第1画面でCtrl+Fを押下して検索画面を開いても、メソッドや属性を検索することはできないんですよね。

f:id:free_croud:20201107091925p:plain
SE24でCtrl+Fを押下して開く選択画面

考えたところ、SE84(オブジェクトナビゲーター)で検索できました。SE84を開き、左側のツリーで「Class Library(クラスライブラリ)」を開くと、クラス/インターフェース以外にもメソッドや属性ほかが検索できます。

f:id:free_croud:20201107092617p:plain
SE84 メソッド検索

画面ショットでは省略しましたが、チェックボックスで様々な条件を指定できるようです。チェックボックスの位置に雑な感じがして少々不安ですが(笑)。 属性でも検索できるので、「タブ文字入れたいけどHORIZONTAL_TABのクラスなんだったっけ?」というときも簡単に検索できます。

f:id:free_croud:20201107093330p:plain
属性検索結果

SE24ではほかにも、項目IDや項目説明から使用DBを検索する、などの機能もあり、SAPGUIでの開発で役に立つと思います。今回は以上です、ありがとうございました。

f:id:free_croud:20201107093727p:plain
テーブル項目で「WERKS」を検索してみた場合の検索結果

SD伝票カテゴリ値は、IF_SD_DOC_CATEGORYの属性値でわかりやすく

こんにちは。 受注伝票のユーザEXITやコピールーチン等で、伝票タイプほど厳密ではなく、 「受注」「無償」「返品」などの分類で処理を分岐させたい場合、伝票カテゴリ(例としてVBAK-VBTYP)を使用する場合があるのですが、 「受注」なら'C'、「無償受注」なら’I'、出荷なら「J」などと値が決まっています(ドメイン:VBTYPLのドメイン値)

となると、ABAPコードでは、

IF VBAK-VBTYP = 'C'. "受注

と書きます。ただし、いざ'C'とだけしか書いていないとわからない場合がありますよね。 そのためコメントでこの’C'の意味を書くことが多いのですが、 インターフェース:IF_SD_DOC_CATEGORYの属性値で書けばコメントを書かずともわかりやすくなります。 先ほどのコードは、

IF VBAK-VBTYP =IF_SD_DOC_CATEGORY=>ORDER.

と書き表すことができます。属性名がそのまま意味をあらわしているのでわかりやすいですよね。

IF_SD_DOC_CATEGORYの属性値と、ドメイン:VBTYPLのドメイン値を比較した一覧を下記に表示します。 一部項目のありなしや値が異なるものがあります。 VBTYPLの値は互換性のため削ることができず、新たに作成されたIF_SD_DOC_CATEGORYで内容を整理した可能性がありますが、詳細は不明です。

f:id:free_croud:20201017011701p:plain
リスト1/2

f:id:free_croud:20201017011820p:plain
リスト2/2

こんなの'C'でコードすればいいならその方がタイプ量が減っていいのに、と思う方もいると思います。 ただ、私の設計書では以降IF_SD_DOC_CATALOGを使って書こうと思っていますので、私の設計書が当たった皆さんは申し訳ございませんが、 都度IF_SD_DOC_CATALOGの属性値を書いていただければ幸いです(笑)。

以上です、ありがとうございました。

【ABAP】VL10*系の一括処理ログ情報取得後、メッセージテキストを作成する一覧結果

こんにちは。 受注伝票の一覧アドオンに、出荷伝票のバッチ登録結果を表示したい、という要望があり、 サンプルコードを作ってみました。まあそれだけだと面白くもなんともないので、

  • OO ABAPライクに(インスタンスを使っているわけでもないのですが(笑))
  • メッセージの各値を渡すとメッセージテキストを返すメソッド(cl_sat_t100_message_svc=>get_text)を使用

ということをやってみました。

本当は、SELECT文の抽出の際にメソッドを呼び出しメッセージテキストも取得して LOOPレスにしたかったのですが、今の自分の知識ではできませんでした。 FIELDS句にメソッドのRETURNINGパラメータを持たせることはできそうなのですが、 引き渡しパラメータとしてテーブル項目(T2~MSGIDなど)を設定しようとするとエラーが出てしまいました。 ラッパメソッドを作って間接的に呼び出せば…?と試したりもしましたが、自分の知識不足なのか、うまくいきませんでした。

テストコードなので命名方法がバラバラなのはご容赦願います(笑)

CLASS test DEFINITION.
  PUBLIC SECTION.
    TYPES: BEGIN OF typ_data,
             sammg  TYPE vbsk-sammg,
             smart  TYPE vbsk-smart,
             ernam  TYPE vbsk-ernam,
             erdat  TYPE vbsk-erdat,
             uzeit  TYPE vbsk-uzeit,
             vbnum  TYPE vbsk-vbnum,
             ernum  TYPE vbsk-ernum,
             vstel  TYPE vbsk-vstel,
             vtext  TYPE vbsk-vtext,
             vbeln  TYPE vbfs-vbeln,
             posnr  TYPE vbfs-posnr,
             etenr  TYPE vbfs-etenr,
             zaehl  TYPE vbfs-zaehl,
             msgid  TYPE vbfs-msgid,
             msgno  TYPE vbfs-msgno,
             msgty  TYPE vbfs-msgty,
             msgv1  TYPE vbfs-msgv1,
             msgv2  TYPE vbfs-msgv2,
             msgv3  TYPE vbfs-msgv3,
             msgv4  TYPE vbfs-msgv4,
             errmsg TYPE string,
           END OF typ_data,
           ttyp_data TYPE TABLE OF typ_data.
    CLASS-DATA: itab_data TYPE ttyp_data,    "静的データ定義
                w_msg TYPE symsg.

    CLASS-METHODS:  "Static Methodの定義
      main,
      add_msg CHANGING  table_data TYPE STANDARD TABLE,
      disp_data IMPORTING results TYPE STANDARD TABLE.

ENDCLASS.

CLASS test IMPLEMENTATION.
  METHOD main.
    SELECT
      FROM vbsk AS t1
      INNER JOIN vbfs AS t2
      ON t1~sammg = t2~sammg
      FIELDS
        t1~sammg,
        t1~smart,
        t1~ernam,
        t1~erdat,
        t1~uzeit,
        t1~vbnum,
        t1~ernum,
        t1~vstel,
        t1~vtext,
        t2~vbeln,
        t2~posnr,
        t2~etenr,
        t2~zaehl,
        t2~msgid,
        t2~msgno,
        t2~msgty,
        t2~msgv1,
        t2~msgv2,
        t2~msgv3,
        t2~msgv4,
        @space AS errmsg
      WHERE t1~smart = 'L'
      ORDER BY t1~smart, erdat, uzeit
      INTO TABLE @itab_data.

*   メッセージテキストを付与
    add_msg( CHANGING table_data = itab_data ).

*   Static Methodを同クラスから呼び出し
*    disp_data( results = itab_data ).
    disp_data( itab_data ). "必須のIMPORTパラメータなのでパラメータ名省略可

  ENDMETHOD.

* メッセージテキストをテーブルの各データに追加
  METHOD add_msg.
    FIELD-SYMBOLS <line> TYPE typ_data. "インライン定義すると項目がないとエラー
    LOOP AT table_data ASSIGNING <line>.
      w_msg-msgty = <line>-msgty.
      w_msg-msgid = <line>-msgid.
      w_msg-msgno = <line>-msgno.
      w_msg-msgv1 = <line>-msgv1.
      w_msg-msgv2 = <line>-msgv2.
      w_msg-msgv3 = <line>-msgv3.
      w_msg-msgv4 = <line>-msgv4.
      <line>-errmsg = cl_sat_t100_message_svc=>get_text( w_msg ).
    ENDLOOP.

  ENDMETHOD.

* 結果出力
  METHOD disp_data.
    cl_demo_output=>display( results ).
  ENDMETHOD.

ENDCLASS.

START-OF-SELECTION.
  test=>main( ).   

f:id:free_croud:20201010111721p:plain
結果ショット1

f:id:free_croud:20201010111804p:plain
結果ショット2

ユーザIDが変更になった場合のADTツリー表示変更・オブジェクトの所有者変更について

こんにちは。

ABAP Develop,ent Tool(ADT)で、自身が使用しているユーザIDが変更になった場合に、 今のユーザのプロジェクトに前のユーザIDが作成したローカルオブジェクトを表示させる方法についてまとめました。

一般的な開発案件ではありえない話ですが、レンタル環境でSAP環境を使っており、 さらにプログラムをすべてローカルオブジェクトとして登録していた中で、 何度かユーザIDの変更が発生したので記載しておきます。

1.現在のユーザのプロジェクトエクスプローラーに別ユーザのローカルオブジェクトをツリー表示させる

1-1.Project Explorer内のLocal Objects($tmp)を右クリックして、 「Add Local Objects of User」を選択

f:id:free_croud:20200929223843p:plain
右クリックして、Add local Objects of User を選択

1-2.取り込みたい過去のユーザIDを指定してエンターを押下

f:id:free_croud:20200929224031p:plain
取り込みたい過去のユーザIDを指定

1-3.そのユーザIDのローカルオブジェクトのツリー表示され、コードをツリーからたどれるようになる

f:id:free_croud:20200929224121p:plain
指定したユーザIDのツリーがプロジェクトに表示される

以上で、表示自体は可能なのですが、過去のユーザIDのツリーからたどる必要があり少々煩雑です。もう過去のユーザIDにはログインしないので、過去のユーザIDで作成したローカルオブジェクトを自分のツリーの配下に表示させたい、という場合は以下を実施します。
今回はプログラムのみに絞って説明します。

2.ローカルオブジェクトの責任者を現在のユーザIDに設定(ADT編)

2-1.プログラムIDを右クリック>Open With>SAP GUI で、対象プログラムをSAP GUIで開く。

f:id:free_croud:20200929230511p:plain
対象プログラムを(ADT上の)SAP GUIで開く

2-2.メニューバーの「More(追加)」>Go To(ジャンプ)>Object Directory Entry(オブジェクトディレクトリエントリ)を指定する。

f:id:free_croud:20200929230605p:plain
日本語だと追加>ジャンプ>オブジェクトディレクトリエントリ でしょうか?

2-3.表示されたオブジェクトディレクトリエントリ画面で変更ボタンを押下>下部の左から2番目の「Display/Change」を押下>Person Responsible(責任者)を今のユーザIDに変更して保存する。

f:id:free_croud:20200929230944p:plain
責任者を前のユーザIDから現在のユーザIDに変更

2-4.対応したいすべてのプログラムでこれを繰り返す(えっ)。
※一括で対応できる方法をご存じの方、ぜひ書き込みお願いします!!

2-5.ユーザのツリーのところで右クリックしてRefresh(リフレッシュ)またはF5キー押下で更新すると変更が反映される。
対象のプログラムが新しいユーザIDのツリーで表示できるようになりますが、前のユーザと今のユーザの両方で行わないとツリーが反映されないようです。
そのため、すべてのプログラムで対応が終わってから再度ログインした方が良いと思います。

f:id:free_croud:20200929231235p:plain
更新前
f:id:free_croud:20200929231722p:plain
前のユーザ、今のユーザの両方でツリーを更新するとツリー上でも移動する

3.ローカルオブジェクトの責任者を現在のユーザIDに設定(SAP GUI編)

トランザクションSE38から実施

各プログラムを指定してコード照会画面に遷移してから、上記2-2.からの手順で対応する。

トランザクションSE80から実施

以下の操作を行なってから、上記2-3.からの手順で対応する。

3-1.左下のツリーの上部で「ローカルオブジェクト」と「前のユーザID」を指定してエンターキーを押下する。そのユーザIDで作成したローカルオブジェクトがすべてツリーに表示される。

f:id:free_croud:20200929232407p:plain
SAP GUI SE80で行う場合

3-2.ツリーのプログラムIDを右クリック>Additional Functions(追加機能)>Display Object Directory Entry でオブジェクトディレクトリエントリ画面を表示させる。
f:id:free_croud:20200929232513p:plain
操作をしてオブジェクトディレクトリ画面を表示させます

意外なほど手間がかかるのでもしかすると標準プログラムなどで移行ツールがあったりしないかな?と思っています。
もしご存じの方いらっしゃいましたらコメントをいただけますと幸いです。

受注伝票標準画面の追加データBタブにカスタム項目を追加する

自社の後輩社員から件名の内容について確認がありました。 後輩社員さんはググったけど見つからなかったと言っていましたが、どうやら日本語で検索していたようです。 日本語でのSAP情報の充実と、自身の備忘録として(すぐ忘れちゃうので:笑)この記事を作成しました。

参考にさせていただいたサイト

www.saptutorial.org

wiki.scn.sap.com


1.SAPテーブルに追加データBタブで表示する項目を追加

VBAK・VBAPにappend項目を追加(append項目を定義>その配下にINCLUDEを定義>その配下に項目を定義)
※項目は「ZZ始まり」で定義する必要があります。
※アクセスキーを取得する必要があります。

2.画面を定義

ヘッダ:SAPMV45A 8309
明細: SAPMV45A 8459

をSE51にて編集し、画面に項目を追加して有効化

3. PBO、PAIロジックを追加(必要なら)

PBO(Process Before Output:画面表示前に行う処理):MV45AO0Z 初期値取得ロジック
PAI(Process After Input:項目入力後に行う処理):MV45AI0Z 入力値チェックロジックなど

をそれぞれ必要であれば設定します。

4.保存前ロジックを追加(必要なら)

MV45AFZZのルーチン:SAVE_DOCUMENT_PREPARE に記述します。

以上となります。

【ABAP】BAPI_PRICES_CONDITIONS SAMPLE CODE2

条件マスタの内容を登録更新を行うBAPI, BAPI_PRICES_CONDITIONSの動作検証時に作成したサンプルコードです。

条件タイプPB00、条件テーブルA018でのサンプルです。 品目コードを18バイトで設定しないとゴミデータを登録するので注意が必要です。 条件マスタ関連およびBAPI_PRICES_CONDITIONSの説明は Qiitaにて記事を作成しています。

qiita.com

サンプルコード

TYPES:
   tt_bapicondct  TYPE TABLE OF bapicondct,
   tt_bapicondhd  TYPE TABLE OF bapicondhd,
   tt_bapicondit  TYPE TABLE OF bapicondit,
   tt_bapicondqs  TYPE TABLE OF bapicondqs,
   tt_bapicondvs  TYPE TABLE OF bapicondvs,
   tt_bapiret2    TYPE TABLE OF bapiret2,
   tt_bapiknumhs  TYPE TABLE OF bapiknumhs,
   tt_mem_initial TYPE TABLE OF cnd_mem_initial.
DATA:
  it_bapicondct  TYPE tt_bapicondct,
  it_bapicondhd  TYPE tt_bapicondhd,
  it_bapicondit  TYPE tt_bapicondit,
  it_bapicondqs  TYPE tt_bapicondqs,
  it_bapicondvs  TYPE tt_bapicondvs,
  it_bapiret2    TYPE tt_bapiret2,
  it_bapiknumhs  TYPE tt_bapiknumhs,
  it_men_initial TYPE tt_mem_initial.

data(l_table_no) = '018'.
data(l_operation) = '009'.
data(l_cond_usage) ='A'.
data(l_applicatio) = 'M'.
data(l_cond_no) = '$000000001'. "新規登録時に使用するダミーの条件レコード番号
data(l_cond_type) = 'PB00'.
data(l_valid_from) = '20250101'.
data(l_valid_to) = '20251231'.

* 変数キー項目定義
data(varkey_lifnr) = |{ '100015'          alpha = in width = 10 }|.
data(varkey_matnr) = |{ 'T-M15A01'  alpha = in width = 18 }|. "NOT 40
data(varkey_EKORG) = |{ '1000'         width = 4 }|.
data(varkey_ESOKZ) = |{ '0'                width = 1 }|.
data(l_varkey) = |{ varkey_lifnr }{ varkey_matnr }{ varkey_ekorg }{ varkey_esokz }|.

it_bapicondct = VALUE #(
  ( operation = l_operation
    cond_usage = l_cond_usage
    table_no = l_table_no
    applicatio = l_applicatio
    cond_type = l_cond_type
    varkey = l_varkey
    valid_to = l_valid_to
    valid_from = l_valid_from
    cond_no = l_cond_no )
     ).
it_bapicondhd = VALUE #(
  ( operation = l_operation
    cond_no = l_cond_no
    created_by = sy-uname
    creat_date = sy-datum
    cond_usage = l_cond_usage
    table_no = l_table_no
    applicatio = l_applicatio
    cond_type = l_cond_type
    varkey = l_varkey
    valid_from = l_valid_from
    valid_to = l_valid_to )
    ).
it_bapicondit = VALUE #(
  ( operation = l_operation
    cond_no = l_cond_no
    cond_count = '01'
    applicatio = l_applicatio
    cond_type = l_cond_type
    scaletype = 'A'
*    scalebasin = ''
*    scale_qty = '0'
    cond_p_unt = '1'
    cond_unit = 'ST' "NOT PC
    calctypcon = 'C'
    cond_value = '1500'
    condcurr = 'JPY' )
    ).

CALL FUNCTION 'BAPI_PRICES_CONDITIONS'
*  EXPORTING
*    pi_initialmode = 'X'
**PI_BLOCKNUMBER =
*    PI_PHYSICAL_DELETION = abap_on
  TABLES
    ti_bapicondct  = it_bapicondct
    ti_bapicondhd  = it_bapicondhd
    ti_bapicondit  = it_bapicondit
    ti_bapicondqs  = it_bapicondqs
    ti_bapicondvs  = it_bapicondvs
    to_bapiret2    = it_bapiret2
    to_bapiknumhs  = it_bapiknumhs
    to_mem_initial = it_men_initial
  EXCEPTIONS
    update_error   = 1
    OTHERS         = 2.

cl_demo_output=>write(  sy-subrc ).
cl_demo_output=>write( it_bapiret2 ).

IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING
      wait = 'X'.
*   IMPORTING
*     RETURN        =    .
ELSE.
  MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
  WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

cl_demo_output=>display( ).

【ABAP】BAPI_PRICES_CONDITIONS SAMPLE CODE

条件マスタの内容を登録更新を行うBAPI, BAPI_PRICES_CONDITIONSの動作検証をしていたところ、 過去のSAP COMMUNITYのコードを見つけて試したものの動かず。

さらに検索したところやっと動くコードを見つけて動作させることができました。 ※詳細はQiitaに掲載します。記事はこれから書くので後でリンクを張っておきます。

※条件タイプPR00、条件テーブルA304でのサンプルです。

参考先

abap-mania.blogspot.com

answers.sap.com

サンプルコード

TYPES:
   tt_bapicondct  TYPE TABLE OF bapicondct,
   tt_bapicondhd  TYPE TABLE OF bapicondhd,
   tt_bapicondit   TYPE TABLE OF bapicondit,
   tt_bapicondqs  TYPE TABLE OF bapicondqs,
   tt_bapicondvs  TYPE TABLE OF bapicondvs,
   tt_bapiret2      TYPE TABLE OF bapiret2,
   tt_bapiknumhs  TYPE TABLE OF bapiknumhs,
   tt_mem_initial   TYPE TABLE OF cnd_mem_initial.
DATA:
  it_bapicondct  TYPE tt_bapicondct,
  it_bapicondhd  TYPE tt_bapicondhd,
  it_bapicondit  TYPE tt_bapicondit,
  it_bapicondqs  TYPE tt_bapicondqs,
  it_bapicondvs  TYPE tt_bapicondvs,
  it_bapiret2    TYPE tt_bapiret2,
  it_bapiknumhs  TYPE tt_bapiknumhs,
  it_men_initial TYPE tt_mem_initial.

DATA: l_a304 TYPE a304.
l_a304-vkorg = '1510'.
l_a304-vtweg = '10'.
l_a304-matnr = 'FG126'.
l_a304-kfrst = space.

it_bapicondct = VALUE #(
  ( operation = '009'
    cond_usage = 'A'
    table_no = '304'
    applicatio = 'V'
    cond_type = 'PR00'
    varkey = |{ l_a304-vkorg }{ l_a304-vtweg }{ l_a304-matnr }{ l_a304-kfrst }|
    valid_to = '99991231'
    valid_from = '20230101'
    cond_no = '$000000001' )
     ).
it_bapicondhd = VALUE #(
  ( operation = '009'
    cond_no = '$000000001'
    created_by = sy-uname
    creat_date = '20200909'
    cond_usage = 'A'
    table_no = '304'
    applicatio = 'V'
    cond_type = 'PR00'
    varkey = |{ l_a304-vkorg }{ l_a304-vtweg }{ l_a304-matnr }{ l_a304-kfrst }|
    valid_from = '20230101'
    valid_to = '99991231')
    ).
it_bapicondit = VALUE #(
  ( operation = '009'
    cond_no = '$000000001'
    cond_count = '01'
    applicatio = 'V'
    cond_type = 'PR00'
*    scaletype = ''
*    scalebasin = ''
*    scale_qty = '0'
    cond_p_unt = '1'
    cond_unit = 'ST' "NOT PC
    calctypcon = 'C'
    cond_value = '800'
    condcurr = 'JPY' )
    ).

CALL FUNCTION 'BAPI_PRICES_CONDITIONS'
*  EXPORTING
*    pi_initialmode = 'X'
**PI_BLOCKNUMBER =
  TABLES
    ti_bapicondct  = it_bapicondct
    ti_bapicondhd  = it_bapicondhd
    ti_bapicondit  = it_bapicondit
    ti_bapicondqs  = it_bapicondqs
    ti_bapicondvs  = it_bapicondvs
    to_bapiret2    = it_bapiret2
    to_bapiknumhs  = it_bapiknumhs
    to_mem_initial = it_men_initial
  EXCEPTIONS
    update_error   = 1
    OTHERS         = 2.

cl_demo_output=>write(  sy-subrc ).
cl_demo_output=>write( it_bapiret2 ).

IF sy-subrc = 0.
  CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
    EXPORTING
      wait = 'X'.
*   IMPORTING
*     RETURN        =    .
ELSE.
  MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
  WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.

cl_demo_output=>display( ).