Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
robynhosby
Active Participant

Hello!

This blog pertains to Security Weaver’s utility Process Auditor.  I recently had the opportunity to work with Security Weaver’s Process Auditor (or PA). In summary, PA is a utility that will provide continuous compliance monitoring in SAP.

This previous post gives a general overview of the utility...

  http://scn.sap.com/community/grc/blog/2013/10/09/process-audit-don-t-worry--sw-pa-can-help

PA has several out-of-the-box controls to use, however our requirement was to develop custom controls.  I was not able to find detailed documentation on how to configure and develop within the tool or about how the areas are connected within the tool and in the canned programs. The PA user guide (ProcessAuditor-UserGuideforv2 5PS3.pdf) contains user information and general information on how to create a new control and rule id.  Start with that document first.  In this blog, I will discuss other technical details that are vague or not detailed at all in the user guide as well as my observations to help your developer/configurator with an installation.

Sections covered in this blog include:

1) Our Requirements
2) The Process Auditor utility

a. Create a new Control and Rule Parameters
b. The Development Workbench:

- Output format (the format of the alert record)
- Fetch Data Code (when to generate the alert)
- Hotspot code (for hyperlink in the Inbox)

c. Online Execution
d. Execution in Background
e. How to view the Alerts
f. User Exits to Know About
g. How to Debug the Alert Generation
h. How to Import to a Target Systems
i. Observations
j. Additional Controls

Our Requirements

Our requirements were to create three custom controls in ECC for transaction codes FB01, FB05, and FB50 based on on a specific document type. I’ll only show FB01 in this blog.

Basically, I needed to...

  1. Create a rule ID for each control
  2. Create control IDs
  3. Create hotspots
  4. Create a background Jobs to trigger alerts in Process Auditor tool.

Process Auditor utility

Tcode /n/PSYNG/PA


a) Create a new Control

As explained in the user guide, here is the control I created:

Header…

Rule Parameters…

Rule parameters are passed to the program when the control is executed directly in the utility.  They are NOT passed to the batch job.  The batch job variant and special logic in Fetch Code are needed to pass these values to batch processing. I’ll explain more about that in the Fetch Data Code section.


b) The Development Workbench

Alert Output Format

In this section, enter the format of the output record that will appear in the Alert.  I used the same name for the Rule ID as I did for the Control ID for clarity.

For the accounting debit and credit amounts above, I used a custom structure…

Fetch Data Code

Any time you enter the Fetch Code tab, you need to enter the Rule ID. Then, while keeping the cursor on the Rule ID field, select ENTER. This will allow the existing code to be displayed....

If you move the cursor‘s focus to either the Selection Screen or Fetch Data Code sections, then select ENTER, the utility gets „confused“ and it will appear as if no code exists like this...

Don’t worry! Any existing code is still there. :smile: To fix this situation, just select a different tab. Select to confirm that the changes are NOT to be saved.
Then, return to the Fetch Data Code tab and keep the cursor on the Rule ID field when you select ENTER.

The Selection Screen and Fetch Data Codes sections are Includes. They are inserted into the canned program created by the PA utility.

Here is the code I used in my Selection Screen section....

{code}

tables: bkpf, bseg, /PSYNG/SACONRULE, /PSYNG/SARULEHDR.

SELECTION-SCREEN : BEGIN OF BLOCK BLK1.

* Refer to include /PSYNG/SA_001F01 form submit_programs for fields
* passed in SELTAB:

** Used to create case. Not used in Fetch Code directly. Declared in
** main program
*SELECT-OPTIONS  : cntrlid for /PSYNG/SACONRULE-CONTROLID,
*                  p_ruleid for /PSYNG/SARULEHDR-RULEID.

** Used to read data:
SELECT-OPTIONS  : BELNR  for bkpf-belnr,
                  BLART  for bkpf-blart,
                  wrbtr for BSEG-WRBTR,
                  tcode  for bkpf-tcode,

* read data fields for testing...
                  BUDAT FOR SY-DATUM.

* When executed in batch, the rule parameters are not passed, so the
* batch job does not receive stardard parms ZCNTRLID or ZP_RULEID.
* Pass them in variant, so the case id will be created by the batch job.
SELECT-OPTIONS  : zcntrlid for /PSYNG/SACONRULE-CONTROLID.
parameters      : zp_rule like /PSYNG/SARULEHDR-RULEID,

* "=X if processing batch job. Set in variant only
                  p_Batch(1).

SELECTION-SCREEN : END OF BLOCK BLK1.

{code}

Here is the code in my Fetch Data Code.....

{code}

************************************************
* Flow:
* 1) Read data for selection parameters
* 2) Populate output fields that appear in inbox
* 3) Fill rule and control ids, needed for batch processing
* 4) output for batch job spool
*
* Batch Job:
* When scheduling batch job, the data for this is extracted for
* yesterday.  Schedule batch job at 00:01 (midnight) to read all of
* yesterday's data.
************************************************

TYPES : BEGIN OF TY_BKPF,
        BUKRS TYPE BKPF-BUKRS, "company code
        BELNR TYPE BKPF-BELNR, "document no
        GJAHR TYPE BKPF-GJAHR, "year
        BLART TYPE BKPF-BLART, "document type
        BUDAT TYPE BKPF-BUDAT, "Posting date
        tcode type bkpf-tcode, "doc created in tcode
      END OF TY_BKPF.

TYPES : BEGIN OF TY_BSEG,
        BUKRS TYPE BKPF-BUKRS, "company code
        BELNR TYPE BKPF-BELNR, "document no
        GJAHR TYPE BKPF-GJAHR, "year
        BUZEI TYPE BSEG-BUZEI,
        BSCHL TYPE BSEG-BSCHL,
        KOART TYPE BSEG-KOART,
        SHKZG TYPE BSEG-SHKZG,
        GSBER TYPE BSEG-GSBER,
        MWSKZ TYPE BSEG-MWSKZ,
        WRBTR type ZPA_WRBTR, "amount in transaction
      END OF TY_BSEG.

DATA : LT_BKPF TYPE STANDARD TABLE OF TY_BKPF WITH HEADER LINE
                                              INITIAL SIZE 0.

DATA : LT_BSEG TYPE STANDARD TABLE OF TY_BSEG WITH HEADER LINE
                                              INITIAL SIZE 0.

data: gs_output like line of GT_output.

DATA : TABIX TYPE SY-TABIX VALUE 1,
      gs_tabix type sy-tabix.

data:  ls_yesterday like sy-datum.
DATA : v_bukrs LIKE bkpf-bukrs,
      v_belnr LIKE bkpf-belnr,
      v_gjahr LIKE bkpf-gjahr.

DATA : bkpf_curs  TYPE cursor,
      l_pack_size TYPE I VALUE 999999. "limit # of alerts

*--------------------------------------------------

FREE : LT_BKPF,LT_BSEG,GT_OUTPUT.
REFRESH: LT_BKPF,LT_BSEG,GT_OUTPUT.

*-------------------------------------------------------------
* Set date range to read. If not set, process as in production and
* default to only yesterday's records. If set, we are in testing mode.
    if BUDAT[] is initial.
*    for production processing, use yesterday's date only...
      ls_yesterday = sy-datum - 1.
      BUDAT-sign = 'I'.
      BUDAT-option = 'EQ'.
      BUDAT-low = ls_yesterday.
      append BUDAT.
    else.
*    use date requested in parm
    endif.

*-------------------------------------------------------------
* 1) Read data for selection parameters
  OPEN CURSOR WITH HOLD bkpf_curs
      FOR SELECT bukrs belnr gjahr blart budat tcode
                  FROM bkpf
                  WHERE belnr in belnr
                    and tcode in tcode
                    and blart in blart
                    and BUDAT IN BUDAT.
  DO.
    FETCH NEXT CURSOR bkpf_curs  INTO TABLE lt_bkpf
                                  PACKAGE SIZE l_pack_size.
    IF SY-SUBRC <> 0.
      EXIT.
    ENDIF.

    SORT lt_bkpf BY bukrs belnr gjahr.
    SELECT bukrs belnr gjahr buzei bschl koart shkzg gsber MWSKZ WRBTR
      FROM bseg INTO TABLE lt_bseg
      FOR ALL ENTRIES IN lt_bkpf
        WHERE bukrs = lt_bkpf-bukrs
          AND belnr = lt_bkpf-belnr
          AND gjahr = lt_bkpf-gjahr.

    SORT lt_bseg by bukrs belnr gjahr.

    LOOP AT lt_bkpf.
      v_bukrs = lt_bkpf-BUKRS.
      v_belnr = lt_bkpf-BELNR.
      v_gjahr = lt_bkpf-GJAHR.

      LOOP AT lt_bseg FROM TABIX.
        IF LT_BSEG-BUKRS <> v_bukrs OR
          LT_BSEG-GJAHR <> v_gjahr OR
          LT_BSEG-BELNR <> v_belnr.

          TABIX = SY-TABIX.
          EXIT.
      ELSE.

*--------------------------------------------------
* 2) Populate output fields that appear in inbox
        GT_output-bukrs = LT_BSEG-bukrs.
        GT_output-belnr = LT_BSEG-belnr.
        GT_output-blart = lt_bkpf-blart.
        GT_output-GJAHR = lt_bkpf-GJAHR.
        GT_output-budat  = lt_bkpf-budat.
        GT_output-tcode = lt_bkpf-tcode.

        case LT_BSEG-SHKZG.
          when 'H'."credit
            GT_output-WRBTR = LT_BSEG-WRBTR.
          when 'S'. "debit
              GT_output-DMBTR = LT_BSEG-WRBTR.
        ENDcase.

        GT_output-ruleid = cntrlid.
        GT_output-CONTROLID = p_ruleid.

        COLLECT GT_output.
        CLEAR : GT_output.
      ENDIF.
      CLEAR : lt_bseg.
    ENDLOOP.

    CLEAR lt_bkpf.
  ENDLOOP.
  REFRESH lt_bkpf.

ENDDO.

*-----------------------------------------------------
* 3) Filter cumulative amounts for DEBIT based on parm value
loop at GT_OUTPUT into gs_output.
  gs_tabix = sy-tabix.
  if Gs_output-DMBTR in wrbtr. "min amt set in parms
    "...keep in list
  else. "not in alert range so filter from list...
    delete gt_output index gs_tabix.
  endif.
endloop.

SORT GT_OUTPUT BY bukrs blart belnr.

*-----------------------------------------------------
* 4) Fill rule and control ids, needed for batch processing
if cntrlid is initial.
  move-corresponding zcntrlid to cntrlid.
  append cntrlid.
endif.

if p_ruleid is initial.
    move zp_rule to p_ruleid.
endif.

*-----------------------------------------------------
* 4) output for batch job spool
if p_batch is not initial. "processing batch job?
    write: / 'For date:', BUDAT-option, space, BUDAT-sign,
              space, BUDAT-low.
    write: / 'Parameters:',
          / 'BELNR=', belnr,
          / 'BLART=', blart,
          / 'TCODE=', tcode,
          / 'cntrlid=', cntrlid,
          / 'p_ruleid=', p_ruleid,
          / 'Amount (Credit)',
          / 'Amount (Debit)'.

    skip 2.
    write: / 'Data Read:'.
    loop at gt_output.
        write: / GT_output-bukrs,
                GT_output-belnr,
                GT_output-blart,
                GT_output-GJAHR,
                GT_output-budat,
                GT_output-tcode,
                GT_output-WRBTR,
                GT_output-DMBTR.
        skip.
    endloop.
endif.

FREE : lt_bkpf, lt_bseg.

{code}

Hotspot Code

This logic is called when the Alert is selected in the Inbox (note that this does NOT apply to the Alert Report). 

This logic will call FB03 (display mode) for the accounting document hyperlink selected in the Inbox.

{code}

DATA :  lt_bkpf TYPE STANDARD TABLE OF bkpf WITH HEADER LINE.

CHECK i_column_id-fieldname = 'BELNR'.

clear gt_output.
READ TABLE GT_OUTPUT INDEX is_row_no-row_id.

SELECT SINGLE * FROM BKPF INTO LT_BKPF WHERE bukrs = gt_output-bukrs
                                          AND  belnr = gt_output-belnr.
  CHECK sy-subrc = 0.
  SET PARAMETER ID 'BUK' FIELD GT_OUTPUT-BUKRS.
  SET PARAMETER ID 'BLN' FIELD GT_OUTPUT-BELNR.
  SET PARAMETER ID 'GJR' FIELD GT_output-gjahr.

AUTHORITY-CHECK OBJECT 'S_TCODE' ID 'TCD' FIELD 'FB03'.
if sy-subrc = 0.
  CALL TRANSACTION 'FB03' AND SKIP FIRST SCREEN .
else.
  MESSAGE e077(s#) WITH 'FB03'.
endif.

{code}

When you are done with the code sections, select SAVE and GENERATE. You will be prompted to enter the program name to save it under.  This program name is the one you will want to use later if you schedule a batch job for execution.

c) Execution Online

Online execution is perfect for testing.  The parameters used in the execution online will be the ones stored on the Rule Parameter screen.

In this example, only data for transaction FB01 for document type ZG created on 12/15/2015 with debit amounts greater than $200,000 will be processed in the alert…

To trigger the execution, select tab Controls -> Header. Enter the Control ID to execute and ENTER (with the cursor’s focus on the Control ID field)…

Select Execute Control button....

A new Case ID will be created in the Inbox (of the user assigned) and in the Alert Monitor...

...The format of these roles is from the Development Workbench -> Format tab.

...The Hotspot Code (hyperlink) is executed by selecting the Accounting Document Number. It will flow to FB03 in this case.

d) Execution in Background

To create the batch job, you can create it directly in tcode SM36 or you can create a "template“  batch job using the wizard in the utility.  I use the word "template“ because the wizard does not create the batch job correctly. I needed to modify the resulting job for it to exist correctly.

I created one batch job for each custom control for clarity.

Create a Variant

The Rule Parameters are not used by the batch job, so you’ll need to create the variant to initialize those fields.

  • I’m using BUDAT in the Fetch Code Data to read a specific date’s data for testing. BUDAT is not set in the variant since our requirement was to create alerts for all documents that meet the criteria. The Fetch Code Data is written for this requirement.
  • P_BATCH is used to print the values to the spool file. (Refer to the Fetch Data Code section)
  • The other values are similar to the Rule Parameters.

To Create the Batch Job using the Wizard

Go to tab Monitoring -> Process Controls.

To fix the incorrectly created batch job, in SM37, edit the batch job step to correct the Z program name and the variant.  Also, confirm and update the Frequency.  My Fetch Logic Code will read the data from the prior date, so it is set to run daily just after midnight to pick up all of prior day’s records.

e. How to view the Alerts

Inbox

Alerts will be set to the Inbox of the user assigned to the case id.

Alert Report

They will also be sent to the Alert Report...

f. User Exits to Know About

Program /PSYNG/SA_009  - User Exit 100
This exit allows setting flag SCHEDULE to X if controls are to be re-processed so they will appear again in the Inbox. 
If controls are not to be reprocessed, remove this flag.


Activate the Exit in tab Misc….

My Exit code looks like this when generated…

{code}

  *----------------------------------------------------------------------*
* Report  /PSYNG/SA_009                                                *
* AUTHOR: Security Weaver, LLC                                        *
*----------------------------------------------------------------------*
* COPYRIGHTS Security Weaver, LLC
*
* WARNING:
* THIS COMPUTER PROGRAM IS PROTECTED BY COPYRIGHT LAW AND INTERNATIONAL
* TREATIES. UNAUTHORIZED REPRODUCTION OR DISTRIBUTION IS STRICTLY
* PROHIBITED AND MAY RESULT IN SEVERE CIVIL AND CRIMINAL PENALTIES AND
* WILL BE PROSECUTED TO THE MAXIMUM EXTENT POSSIBLE UNDER THE LAW.
*&---------------------------------------------------------------------*


REPORT /psyng/sa_009 MESSAGE-ID /psyng/sa.
DATA: schedule.

*&---------------------------------------------------------------------*
*& Form start_user_exit
*&---------------------------------------------------------------------*
FORM execute_user_exit using schedule.
schedule = 'X'.
endform.

{code}

The exit code for the Schedule Flag is read here...

Program /PSYNG/SA_001F01 – User Exit 001

I found this exit in my analysis. It is not currently in use in my implementation.

{code}

...
WHEN 'RPT_SYS'.
      SUBMIT /psyng/sa_rpt07 VIA SELECTION-SCREEN AND RETURN.

*    WHEN 'PROC03'.                    "SOD Control Report
*      submit /PSYNG/SA_SOD_BY_HISTORY via selection-screen and return.
*      submit /PSYNG/SODREPORT_BY_HISTORY
*                via selection-screen and return.
      SELECT SINGLE * FROM /psyng/sa_usrext INTO /psyng/sa_usrext
            WHERE  exitnumber = 1.
      IF sy-subrc = 0.
        l_prog_name = /psyng/sa_usrext-exitname.
        PERFORM execute_user_exit IN PROGRAM (l_prog_name).
      ENDIF.

{code}

Due to the length of this post, this discussion is continued under...

Security Weaver’s Process Auditor - Developer's Observations (Part 2)

1 Comment