Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

ABAP OO - MEREQ (Purchase Req) - Protected Attributes

Former Member
0 Kudos

Hi Gurus !!

I'm trying to Assign data in PR (ME5xN) as I do in PO, but I'm afraid I'm facing a wall.

Here is my requirement : when a field on an item is changed (let's say AFNAM), I have to modify field in coding block, here FISTL.

I've tried a lot of syntaxes to get to the Account data, including the casting to root object one, but from an item, I can go to the Account container but then attr MY_STATE is declared as Protected...

Too bad, 'cause next step is ACCT_ITEMS, in which further are the account item, even though there's another My_State set as protected to override.

From Abap debuger, I can access to the field I want, and edit it, my value will appear in screen then.

So question is : how do I work around protected attr, can I Assign structures/table anyway ? Is there any hope ??

Thx in advance Gurus !

N H

Edit: just to clarify, I've decided to put my code in an enhancement just before the method Process_Item of BAdI PROCESS_REQ_CUS and use the content there from object ME. I might put it back in the method, but I'm not sure content is at all taken in consideration if I succeed in modifying internal data.

Edited by: N H on Oct 22, 2008 12:45 PM

1 ACCEPTED SOLUTION

uwe_schieferstein
Active Contributor
0 Kudos

Hello

The coding shown below changes the cost center (KOSTL) of an item if the requisitioner is changed and contains the string 'us'. The reason why I did not test this with FISTL is because I did not have a suitable PO req available.

Disclaimer: I did not save the changed PO and did not check whether anything was changed in a proper manner because I have little experience with PO reqs.

BAdI ME_PROCESS_REQ_CUST (interface IF_EX_ME_PROCESS_REQ_CUST) -> create implementation and corresponding class:


METHOD if_ex_me_process_req_cust~process_item.
  DATA:
    ld_attr         TYPE string,
    ld_method       TYPE string,
    lo_obj          TYPE REF TO object,  " root object
    lo_obj_2        TYPE REF TO object.

  DATA: lt_cobl     TYPE STANDARD TABLE OF cobl,
**        lt_cobl_add type STANDARD TABLE OF meaccadd,
        ls_cobl     TYPE cobl.


  FIELD-SYMBOLS:
    <lo_lcl>        TYPE ANY,
    <lo_lcl_2>      TYPE ANY,
    <ld_afnam>      TYPE ANY,
    <ls_item>       TYPE mereq_item,
    <ls_itemx>      TYPE mereq_itemx.


  break-point.
  CHECK ( im_count = 1 ).  " avoid endless iteration -> see NOTE below

  lo_obj     ?= im_item.  " casting to root object !!!!!

  ld_attr = 'MY_STATE'.
  ASSIGN lo_obj->(ld_attr) TO <lo_lcl>.

  ld_attr = 'MY_STATE->ITEM'.
  ASSIGN lo_obj->(ld_attr) TO <ls_item>.
  "    ASSIGN l_item_ref->(ld_attr) TO <ls_item>.  " does not work...
*
  ld_attr = 'MY_STATE->ITEMX'.
  ASSIGN lo_obj->(ld_attr) TO <ls_itemx>.

  " Check change indicator for requisitioner
  ASSIGN COMPONENT 'AFNAM' OF STRUCTURE <ls_itemx> TO <ld_afnam>.
  CHECK ( <ld_afnam> = 'X' ).

  " Get account container instance
  ld_attr = 'MY_STATE->ACCT_CONTAINER'.
  ASSIGN lo_obj->(ld_attr) TO <lo_lcl_2>.
  lo_obj_2 = <lo_lcl_2>.



  " Get requisitioner
  ASSIGN COMPONENT 'AFNAM' OF STRUCTURE <ls_item> TO <ld_afnam>.
  CHECK ( <ld_afnam> CS 'us' ).

  " Condition: if requisitioner was changed and contains 'us' string
  "            then set KOSTL = '4200'

  ld_method = 'GET_COBL'.  " getter method
  CALL METHOD lo_obj_2->(ld_method)
    IMPORTING
      ex_cobl = lt_cobl.

  READ TABLE lt_cobl INTO ls_cobl INDEX 1.
  ls_cobl-kostl = '0000004200'.  " previous KOSTL = '0000004140'
  MODIFY lt_cobl FROM ls_cobl INDEX 1.

  ld_method = 'SET_COBL'.  " setter method
  CALL METHOD lo_obj_2->(ld_method)
    EXPORTING
      im_cobl = lt_cobl.

  " NOTE: Afterwards method IF_EX_ME_PROCESS_REQ_CUST~PROCESS_ACCOUNT
  "       is called. At same point the the process flow
  " the iteration counter is increased.
  " And then this method (PROCESS_ITEM) is called again. Therefore, we check that
  " IM_COUNT = 1.


ENDMETHOD.

An explanation may follow later or will be added to the Wiki posting.

Regards

Uwe

11 REPLIES 11

uwe_schieferstein
Active Contributor
0 Kudos

Hello

Unfortunately I currently do not have time to "dig" into this problem.

However, you may have a look at my Wiki posting

[Accessing the Inacessible - Local Classes within Global Classes|https://wiki.sdn.sap.com/wiki/display/ABAP/AccessingtheInacessible-LocalClasseswithinGlobalClasses]

which might be useful for you.

Regards

Uwe

0 Kudos

Hi Uwe,

I'm glad you come to my post

Indeed I've been trying your trick from your blog, casting the context object to a local root object then accessing the State.

However, in my case, since the attribute is protected, the Assign returns a sy-subrc EQ 4, unless my wording is wrong, which I hope.

What makes me mad is that I can modify my value using the debugger, but I can't find a way to do it throught code. Should I debug the debugger to see how it does ?

Or maybe you have any clue on modifying an account assignment, here FISTL in EXBN, when a field on the item is modified ? Unfortunately, method Process_Account only ticks when Account Assignment Category (KNTTP) is modified, or a field in the coding block, not from an item modification.

Regards,

N H

0 Kudos

Oh, one track I've tried to follow is to use the methods provided with the local class lcl_acct_container, such as get_exkn, set_exkn, get_cobl and set_cobl.

However, set_exkn is not implemented, and while using set_cobl I've ended up into an infinite loop. Some standard variable tries to know if there's any error. If so, it re-checks again the item, endlessly. And it has found my modification raises an error, but I couldn't figure out which one.

In addition to your blog, in a similar manner, this wording works too :


  DATA: vl_lcl_req_item_state TYPE REF TO lcl_req_item_state.

  vl_lcl_req_item_state = me->my_state.

At least in the debugger, If I move throught the attributes and modify at the end FISTL, it then appears on the screen.

The only difference is that my local object is declared as a ref to the locally defined class lcl_req_item_state. And I'm not using ?= but simply =.

I guess then Assign is used to acces attributes defined as tables or variables, not Ref To.

uwe_schieferstein
Active Contributor
0 Kudos

Hello

The coding shown below changes the cost center (KOSTL) of an item if the requisitioner is changed and contains the string 'us'. The reason why I did not test this with FISTL is because I did not have a suitable PO req available.

Disclaimer: I did not save the changed PO and did not check whether anything was changed in a proper manner because I have little experience with PO reqs.

BAdI ME_PROCESS_REQ_CUST (interface IF_EX_ME_PROCESS_REQ_CUST) -> create implementation and corresponding class:


METHOD if_ex_me_process_req_cust~process_item.
  DATA:
    ld_attr         TYPE string,
    ld_method       TYPE string,
    lo_obj          TYPE REF TO object,  " root object
    lo_obj_2        TYPE REF TO object.

  DATA: lt_cobl     TYPE STANDARD TABLE OF cobl,
**        lt_cobl_add type STANDARD TABLE OF meaccadd,
        ls_cobl     TYPE cobl.


  FIELD-SYMBOLS:
    <lo_lcl>        TYPE ANY,
    <lo_lcl_2>      TYPE ANY,
    <ld_afnam>      TYPE ANY,
    <ls_item>       TYPE mereq_item,
    <ls_itemx>      TYPE mereq_itemx.


  break-point.
  CHECK ( im_count = 1 ).  " avoid endless iteration -> see NOTE below

  lo_obj     ?= im_item.  " casting to root object !!!!!

  ld_attr = 'MY_STATE'.
  ASSIGN lo_obj->(ld_attr) TO <lo_lcl>.

  ld_attr = 'MY_STATE->ITEM'.
  ASSIGN lo_obj->(ld_attr) TO <ls_item>.
  "    ASSIGN l_item_ref->(ld_attr) TO <ls_item>.  " does not work...
*
  ld_attr = 'MY_STATE->ITEMX'.
  ASSIGN lo_obj->(ld_attr) TO <ls_itemx>.

  " Check change indicator for requisitioner
  ASSIGN COMPONENT 'AFNAM' OF STRUCTURE <ls_itemx> TO <ld_afnam>.
  CHECK ( <ld_afnam> = 'X' ).

  " Get account container instance
  ld_attr = 'MY_STATE->ACCT_CONTAINER'.
  ASSIGN lo_obj->(ld_attr) TO <lo_lcl_2>.
  lo_obj_2 = <lo_lcl_2>.



  " Get requisitioner
  ASSIGN COMPONENT 'AFNAM' OF STRUCTURE <ls_item> TO <ld_afnam>.
  CHECK ( <ld_afnam> CS 'us' ).

  " Condition: if requisitioner was changed and contains 'us' string
  "            then set KOSTL = '4200'

  ld_method = 'GET_COBL'.  " getter method
  CALL METHOD lo_obj_2->(ld_method)
    IMPORTING
      ex_cobl = lt_cobl.

  READ TABLE lt_cobl INTO ls_cobl INDEX 1.
  ls_cobl-kostl = '0000004200'.  " previous KOSTL = '0000004140'
  MODIFY lt_cobl FROM ls_cobl INDEX 1.

  ld_method = 'SET_COBL'.  " setter method
  CALL METHOD lo_obj_2->(ld_method)
    EXPORTING
      im_cobl = lt_cobl.

  " NOTE: Afterwards method IF_EX_ME_PROCESS_REQ_CUST~PROCESS_ACCOUNT
  "       is called. At same point the the process flow
  " the iteration counter is increased.
  " And then this method (PROCESS_ITEM) is called again. Therefore, we check that
  " IM_COUNT = 1.


ENDMETHOD.

An explanation may follow later or will be added to the Wiki posting.

Regards

Uwe

0 Kudos

Wow...! Simply Wow !!

That's worked !

It definitively looks like a bug exploit, but I'm very impressed by your technique.

I'll clarify my implementation and I will post that back.

Some days ago, I put some coding earlier on in the stack using an enhancement before the call to the BAdI. I did that because there I have access to the local implementation of local_item and local_account_container. I may try to implement your solution there too to see if there are any differences.

Thx a lot !

N H

PS: I still have a concern about the parameter IM_COUNT of the method Process_Item. With my enhancement, I've found out that somehow while using the method SET_COBL, standard code that calls the BAdI thinks that there's some error in the PR. An internal object attribute is set to Error_Found and then the PR is re-check and the BAdI re-processed. This starts the endless loop. I'm not really confident what the iteration count is used for...

0 Kudos

Hello

That's why I added the disclaimer (as SAP did at any presentation at the TechED in Berlin)...

Regards

Uwe

0 Kudos

Thx Uwe for you trick, it's such a valuable one

I won't have time to set my case right and post it here. Furthermore, comments wouldn't be in english as well.

Anyway, your blog and your post are sufficient, I guess.

Thx again !

N H

0 Kudos

NH,

I need to change cobl-aufnr in ME51N transaction and i'm using badi ME_PROCESS_REQ_CUST, method CHECK.

After methods: get_data, get_item, get_cobl, ... set_cobl, set_exkn, update doesn't work well. It's because MY_STATE->PROTECT has value 'X'.

How can I resolve this?

Thanks. Best Regards!

0 Kudos

Hi Uwe,

I have used this BAdI and the user wants to update the customer field of Delivery tab in ME51N according to the

WBS Element filled by the user in account assignment tab (Both the tabs are at item level). I am getting the data to be placed in customer field but unable to set the value in customer field. I have mentioned code below, I am updating the customer field through field symbol.


METHOD IF_EX_ME_PROCESS_REQ_CUST~PROCESS_ITEM.

  DATA: LS_ITEM TYPE MEREQ_ITEM.
  DATA: GET_ITEM TYPE MMPUR_ACCOUNTING_LIST.
  DATA: GET_ITEMX TYPE EXKN.
  DATA : L_MEPO_DOC TYPE MEPO_DOCUMENT.
  DATA : L_PSPNR TYPE EXKN-PS_PSP_PNR.
  DATA: GT_VBAP TYPE VBAP.
  DATA: GT_VBPA TYPE VBPA.
  DATA: L_KUNNR TYPE VBPA-KUNNR.
  DATA: L_MEREQ_ITEM TYPE MEREQ_ITEM.


  BREAK IDMCABAP.
  CHECK ( IM_COUNT = 1 ).

  CALL METHOD IM_ITEM->IF_ACCT_CONTAINER_MM~GET_DATA
  IMPORTING
*    EX_AUFPL_ORD  =
*    EX_APLZL_ORD  =
*    EX_VBELN      =
*    EX_VBELP      =
*    EX_VETEN      =
      EX_PS_PSP_PNR = L_PSPNR
      .
  DATA : FVAR(256).
  FIELD-SYMBOLS : <VAR> TYPE ANY.
  DATA EX_DAT TYPE MEREQ_ITEM.
  DATA FLAG TYPE MEREQ_ITEMX.

  IF L_PSPNR IS NOT INITIAL.
    SELECT SINGLE * FROM VBAP INTO GT_VBAP WHERE PS_PSP_PNR = L_PSPNR.
    IF SY-SUBRC = 0.
      SELECT SINGLE * FROM VBPA INTO GT_VBPA WHERE VBELN = GT_VBAP-VBELN
        AND PARVW = 'WE'.
      IF SY-SUBRC = 0.
* SAPLMMDA SAPLMEGUI  CMMDA-KUNNR
        FVAR = '(SAPLMMDA)CMMDA-KUNNR'.
        ASSIGN (FVAR) TO <VAR>.
        IF SY-SUBRC = 0.
          <VAR> = GT_VBPA-KUNNR.

*        CALL METHOD IM_ITEM->GET_DATA
*          RECEIVING
*            RE_DATA = LS_ITEM.
*
*        LS_ITEM-KUNNR = GT_VBPA-KUNNR.
*        LS_ITEM-ADRNR = GT_VBPA-ADRNR.
**        EX_DAT-KUNNR = GT_VBPA-KUNNR.
*
*        CALL METHOD IM_ITEM->SET_DATA
*          EXPORTING
*            IM_DATA = LS_ITEM.

*        FLAG-KUNNR = 'X'.
*        CALL METHOD IM_ITEM->SET_DATAX
*          EXPORTING
*            IM_DATAX = FLAG.

        ENDIF.
*    IF SY-SUBRC EQ 0.
*      T_TFKKOPK = <TAB>.
*      LOOP AT T_TFKKOPK INTO WA WHERE PRCTR IS NOT INITIAL.
*        WA-KOSTL = WA-PRCTR.
*        MODIFY T_TFKKOPK FROM WA TRANSPORTING KOSTL.
*      ENDLOOP.
*      CLEAR <TAB>.
*        <TAB> = GT_VBPA-KUNNR.


*        L_MEREQ_ITEM-KUNNR = GT_VBPA-KUNNR.
*        L_MEREQ_ITEM-ADRNR = GT_VBPA-ADRNR.
*
*        IM_ITEM->SET_DATA( L_MEREQ_ITEM ).
*          EXPORTING
*            IM_DATA = L_MEREQ_ITEM.

      ENDIF.
    ENDIF.
  ENDIF.
ENDMETHOD.

Former Member
0 Kudos

hi N H,

you cannot direcltly access a protcted attribute .

you can access private attribute only in the method of that class or threw method of inheriting class .

and then object of that class can call its method .

Regards.

Punit

former_member602116
Participant
0 Kudos

Hi,

I have a similar problem where I need to change a value in a custom field from EBKN, however I am unable to do so as my_state->protect is equal to 'X'. How was this problem solved? Thank you.