上次在《创建自定义表的日志》里聊了如何记录日志,今天聊聊自定义维护视图如何记录修改日志。
一、首先为表创建一个SCDO对象ZSD001
二、然后在SE11创建完维护视图,并为其创建视图的维护程序
之后为视图创建事件
创建如下两个事件
01事件是在保存前记录日志,02事件更新数据库
通用示例代码如下,直接copy了放进去即可,但是我调试的时候总是有问题,逻辑是动态取视图中的表所对应的SCDO对象,通过执行动态程序来更新数据。有兴趣的同学可以调试下
*&----------------------------------------------------------------*
*& Form F_BEFORE_SAVE
*&----------------------------------------------------------------*
FORM f_before_save ##CALLED.
TYPES: BEGIN OF ty_tcdrp,
object TYPE cdobjectcl,
reportname TYPE cdreport,
END OF ty_tcdrp,
BEGIN OF ty_view_tab,
object TYPE cdobjectcl,
tabname TYPE cdtabname,
END OF ty_view_tab.
DATA: lt_ptab TYPE STANDARD TABLE OF string,
lv_prog TYPE string,
lv_mess TYPE string,
lv_sid TYPE string,
lt_obj TYPE STANDARD TABLE OF ty_view_tab,
lt_tcdrp TYPE STANDARD TABLE OF ty_tcdrp,
lv_fugn TYPE funct_pool,
lv_table TYPE cdtabname,
lv_namesfunc TYPE namespace,
lv_funcgroup TYPE progname,
lv_namesprog TYPE namespace,
lv_program TYPE progname,
lrt_tabname TYPE RANGE OF tabname,
lt_dd26v TYPE TABLE OF dd26v,
lv_object TYPE cdobjectcl.
" Get tabnames
" DD: Interface for reading a view from the ABAP/4 Dictionary
CALL FUNCTION 'DDIF_VIEW_GET'
EXPORTING
name = vim_view_name
TABLES
dd26v_tab = lt_dd26v
EXCEPTIONS
illegal_input = 1
OTHERS = 2.
IF sy-subrc IS NOT INITIAL.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
IF lt_dd26v IS INITIAL.
APPEND INITIAL LINE TO lrt_tabname ASSIGNING FIELD-SYMBOL(<lrs_tabname>).
<lrs_tabname>-sign = 'I'.
<lrs_tabname>-option = 'EQ'.
<lrs_tabname>-low = vim_view_name.
ELSE.
SORT lt_dd26v BY tabname.
DELETE ADJACENT DUPLICATES FROM lt_dd26v COMPARING tabname.
"*-
LOOP AT lt_dd26v INTO DATA(ls_dd26v).
APPEND INITIAL LINE TO lrt_tabname ASSIGNING <lrs_tabname>.
<lrs_tabname>-sign = 'I'.
<lrs_tabname>-option = 'EQ'.
<lrs_tabname>-low = ls_dd26v-tabname.
ENDLOOP.
ENDIF.
" Objects for change document creation
SELECT object tabname
FROM tcdob
INTO TABLE lt_obj
WHERE tabname IN lrt_tabname
##WARN_OK.
IF sy-subrc IS NOT INITIAL.
" No change document objects found
MESSAGE i899(cd).
RETURN.
ENDIF.
" Information on Include Reports Generated by RSSCD000
SELECT object reportname
FROM tcdrp
INTO TABLE lt_tcdrp
FOR ALL ENTRIES IN lt_obj
WHERE object EQ lt_obj-object
##WARN_OK.
IF sy-subrc IS NOT INITIAL.
" Update program does not yet exist
MESSAGE i446(m2).
RETURN.
ENDIF.
" View Directory
SELECT SINGLE area
FROM tvdir
INTO lv_fugn
WHERE tabname EQ vim_view_name.
"*-
LOOP AT lt_obj ASSIGNING FIELD-SYMBOL(<ls_obj>).
READ TABLE lt_tcdrp ASSIGNING FIELD-SYMBOL(<ls_tcdrp>)
WITH KEY object = <ls_obj>-object.
IF sy-subrc IS NOT INITIAL.
CONTINUE.
ENDIF.
" Split namespace
CLEAR: lv_namesprog, lv_program.
lv_program = <ls_tcdrp>-reportname.
CALL FUNCTION 'RS_NAME_SPLIT_NAMESPACE'
EXPORTING
name_with_namespace = lv_program
IMPORTING
namespace = lv_namesprog
name_without_namespace = lv_program
EXCEPTIONS
delimiter_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
lv_program = <ls_tcdrp>-reportname.
ENDIF.
CLEAR: lv_namesfunc, lv_funcgroup.
lv_funcgroup = lv_fugn.
CALL FUNCTION 'RS_NAME_SPLIT_NAMESPACE'
EXPORTING
name_with_namespace = lv_funcgroup
IMPORTING
namespace = lv_namesfunc
name_without_namespace = lv_funcgroup
EXCEPTIONS
delimiter_error = 1
OTHERS = 2.
IF sy-subrc <> 0.
lv_funcgroup = lv_fugn.
ENDIF.
" Namespace conversion
lv_object = <ls_obj>-object.
IF lv_object(1) = '/'.
SHIFT lv_object LEFT DELETING LEADING '/'.
REPLACE FIRST OCCURRENCE OF '/' IN lv_object WITH '_'.
ENDIF.
lv_table = <ls_obj>-tabname.
IF lv_table(1) = '/'.
SHIFT lv_table LEFT DELETING LEADING '/'.
REPLACE FIRST OCCURRENCE OF '/' IN lv_table WITH '_'.
ENDIF.
" Subroutine pool
APPEND ##NO_TEXT:
`PROGRAM SUBPOOL.` TO lt_ptab,
` INCLUDE ` && lv_namesprog && `F` && lv_program && `CDT.` TO lt_ptab,
` INCLUDE ` && lv_namesprog && `F` && lv_program && `CDC.` TO lt_ptab,
` FORM f_process.` TO lt_ptab,
` TYPES: BEGIN OF total.` TO lt_ptab,
` INCLUDE STRUCTURE ` && vim_view_name && `.` TO lt_ptab,
` INCLUDE STRUCTURE vimflagtab.` TO lt_ptab,
` TYPES: END OF total.` TO lt_ptab,
` FIELD-SYMBOLS: <fs_total> TYPE ANY TABLE,` TO lt_ptab,
` <fs_total_wa> TYPE total,` TO lt_ptab,
` <fs_x_namtab> TYPE ANY TABLE,` TO lt_ptab,
` <fs_x_namtab_wa> TYPE vimnamtab,` TO lt_ptab,
` <fs_field> TYPE any.` TO lt_ptab,
` DATA: lv_tabname(40) TYPE c VALUE '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)TOTAL[]',` TO lt_ptab,
` lv_cond_line TYPE string,` TO lt_ptab,
` lv_cond_line2 TYPE string.` TO lt_ptab,
` ASSIGN (lv_tabname) TO <fs_total>.` TO lt_ptab,
` LOOP AT <fs_total> ASSIGNING <fs_total_wa> CASTING.` TO lt_ptab,
` CASE <fs_total_wa>-action.` TO lt_ptab,
` WHEN 'U'. " Update` TO lt_ptab,
` lv_tabname = '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)X_NAMTAB[]'.` TO lt_ptab,
` ASSIGN (lv_tabname) TO <fs_x_namtab>.` TO lt_ptab,
` lv_cond_line2 = |keyflag EQ 'X' AND viewfield NE 'MANDT'|.` TO lt_ptab,
` LOOP AT <fs_x_namtab> ASSIGNING <fs_x_namtab_wa> WHERE (lv_cond_line2).` TO lt_ptab,
` ASSIGN COMPONENT <fs_x_namtab_wa>-viewfield OF STRUCTURE <fs_total_wa> TO <fs_field>.` TO lt_ptab,
` IF sy-subrc IS INITIAL.` TO lt_ptab,
` lv_cond_line = lv_cond_line && |AND | && ` TO lt_ptab,
` <fs_x_namtab_wa>-viewfield && | EQ '| && <fs_field> && |' |.` TO lt_ptab,
` objectid = objectid && <fs_field>.` TO lt_ptab,
` UNASSIGN <fs_field>.` TO lt_ptab,
` ENDIF.` TO lt_ptab,
` ENDLOOP.` TO lt_ptab,
` IF sy-subrc IS INITIAL.` TO lt_ptab,
` SHIFT lv_cond_line LEFT BY 3 PLACES.` TO lt_ptab,
` SELECT SINGLE *` TO lt_ptab,
` FROM ` && <ls_obj>-tabname TO lt_ptab,
` INTO *` && <ls_obj>-tabname TO lt_ptab,
` WHERE (lv_cond_line).` TO lt_ptab,
` MOVE-CORRESPONDING <fs_total_wa> TO ` && <ls_obj>-tabname && `.` TO lt_ptab,
` objectid = objectid.` TO lt_ptab,
` tcode = sy-tcode.` TO lt_ptab,
` udate = sy-datum.` TO lt_ptab,
` utime = sy-uzeit.` TO lt_ptab,
` username = sy-uname.` TO lt_ptab,
` cdoc_upd_object = 'U'.` TO lt_ptab,
` upd_` && lv_table && ` = 'U'.` TO lt_ptab,
` PERFORM cd_call_` && lv_object && `.` TO lt_ptab,
` ENDIF.` TO lt_ptab,
` WHEN 'N'. " New` TO lt_ptab,
` lv_tabname = '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)X_NAMTAB[]'.` TO lt_ptab,
` ASSIGN (lv_tabname) TO <fs_x_namtab>.` TO lt_ptab,
` lv_cond_line2 = |keyflag EQ 'X' AND viewfield NE 'MANDT'|.` TO lt_ptab,
` LOOP AT <fs_x_namtab> ASSIGNING <fs_x_namtab_wa> WHERE (lv_cond_line2).` TO lt_ptab,
` ASSIGN COMPONENT <fs_x_namtab_wa>-viewfield OF STRUCTURE <fs_total_wa> TO <fs_field>.` TO lt_ptab,
` IF sy-subrc IS INITIAL.` TO lt_ptab,
` objectid = objectid && <fs_field>.` TO lt_ptab,
` UNASSIGN <fs_field>.` TO lt_ptab,
` ENDIF.` TO lt_ptab,
` ENDLOOP.` TO lt_ptab,
` IF sy-subrc IS INITIAL.` TO lt_ptab,
` MOVE-CORRESPONDING <fs_total_wa> TO ` && <ls_obj>-tabname && `.` TO lt_ptab,
` objectid = objectid.` TO lt_ptab,
` tcode = sy-tcode.` TO lt_ptab,
` udate = sy-datum.` TO lt_ptab,
` utime = sy-uzeit.` TO lt_ptab,
` username = sy-uname.` TO lt_ptab,
` cdoc_upd_object = 'I'.` TO lt_ptab,
` upd_` && lv_table && ` = 'I'.` TO lt_ptab,
` PERFORM cd_call_` && lv_object && `.` TO lt_ptab,
` ENDIF.` TO lt_ptab,
` WHEN 'D'. " Delete` TO lt_ptab,
` lv_tabname = '(` && lv_namesfunc && `SAPL` && lv_funcgroup && `)X_NAMTAB[]'.` TO lt_ptab,
` ASSIGN (lv_tabname) TO <fs_x_namtab>.` TO lt_ptab,
` lv_cond_line2 = |keyflag EQ 'X' AND viewfield NE 'MANDT'|.` TO lt_ptab,
` LOOP AT <fs_x_namtab> ASSIGNING <fs_x_namtab_wa> WHERE (lv_cond_line2).` TO lt_ptab,
` ASSIGN COMPONENT <fs_x_namtab_wa>-viewfield OF STRUCTURE <fs_total_wa> TO <fs_field>.` TO lt_ptab,
` IF sy-subrc IS INITIAL.` TO lt_ptab,
` objectid = objectid && <fs_field>.` TO lt_ptab,
` UNASSIGN <fs_field>.` TO lt_ptab,
` ENDIF.` TO lt_ptab,
` ENDLOOP.` TO lt_ptab,
` IF sy-subrc IS INITIAL.` TO lt_ptab,
` MOVE-CORRESPONDING <fs_total_wa> TO *` && <ls_obj>-tabname && `.` TO lt_ptab,
` objectid = objectid.` TO lt_ptab,
` tcode = sy-tcode.` TO lt_ptab,
` udate = sy-datum.` TO lt_ptab,
` utime = sy-uzeit.` TO lt_ptab,
` username = sy-uname.` TO lt_ptab,
` cdoc_upd_object = 'D'.` TO lt_ptab,
` upd_` && lv_table && ` = 'D'.` TO lt_ptab,
` PERFORM cd_call_` && lv_object && `.` TO lt_ptab,
` ENDIF.` TO lt_ptab,
` ENDCASE.` TO lt_ptab,
` CLEAR: lv_cond_line, lv_cond_line2, objectid, ` && <ls_obj>-tabname && `, *` && <ls_obj>-tabname && `.` TO lt_ptab,
` ENDLOOP.` TO lt_ptab,
` ENDFORM.` TO lt_ptab.
"*-
GENERATE SUBROUTINE POOL lt_ptab NAME lv_prog
MESSAGE lv_mess
SHORTDUMP-ID lv_sid.
IF sy-subrc = 0.
PERFORM ('F_PROCESS') IN PROGRAM (lv_prog) IF FOUND.
ELSEIF sy-subrc = 4.
MESSAGE lv_mess TYPE 'I'.
ELSEIF sy-subrc = 8.
MESSAGE lv_sid TYPE 'I'.
ENDIF.
CLEAR: lt_ptab.
ENDLOOP.
ENDFORM.
*&----------------------------------------------------------------*
*& Form F_AFTER_SAVE
*&----------------------------------------------------------------*
FORM f_after_save ##CALLED.
COMMIT WORK AND WAIT.
ENDFORM.
我没有调通上面的代码,于是重新复写了FRM_BEFORE_SAVE
FORM frm_before_save.
TYPES: BEGIN OF total.
INCLUDE STRUCTURE zsdv004.
INCLUDE STRUCTURE vimflagtab.
TYPES: END OF total.
FIELD-SYMBOLS: <fs_total> TYPE ANY TABLE,
<fs_total_wa> TYPE total.
DATA: lv_tabname(40) TYPE c VALUE '(SAPLZSDV004)TOTAL[]'.
DATA: lv_uuid LIKE sysuuid-x,
ls_zsd001 LIKE cdtxt,
lt_zsd001 LIKE TABLE OF ls_zsd001,
ls_zsdt004 TYPE zsdt004,
ls_yzsdt004 TYPE yzsdt004,
lt_zsdt004 TYPE TABLE OF YZSDT004,
lt_zsdt004_old TYPE TABLE OF YZSDT004.
ASSIGN (lv_tabname) TO <fs_total>.
LOOP AT <fs_total> ASSIGNING <fs_total_wa> CASTING.
CLEAR: lt_zsdt004,lt_zsdt004_old,lt_zsd001.
CASE <fs_total_wa>-action.
WHEN 'U'. " Update
* CALL FUNCTION 'SYSTEM_UUID_CREATE'
* IMPORTING
* uuid = lv_uuid.
CONCATENATE SY-MANDT <fs_total_wa>-kunnr INTO ls_zsd001-teilobjid.
* ls_zsd001-teilobjid = lv_uuid.
ls_zsd001-textart = 'MODF'.
ls_zsd001-textspr = '1'.
ls_zsd001-updkz = 'U'.
APPEND ls_zsd001 TO lt_zsd001.
CLEAR ls_zsd001.
"旧值
SELECT SINGLE *
FROM zsdt004
INTO ls_zsdt004
WHERE kunnr = <fs_total_wa>-kunnr.
IF sy-subrc = 0.
MOVE-CORRESPONDING ls_zsdt004 to ls_yzsdt004.
APPEND ls_yzsdt004 TO lt_zsdt004_old.
CLEAR: ls_zsdt004,ls_yzsdt004.
ENDIF.
"新值
MOVE-CORRESPONDING <fs_total_wa> TO ls_yzsdt004.
APPEND ls_yzsdt004 TO lt_zsdt004.
CLEAR ls_yzsdt004.
CALL FUNCTION 'ZSD001_WRITE_DOCUMENT'
EXPORTING
objectid = 'ZSD001'
tcode = sy-tcode
utime = sy-uzeit
udate = sy-datum
username = sy-uname
upd_icdtxt_zsd001 = 'U'
upd_zsdt004 = 'U'
TABLES
icdtxt_zsd001 = lt_zsd001
xzsdt004 = lt_zsdt004
yzsdt004 = lt_zsdt004_old.
WHEN 'D'. " Delete
* CALL FUNCTION 'SYSTEM_UUID_CREATE'
* IMPORTING
* uuid = lv_uuid.
* ls_zsd001-teilobjid = lv_uuid.
CONCATENATE SY-MANDT <fs_total_wa>-kunnr INTO ls_zsd001-teilobjid.
ls_zsd001-textart = 'DELE'.
ls_zsd001-textspr = '1'.
ls_zsd001-updkz = 'D'.
APPEND ls_zsd001 TO lt_zsd001.
CLEAR ls_zsd001.
"旧值
SELECT SINGLE *
FROM zsdt004
INTO ls_zsdt004
WHERE kunnr = <fs_total_wa>-kunnr.
IF sy-subrc = 0.
MOVE-CORRESPONDING ls_zsdt004 to ls_yzsdt004.
APPEND ls_yzsdt004 TO lt_zsdt004_old.
CLEAR: ls_zsdt004,ls_yzsdt004.
ENDIF.
"新值
MOVE-CORRESPONDING <fs_total_wa> TO ls_yzsdt004.
APPEND ls_yzsdt004 TO lt_zsdt004.
CLEAR ls_yzsdt004.
CALL FUNCTION 'ZSD001_WRITE_DOCUMENT'
EXPORTING
objectid = 'ZSD001'
tcode = sy-tcode
utime = sy-uzeit
udate = sy-datum
username = sy-uname
upd_icdtxt_zsd001 = 'U'
upd_zsdt004 = 'U'
TABLES
icdtxt_zsd001 = lt_zsd001
xzsdt004 = lt_zsdt004
yzsdt004 = lt_zsdt004_old.
ENDCASE.
ENDLOOP.
ENDFORM.
三、创建报表程序,调用rsscd100显示更改日志
REPORT zsdr054.
DATA: gt_cdred_str TYPE cdred_str_tab.
*----------------------------------------------------------------------
* screen
*----------------------------------------------------------------------
SELECTION-SCREEN BEGIN OF BLOCK bk1 WITH FRAME TITLE text-001.
PARAMETERS: aenderer TYPE cdhdr-username,
datum TYPE cdhdr-udate,
zeit TYPE cdhdr-utime,
dat_bis TYPE cdhdr-udate DEFAULT sy-datum,
zeit_bis TYPE cdhdr-utime DEFAULT '235959'.
SELECTION-SCREEN END OF BLOCK bk1.
*----------------------------------------------------------------------
* START-OF-SELECTION
*----------------------------------------------------------------------
START-OF-SELECTION.
* 调用程序显示数据
PERFORM frm_data_display.
*&---------------------------------------------------------------------*
*& Form FRM_DATA_DISPLAY
*&---------------------------------------------------------------------*
* 调用程序显示数据
*----------------------------------------------------------------------*
FORM frm_data_display .
SUBMIT rsscd100 WITH objekt = 'ZSD001'
WITH aenderer = aenderer
WITH datum = datum
WITH zeit = zeit
WITH dat_bis = dat_bis
WITH zeit_bis = zeit_bis AND RETURN.
ENDFORM. " FRM_DATA_DISPLAY
执行程序,查看运行效果:
PS:喜欢的同学可以关注微信公众号