How to get long text object change log programmatically? - abap

I have a requirement to fetch all changes that were made to a long text object.
From what I know, there is a program called S_AUT_REP10 where you can see the changes that were made to a long text in ALV but I can't seem to find how to extract this data in my code.
I know that the data is somehow stored in STXH, STXL and dbtablog for the changes but would really appreciate any help extracting the actual changes that were made to the long text.
Thank you.

You can check the datasource by pressing Start evaluation button in the left apper corner of the screen after triggering the report by your parameters.
It shows where the data comes from, in this case it is the STXH table by certain key
<client><obj>*<text_name>*<text_id>*
This key will be of great use when you will be fetching the DBTABLOG.
Recreation of the S_AUT_REP10-like query in the ABAP code will look like this
DATA: tabname TYPE aut_t_tabname_range
logkey TYPE aut_t_logkey_range
from_date LIKE sy-datum
from_time LIKE st-timlo.
APPEND INITIAL LINE TO tabname
ASSIGNING FIELD-SYMBOL(<fs_r_tabname>).
<ls_r_tabname>-sign = 'I'.
<ls_r_tabname>-option = 'CP'.
<ls_r_tabname>-low = 'STXH'.
APPEND INITIAL LINE TO logkey
ASSIGNING <ls_r_logkey>.
<ls_r_logkey>-sign = 'I'.
<ls_r_logkey>-option = 'CP'.
<ls_r_logkey>-low = '800TEXT*ZT_TB_PHSTF-PH110*ST*'.
from_date = '20211231'.
from_time = '235959'.
SELECT SINGLE logdate logtime logid FROM dbtablog "#EC *
INTO DATA(ls_dbtablog)
WHERE
logdate = from_date AND
logtime >= from_time AND
tabname IN tabname AND
logkey IN logkey.

Related

Date format from 2020.11.20 to 11/2020

I'm trying to change the date format from 2020.11.20 to 11/2020
My objective is to remove the day and leave just month/year.
If I change the type of the field EDATU from vbep-EDATU to string it doesn't work.
Any tips on how to achieve my goal?
DATA: GR_COLUMNS TYPE REF TO CL_SALV_COLUMNS_TABLE,
GR_TABLE TYPE REF TO CL_SALV_TABLE.
TYPES: BEGIN OF IT_STR,
EDATU TYPE VBEP-EDATU,
vbeln type vbep-vbeln,
END OF IT_STR.
DATA: IT_FINAL TYPE STANDARD TABLE OF IT_STR.
FIELD-SYMBOLS: <F_DAT> TYPE IT_STR.
SELECT EDATU vbeln FROM VBEP INTO TABLE IT_FINAL up to 10 rows.
LOOP AT IT_FINAL ASSIGNING <F_DAT>.
<F_DAT>-EDATU = <F_DAT>-EDATU+4(2) && '/' && <F_DAT>-EDATU(4).
ENDLOOP.
TRY.
CALL METHOD CL_SALV_TABLE=>FACTORY
EXPORTING
LIST_DISPLAY = IF_SALV_C_BOOL_SAP=>FALSE
IMPORTING
R_SALV_TABLE = GR_TABLE
CHANGING
T_TABLE = IT_FINAL.
CATCH CX_SALV_MSG .
ENDTRY.
GR_COLUMNS = GR_TABLE->GET_COLUMNS( ).
CALL METHOD GR_TABLE->DISPLAY.
Even though a type D is really just a char based data type of length 8 it has some special behavior when outputting it. If you check in the debugger you will see the data in IT_FINAL is what you want, it's just that the ALV processes this data as a date regardless of the value in it.
So, for example date 20221019 got changed in IT_FINAL-EDATU to '10/2022'. Now, when you display it in the ALV it gets interpreted as a date and gets displayed depending on your user settings, assuming yours are yyyy.mm.dd the output would be: '10/2.02.2'.
You can get around this in two ways:
Add a new field to your table with a char-like type to hold the month value as suggested by Skin, and suppress the display of the EDATU field in the ALV
gr_columns->get_column( columnname = 'EDATU' )->set_technical( abap_true ).
Change the behavior of the EDATU column in the ALV by changing the edit mask with:
gr_columns->get_column( columnname = 'EDATU' )->set_edit_mask('_______').
Option 1 is clearly the better way to avoid unintended mishaps in the future.
I created a new colum type C and changed the loop to
LOOP AT IT_FINAL ASSIGNING <F_DAT>.
data(month) = <F_DAT>-EDATU+4(2).
data(year) = <F_DAT>-EDATU(4).
<f_dat>-char = month && '/' && year.
ENDLOOP.
Thanks for everyone who helped me.

cmd_ei_api=>maintain_bapi to update kna1 table field (ICMSTAXPAY)

I have a requirement to update this field ICMSTAXPAY in KNA1 table using my custom report. So, I tried using cmd_ei_api=>maintain_bapi to update the table. But once I run the program, that particular field is not updated and I don't get any error messages too.
My logic:
Read the KNA1 entries.
Edit the required field to my value.
Pass mandatory data to HEADER for update.
Pass my new KNA1 entries to CENTRAL_DATA.
Read data from table:
CALL METHOD cmd_ei_api_memory=>get_global_kna1
EXPORTING
iv_kunnr = <lfs_final>-kunnr
IMPORTING
es_kna1_old = ls_old.
Change the value of field:
ls_old-icmstaxpay = 9.
MOVE-CORRESPONDING ls_old TO ls_customer-central_data-central-data.
Assign header data:
ls_customer-header-object_instance-kunnr = <lfs_final>-kunnr.
ls_customer-header-object_task = 'U'.
Add all the above to the master data structure:
APPEND ls_customer TO lt_customers[].
ls_master_data-customers = lt_customers[].
Pass the data and update to table:
cmd_ei_api=>initialize( ).
LOOP AT lt_customers INTO ls_customer.
cmd_ei_api=>lock( iv_kunnr = ls_customer-header-object_instance-kunnr ).
ENDLOOP.
" Update Customer with CMD_EI_API
CALL METHOD cmd_ei_api=>maintain_bapi
EXPORTING
iv_test_run = space
is_master_data = ls_master_data
IMPORTING
es_message_defective = ls_message_defective.
IF ls_message_defective IS INITIAL.
BREAK-POINT.
COMMIT WORK.
ELSE.
BREAK-POINT.
ENDIF.
LOOP AT lt_customers INTO ls_customer.
cmd_ei_api=>unlock( iv_kunnr = ls_customer-header-object_instance-kunnr ) .
ENDLOOP.
When I debug, I can see that the entry that is being fetched for update is the old entry that is present in the current memory.
Please let me know if i am doing something wrong while passing the value to the table.
You need including DATAX with X for all fields that you need change.
DATA: ls_datax TYPE cmds_ei_vmd_central_data_xflag.
ls_datax-icmstaxpay = 'X'.
MOVE ls_datax TO ls_customer-central_data-central-datax.
And thanx for your question, helped me with find this methody :)

ITXEX field cleared when HR_INFOTYPE_OPERATION is called

We got into difficulties in maintaining the ITXEX field (Long text indication) of an Infotype record.
Say we got an existing record in an Infotype database table with a long text filled (ITXEX field value in that record is set to 'X').
Some process updates the record through HR_CONTROL_INFTY_OPERATION like this:
CALL FUNCTION 'HR_CONTROL_INFTY_OPERATION'
EXPORTING
infty = '0081'
number = '12345678'
subtype = '01'
validityend = '31.12.9999'
validitybegin = '19.05.2019'
record = ls_0081 " ( ITXEX = 'X' )
operation = 'MOD'
tclas = 'A'
nocommit = abap_true
IMPORTING
return = ls_return.
This call does update the record but clearing it's ITXEX field.
It's important to say that making the same action through PA30 does update the record and maintain ITXEX field as it was.
The described problem seems similar to that question. Trying the solutions given there didn't solve the problem.
Why the two approaches (PA30 and function module) don't work the same? How to fix this?
First of all, FM parameters you use are incorrect. How do you want the infotype to be updated if you set nocommit = TRUE?
Also, you are missing the correct sequence which must be used for the update procedure:
Lock the Employee
Read the infotype
Update the infotype
Unlock the Employee
The correct snippet for your task would be
DATA: ls_return TYPE bapireturn1.
DATA: l_infty_tab TYPE TABLE OF p0002.
CALL FUNCTION 'HR_READ_INFOTYPE'
EXPORTING
pernr = '00000302'
infty = '0002'
TABLES
infty_tab = l_infty_tab.
READ TABLE l_infty_tab ASSIGNING FIELD-SYMBOL(<infotype>) INDEX 1.
<infotype>-midnm = 'Shicklgruber'. " updating the field of infotype
CALL FUNCTION 'ENQUEUE_EPPRELE'
EXPORTING
pernr = '00000302'
infty = '0002'.
CALL FUNCTION 'HR_CONTROL_INFTY_OPERATION'
EXPORTING
infty = <infotype>-infty
number = <infotype>-pernr
subtype = <infotype>-subty
validityend = <infotype>-endda
validitybegin = <infotype>-begda
record = <infotype>
operation = 'MOD'
tclas = 'A'
IMPORTING
return = ls_return.
CALL FUNCTION 'DEQUEUE_EPPRELE'
EXPORTING
pernr = '00000302'
infty = '0002'.
This way itxex field is treated correctly and if existed on that record, will remain intact. However, this method will not work for updating the long text itself, for that you must use object-oriented way, methods of class CL_HRPA_INFOTYPE_CONTAINER.

Change field length afterwards

TABLES: VBRK.
DATA: BEGIN OF it_test,
BUKRS LIKE VBRK-BUKRS,
FKDAT LIKE VBRK-FKDAT,
END OF it_test.
DATA: wa_test LIKE it_test.
SELECT * FROM VBRK INTO CORRESPONDING FIELD OF wa_test.
IF wa_test-BUKRS = 'xxxx'.
wa_test-BUKRS = 'XXXXX' "Problem occurs here as the BUKRS allow 4 value
APPEND wa_test TO it_test.
ENDIF.
Then I want to map the internal table to output as ALV table. Is they any way to change the field length afterwards?
Apart from multiple issues in your code, you can't. If you need something similar to that, add an additional field to the structure with whatever size you require and copy the values over.
If the objective is to output something to the screen that is different(or differently formatted) that what is stored internally(or in the database), then the use of a data element with a conversion exit maybe the way to go.
For an example, look at the key fields of table PRPS.
Expanding the answer of vwegert:
The MOVE-CORRESPONDINGcommand (and SELECT ... INTO CORRESPONDING FIELDS) don't need the same field type. The content is converted. So you could define a 5-character field in your internal structure and copy the BUKRS-value into this 5-character field:
TABLES: VBRK.
DATA: BEGIN OF it_test,
BUKRS(5), "longer version of VBRK-BUKRS,
FKDAT LIKE VBRK-FKDAT,
END OF it_test.
DATA: tt_test TYPE STANDARD TABLE OF it_test.
* I would strongly recommend to set a filter!
SELECT * FROM VBRK INTO CORRESPONDING FIELD OF it_test.
IF it_test-BUKRS = 'xxxx'.
it_test-BUKRS = 'XXXXX'.
APPEND it_test to tt_test.
ENDIF.
ENDSELECT.
A pitfall: When you use it with ALV you will loose the field description. (on the other side, the field description of the original field will not fit any longer the new field.)

Error DBIF_RSQL_INVALID_RSQL CX_SY_OPEN_SQL_DB in program

I get the following error: DBIF_RSQL_INVALID_RSQL CX_SY_OPEN_SQL_DB (Open SQL command is too big. Condition WHERE of the Open SQL command contains too many conditions). The error points to the following line:
select * from Z3T_MAILS into table t_full_mail UP TO 250 ROWS where ID in r_mid and (p_dat_clause).
Other parts of code:
DATA: p_dat_clause type STRING,
t_full_mail type Z3TT_MAILS,
r_mid type range of Z3E_MAIL_ID.
<...>
if not NOT_READED is initial.
p_clause = 'ISREAD = '''''.
endif.
if DATETO is initial.
p_dateto = DATEFROM.
else.
p_dateto = DATETO.
endif.
if not DATEFROM is initial or not DATETO is initial.
concatenate 'SEND_DATE >= ''' DATEFROM ''' and SEND_DATE <= ''' p_dateto '''' into p_dat_clause.
endif.
<...>
if MAILS is supplied or BODY is supplied or p_dat_clause ne ''.
if not r_mid[] is initial.
select * from Z3T_MAILS into table t_full_mail UP TO 250 ROWS where ID in r_mid and (p_dat_clause).
endif.
endif.
I am new to ABAP and would appreciate any help!
That error happens when you use a range/select-option that has too many entries for the database to handle. The solution to this is always dependent on the use, but in any case you have to limit the number of entries in the range.
In your case you only want up to 250 rows from the database anyway. So, if R_MID is filled with all rows containing a single ID you can check the number of lines in it (LINES( R_MID ) ) and limit it to 250 if there are more than that. In most systems this would get rid of the error.
I'm just guessing here but your range r_mid probably has hundreds of lines that look like this:
r_mid-sign = 'I'.
r_mid-option = 'EQ'.
r_mid-low = '123123123'.
r_mid-high = ''.
So instead you could store those IDs in an internal table. You even might be able to use the internal table you're looping over to fill r_mid in the first place.
Your date variables on the other hand are actually well suited to be declared as a single range:
r_date-sign = 'I'.
r_date-option = 'BT'.
r_date-low = datefrom.
r_date-high = dateto.
Also note the documentation about ranges.
Finally you can write your query as follows:
SELECT *
FROM z3t_mails
INTO TABLE t_full_mail
FOR ALL ENTRIES IN lt_mid
WHERE id EQ lt_mid-id
AND send_date IN r_date.