Update itab from another itab? - abap

My program simply put the locks on users if the 'LOCK' checkbox is selected.
Everything works and the users records are updated in the USR02. When this change occurs I want that it also be reflected in IT_USR02, i.e. DB table USR02 and itab it_usr02 should be identical.
SELECT-OPTIONS: USER_ID FOR USR02-BNAME.
START-OF-SELECTION.
SELECT BNAME
USTYP
UFLAG
FROM USR02
INTO TABLE IT_USR02
WHERE BNAME IN USER_ID.
LOOP AT IT_USR02 INTO ST_USR02.
IF LOCK = 'X'.
CALL FUNCTION 'BAPI_USER_LOCK'
EXPORTING
USERNAME = ST_USR02-BNAME
TABLES
RETURN = I_BAPI_RETURN.
MOVE-CORRESPONDING IT_USR02[] TO IT_ZATO_LOCK_UNLOCK[].
MODIFY ZATO_LOCK_UNLOCK FROM TABLE IT_ZATO_LOCK_UNLOCK.
ENDIF.
ENDLOOP.
Essentially after BAPI_USER_LOCK function is called I want that change to be made in the IT_USR02 table as well. From there I copy the contents of IT_USR02 to my custom table ZATO_LOCK_UNLOCK.
Everything here seems to work fine I just can't figure out how to update my internal table. Any help would be appreciated.

If I understand your problem correctly then something like this is what you need:
LOOP AT IT_USR02 ASSIGNING FIELD-SYMBOL(<USR02>).
" Using field symbol for performance and so the entry can be changed
IF LOCK = 'X'.
CALL FUNCTION 'BAPI_USER_LOCK'
EXPORTING
USERNAME = ST_USR02-BNAME
TABLES
RETURN = I_BAPI_RETURN.
IF "All is OK in I_BAPI_RETURN
" Change the table entry
<USR02>-UFLAG = 32. " Not sure if this is the right value
ENDIF.
ENDIF.
ENDLOOP.
" This needs to be outside the loop since you are handling the complete table
MOVE-CORRESPONDING IT_USR02[] TO IT_ZATO_LOCK_UNLOCK[].
MODIFY ZATO_LOCK_UNLOCK FROM TABLE IT_ZATO_LOCK_UNLOCK.
" A commit work might be needed here
Note that you still need to code the condition to check if all was OK with the BAPI call. I am not familiar with the BAPI so do not know if no entries is good news or if you need to check if there are any errors in the returned table.

Related

Trying to fill empty fields by using IS INITAL

I am trying to update a certain part of the code, where the code is shown below.
READ TABLE lt_cc_data ASSIGNING <ls_cc_data>
WITH KEY qmnum = ls_refferal-qmnum.
IF <ls_cc_data>-pruef is INITAL. *>>>>>Statement that I added
IF sy-subrc IS INITIAL.
<ls_cc_data>-pruef = <ls_ccicons>-icon_id.
ENDIF.
ENDIF.
Before entering the statement that I have shown in the code, the program would enter in each qnum = ls_refferal-qmnum and fill the pruef field, however it did not take into account the cases when the qnum had the same values throughout the table. What I try to did is filling the pruef field only in those cases when the field is empty.
Being that I cannot test it due to lack of data in the development system, is the logic behind my solution correct and if not can someone give me an similar solution?
Thank you all in advance!
EDIT
The code would look like this now:
READ TABLE lt_cc_data ASSIGNING <ls_cc_data>
WITH KEY qmnum = ls_refferal-qmnum.
IF <ls_cc_data>-pruef is INITAL. *>>>>>Statement that I added
<ls_cc_data>-pruef = <ls_ccicons>-icon_id.
ENDIF.

Flatten/Unify Table Rows where criteria matches array with ABAP or SQL

I am trying to achieve flattening a table into an array (or structure). My implementation is in SAP ABAP; however, I believe the question is code agnostic. I am wondering if there is an algorithm I'm not aware of or simple solution for what I'm trying to achieve. I will accept any language or pseudocode as an acceptable answer.
I am selecting from a "User Restrictions" (i.e., lt_restrictions) table stored on a database, e.g.:
This is needed for an SAP BSP MVC web app. When the app loads, I am doing user authorization checks to populate a "User Roles" (i.e., mt_user_roles) local table/array (i.e., attribute on an MVC model class).
The authorization checks involve routine ABAP -- using IF statements to conditionally populate the "User Roles" table, e.g.:
AUTHORITY-CHECK OBJECT 'PROGRAM_MANAGER_AUTH' ID 'xxx' FIELD 'yyy'.
IF ( sy-subrc = 0 ).
APPEND VALUE #( low = 'program_manager' ) TO me->mt_user_roles.
ENDIF.
If the user has both e.g., program manager AND entry user authorizations, this "User Roles" table/array would look like this:
With the two tables above, if the user has program manager and entry user roles, the only restriction is convert; therefore, I need to populate a "Restriction List" (i.e., ms_restrictions) like the following:
Otherwise, if the user has e.g., only the entry user role:
...
...there are 2 restrictions (release AND convert), so I would need to populate a "Restriction List" (i.e., ms_restrictions) like this:
I feel like there is a standard algorithm I could use or perhaps this could be done with SQL in a SELECT statement with my database table WHERE restriction = NULL (e.g., WHERE save = ' ') or using a SELECT ... WHERE x IN clause, perhaps, if the "Restrictions List" was a RANGE table?
I should mention, I already have an undesirable, partial solution which involves looping through the database table and having several IF statements for each restriction condition. "Restriction List" is named ms_restrictions, it is a class attribute ABAP STRUCTURE type (for ABAP newbies, this is basically a 1-D sized array):
LOOP AT lt_restrictions INTO DATA(ls_restriction).
LOOP AT mt_user_roles INTO DATA(ls_user_role).
"Check save restriction
IF (
ls_restriction-role = ls_user_role-role AND
ls_user_role = 'save'
).
ms_restrictions-save = 'x'.
ENDIF.
"Check release restriction
IF (
ls_restriction-role = ls_user_role-role AND
ls_user_role = 'release'
).
ms_restrictions-release = 'x'.
ENDIF.
"Check other restrictions
"......
ENDLOOP.
ENDLOOP.
The problem with the solution above is I have to write an IF statement for each restriction. More so, it doesn't take into account whether there are conflicts between 2 or more role restrictions, e.g., program manager has only 1 restriction while entry user has 2. My logic above could be extended to take this into account with -- well -- even more IF statements :-( .. I'm wondering if there's a different approach I can take?
Also, I should mention. The resulting "Restrictions List", i.e., mt_restrictions, is needed in my view for disabling HTML buttons, e.g.:
<button value = 'Save' disabled = '//model/mt_restrictions-save' />
<button value = 'Release' disabled = '//model/mt_restrictions-release' />
<button value = 'Convert' disabled = '//model/mt_restrictions-convert' />
<button ... />
A solution I came up with involves using ABAP <FIELD-SYMBOL>s data-types and an OpenSQL FOR ALL ENTRIES IN SELECT statement addition.
By using <FIELD-SYMBOL>s, you can avoid any hardcoded attribute and/or structure component names. Now, the restriction rules can grow without having to future modify any code.
By using FOR ALL ENTRIES IN, you can sync your Roles table with your Restrictions table. Adding this clause allows you to SELECT from your transparent Role/Restrictions database table INTO a table, only including the roles applicable from the roles found in the AUTH-CHECK (because mt_user_roles populates a new row for each true AUTH-CHECK).
The method is_standard_user( ) is where the AUTH-CHECKs occur. If it equals ABAP_TRUE, then all restrictions are applied -- assuming the ms_restrictions structure components' values all default to ABAP_TRUE.
Dynamically looping through each structure component of ms_restrictions, you can READ the restrictions table for corresponding value. If value equals SPACE, then this means the current row doesn't have a restriction. So mark the structure component value to SPACE (because it may have been marked ABAP_TRUE in a prior iteration) -- this addresses the "conflicting roles issue".
"perform authorization checks
IF ( NOT me->is_standard_user( ) ).
"see if roles found
IF ( lines( me->mt_user_roles ) > 0 ).
"find pertaining restrictions for roles found in auth checks
SELECT
*
FROM
zmm_apr_roles
FOR ALL ENTRIES IN "select only rows applicable to auth-check
#me->mt_user_roles
WHERE
role = #me->mt_user_roles-role
INTO TABLE
#DATA(lt_restrictions).
"dynamically populate restriction list from multi-role restriction table
DATA: lr_descr_struc TYPE REF TO data.
DATA: lo_structdescr TYPE REF TO cl_abap_structdescr.
CREATE DATA lr_descr_struc LIKE ms_restrictions.
lo_structdescr ?= cl_abap_structdescr=>describe_by_data_ref( p_data_ref = lr_descr_struc ).
LOOP AT lo_structdescr->components ASSIGNING FIELD-SYMBOL(<lv_component>).
ASSIGN COMPONENT <lv_component>-name OF STRUCTURE ms_restrictions TO FIELD-SYMBOL(<lv_field>).
IF ( <lv_field> IS ASSIGNED ).
"non-restricted value overwrites restricted value
READ TABLE lt_restrictions WITH KEY (<lv_component>-name) = space TRANSPORTING NO FIELDS.
IF ( sy-subrc = 0 ).
<lv_field> = space.
ENDIF.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.
To add a new restriction, all that needs to be done is:
add new roles to zmm_apr_roles and the corresponding data-dictionary components
add new restrictions to corresponding components of ms_restrictions

BAPI/FM to search prod orders confirmations by workcenter and date?

I'm trying to figure out which BAPI/FM I could use to search amounts confirmed based on search criteria of date (+time if possible) and workcenter confirmed where was confirmed...
I would be using BAPI_PRODORDCONF_GETDETAIL which contains these informations, but according to BAPI guide I can only load in the data of confirmation number+confirmation counter.
Therefore the option would be to run BAPI_PRODORDCONF_GETLIST (but I can only input the production order range or confirmation number range), then filter what includes the workcenter and date I need and from those pick up confirmation number+counter and run it through BAPI_PRODORDCONF_GETDETAIL.
but this procedure of getting list of everything without data being filtered on serverside is extemly timeconsuming and out of SAP Gui I have timeout error... therefore I need any BAPI/FM which I could input the workcenter where was confirmed and date, and have the data filtered already...
Any ideas how to do that?
As far as I know there is no such standard FM, so your only choice is custom development.
I would suggest you MCPK transaction were this info is exposed in a handy form, but as I see that your requirement is to receive this info externally this is not appropriate for you.
The confirmations reside in AFRU table and workcenters are in CRHD, so to find confirmed quantities by workcenter you should join these tables, or use a view u_15673 where this info is linked:
TYPES: BEGIN OF prod_orders,
rueck TYPE afru-rueck, "confirmation number
rmzhl TYPE afru-rmzhl," confirmation counter
gmnga TYPE afru-gmnga, " quantity
arbid TYPE crhd-arbpl, " workcenter
END OF prod_orders.
DATA: orders TYPE TABLE OF prod_orders.
SELECT *
FROM u_15673
INTO CORRESPONDING FIELDS OF TABLE orders
WHERE isdd >= '20180101' AND isdz <= '163000'.
To pull this externally, you must create RFC-enabled FM or use RFC_READ_TABLE and fetch this view with parameters, here is the sample.
Another approach is to use RFC_ABAP_INSTALL_AND_RUN. You must create an ABAP program that uses WRITE for output the results as a standard list to screen.
Send the lines of this program to RFC_ABAP_INSTALL_AND_RUN to PROGRAM parameter and the code will be executed on the remote system and this FM will return screen results as the lines of table WRITES.
Possible sample based on MCPK tcode to send to RFC_ABAP_INSTALL_AND_RUN:
CLEAR lwa_selection.
lwa_selection-selname = 'SL_SPTAG'.
lwa_selection-sign = 'I'.
lwa_selection-option = 'BT'.
lwa_selection-low = '20180101'.
lwa_selection-high = '20201231'.
APPEND lwa_selection TO li_selection.
CLEAR lwa_selection.
lwa_selection-selname = 'SL_ARBPL'.
lwa_selection-sign = 'I'.
lwa_selection-option = 'EQ'.
lwa_selection-low = '10400001'.
APPEND lwa_selection TO li_selection.
SUBMIT rmcf0200 WITH SELECTION-TABLE li_selection
with par_stat = abap_true
EXPORTING LIST TO MEMORY
AND RETURN.
DATA: xlist TYPE TABLE OF abaplist.
DATA: xtext TYPE TABLE OF char200.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
listobject = xlist.
CALL FUNCTION 'LIST_TO_TXT'
EXPORTING
list_index = -1
TABLES
listtxt = xtext
listobject = xlist.
IF sy-subrc = 0.
LOOP AT xtext ASSIGNING FIELD-SYMBOL(<text>).
WRITE <xtext>.
ENDLOOP.
ENDIF.
However, this approach is not flexible because MCPK standard layout is a bit different than you want, and is not easy to adjust programmatically.
Because of that I recommend to stick to the RFC_READ_TABLE approach.

ALV report fill gap between documents

I was trying to challenge myself to make an ALV report that displays all the data by company code. but some document number has a gap.
I want to fill the gap between missing number
For example:
last index value: 20012
then next value is: 20014
How do I able to insert 20013 in the grid if the report is using all the data that exist in internal tables?
Thanks.
This is just blind text typing, but I hope you are able to understand it ... should be quite simple. Dont expect complete code, unless your are not even providing ANY code.
DATA: lv_current type i,
lv_next type i.
SORT lt_internalTable by BUKRS ascending.
LOOP AT lt_internalTable into ls_internalTable.
MOVE sy-tabix to lv_current.
READ TABLE lt_internalTable into ls_tempinternalTable INDEX sy-tabix + 1.
MOVE sy-tabix to lv_next.
IF (lv_next - lv_current) > 1.
... do your stuff
ENDIF.
CLEAR: ls_internalTable, lv_current, lv_next.
ENDLOOP.

How to retrieve a specific field from a list output?

I don't have any developer rights in my SAP-System but I found a way to write some ABAP-Code in a tiny "User-Exit" box (I don't know if that's what you call it) inside a report.
I'm trying to submit a HR-Report and plug it's outcoming PERNR into that same report again.
There's a syntax-error that is telling me that t_list doesn't have a component with the Name PERNR.
What do I have to do in order to get this to work?
DATA: t_list TYPE TABLE OF abaplist WITH HEADER LINE,
seltab TYPE TABLE OF rsparams,
selline LIKE LINE OF seltab.
*I found out that the name of the selection field in the Report-GUI is "PNPPERNR" and tested it
selline-selname = 'PNPPERNR'.
selline-sign = 'I'.
selline-option = 'EQ'.
SUBMIT Y5000112
USING SELECTION-SET 'V1_TEST'
EXPORTING LIST TO MEMORY
AND RETURN.
CALL FUNCTION 'LIST_FROM_MEMORY'
TABLES
listobject = t_list
EXCEPTIONS
not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
WRITE 'Unable to get list from memory'.
ELSE.
LOOP AT t_list.
*The Problem is here: how do I get the pnppernr out of t_list, it's the first column of the report output
selline-low = t_list-pernr.
append selline to seltab.
ENDLOOP.
SUBMIT Y5000112
WITH SELECTION-TABLE seltab
USING SELECTION-SET 'V2_TEST'
AND RETURN.
ENDIF.
Use the function module LIST_TO_ASCI to decode the contents of t_list into something readable. This answer contains some sample code including the data types required. At this point, the data you're looking for will probably occur at the same column range in the output. Use the standard substring access methods - e. g. line+42(21) to obtain the part of the line you need.
The vwegert's answer is more than useful! In my previous answer I forgot to mention LIST_TO_ASCI FM :)
The only thing I can add is that parsing of result lines has no universal solution and greatly depends on its structure. Usually it is done like:
LOOP AT t_list.
SPLIT t_list AT '|' INTO <required_structure>.
selline-low = <required_structure>-pernr.
APPEND selline TO seltab.
ENDLOOP.
where <`required_structure> is your Y5000112 output structure. But this may be not so simple and may require additional manipulations.