Skip to Content

Centralized User License Data Management Report

Vishlashak KAPOOR

12/26/2014

SAP License Audit


SAP annual license audit is a real pain for managers. SAP is transparent about its license pricing & provides publicly available license guides on http://support.sap.com/:

1. SAP System Measurement Guide 7.0: Complete instructions for how to utilize the SAP system to manage licenses.

2. PROCESS OVERVIEW: SAP SYSTEM MEASUREMENT: Procedure elaborating Activation of price list –> Setup of system data and clients –>Classification of  users –> Carry out the measurement and transfer results –> Consolidation of measurement results –> Send LAW results to SAP

3. LAW: A tool overview outlining details of the collection, consolidation and correction of licenses for SAP-developed, on-premises products compared with the current license evaluation rules.

To utilize license contract value & reduce risk of unbudgeted fees, managers should understand following:

  • Named user license categories: Users classification with appropriate contractual user type should be done properly. Some common license categories exist as below:

Untitled.jpg

  • License Reporting to SAP through USMM & LAW:


  • USMM: Transaction for measurement Program which determines number of users & chargeable objects of the engines of the SAP software for each system.
  • LAW : License Administrative Workbench (LAW) consolidate results from multiple systems on the central system on which LAW is run

Purpose

In order to fully utilize SAP’s License Administration Workbench (LAW) tool & validate compliance with license entitlements, managers need to ensure following in their multi-system landscape :

1. Validate all category ID fields: The LAW tool does not determine whether your ID categorization is correct, so if an ID does not have a category in its designated field, LAW will assign the most common user type to that ID (professional users) and report through LAW. The tool then consolidates all instances of categories showing under a single ID and reports the highest cost license in the SAP system through LAW.

2. Counting single users who have multiple IDs: It is important to identify where individuals are using multiple SAP systems, but also using different IDs. For example, David and David1 are logons for the same person in your organization but have raised two different IDs to define themselves in separate packages/engines. Based on this, each ID will count as a unique license versus one license with the highest value. All user IDs should be validated through whatever central system defines your unique employee information. Linking this unique information to the user will allow checking for each employee who has more than one ID. Checks should be made to ensure that policy is being adhered to when creating user IDs in that no employee should need two SAP IDs.

To address above two issues, I have created a custom ABAP based solution: Centralized License Data Management Report such as below:

  Untitled1.jpg

Prerequisites

1. RFC connection to be defined from Central to Child system. Solution Manager can be used as central system as it has already defined RFC connection with all systems

2. Accounting No. or another unique identifier for each logon must be filled. This field or any other field can be used as key identifier for a user such employee id. You can also use Second Forename Field available in User Master’s Address Data tab. This field must be filled for all users in entire SAP landscape to identify users.

3. User Group: This field makes it easier to identify the license type assigned to a group of logons such as number of users in a department, number of developers in a company. This field can be filled in Group Data Tab of User Master. Non-dialog users should have user group other than dialog users.

4. Full Name: Most of the times, Full Name is not aligned in multi-system landscape for a user. This report can easily identify such discrepancies if above 2 key identifiers are filled.

Note: Email ID Field: Sometimes, users doesn’t have email id (in case of external users), in such cases dummy email ids or email ids for person responsible is assigned to user master of such logons as per company policy. Therefore, this field cannot be used as a key field.

Solution Implementation

For creation of this report ABAP developments need to be done on Central as well as Child systems with following prerequisites.

On Each Child System:

1. Table on Child system (say ZTBLIC_CHILD_DATA) : A table needs to be created with following structure:

               Untitled2.jpg

  • This table collects data through function module which collects data through different table joins:

                   Untitled3.jpg

2.      Function Module on each Child System (say ZFMLIC_RFC_CHILD)

  • This RFC populates the gt_table (gt_table is an internal table of above table with the condition that we get only the dialog users i.e. we get only the users having usertype = ‘A’

  • Through this RFC, the data from a particular destination is fetched by applying left outer and inner joins on the tables

  • The tables involved are USR02, USR21, ADRP, ADR6, USR06.If an error occurs, we get ‘E’ in a field named ‘ev_status’

Sample Source Code:

TYPES:
BEGIN OF tyy_adrp,
bname     
TYPE xubname,
persnumber
TYPE ad_persnum,
name 
TYPE ad_namtext,
email_id 
TYPE ad_smtpadr,
END OF tyy_adrp,
ty_adrp
TYPE STANDARD TABLE OF tyy_adrp.


DATA lt_adrp TYPE ty_adrp.


SELECT a~bname AS bname
a
~accnt AS acc_no
a
~class AS usergroup
b
~lic_type AS lic_type
INTO CORRESPONDING FIELDS OF TABLE gt_table
FROM usr02 AS a
LEFT OUTER JOIN usr06 AS b
ON a~bname = b~bname WHERE USTYP = ‘A’.
DELETE gt_table WHERE usergroup = ‘TERMINATED’ OR usergroup = ‘COMMUSER’.


DELETE ADJACENT DUPLICATES FROM gt_table COMPARING bname.
IF gt_table[] IS INITIAL.
ev_status
= ‘E’.
RETURN.
ENDIF.
SELECT a~bname
b
~name_text As name
c~smtp_addr As email_id
INTO CORRESPONDING FIELDS OF TABLE lt_adrp
FROM usr21 AS a
INNER
JOIN adrp AS b
ON a~persnumber = b~persnumber
LEFT OUTER JOIN adr6 AS c
ON a~persnumber = c~persnumber.
FIELD-SYMBOLS <table> LIKE LINE OF gt_table.
FIELD-SYMBOLS <adrp>  LIKE LINE OF lt_adrp.
SORT gt_table BY bname.
SORT lt_adrp  BY bname.

LOOP AT gt_table ASSIGNING <table>.
READ TABLE lt_adrp ASSIGNING <adrp>
WITH KEY bname = <table>bname
BINARY SEARCH.
IF <adrp> IS ASSIGNED.
<table>
name = <adrp>name.
<table>
email_id = <adrp>email_id.
ENDIF.
UNASSIGN <adrp>
.
ENDLOOP.
ENDFUNCTION.

On Central system:

1.      Centralized License Data Table (say ZTBLIC_CENTRAL_DATA): A table needs to be created with following structure:

        Untitled4.jpg

2.      Table for RFC connections (say ZTBLIC_CONNECT):

  • In order to have a collection of all the systems from where we have to fetch data, we have created a table on central system.
  • We will fetch the destination row wise in order to fetch data from the destination.
  • The structure of this table should be as follows :
    • MANDT: Client of the central system on which data needs to be consolidated
    • SERNR: Serial number : The order in which you want to have your systems configured in the Centralized License Management Data report
    • RFCDEST: The RFC destination (specified in function call in RFC)
    • RFCTYTEXT: RFC connection type
    • STATUS: General flag (X)

       

Untitled5.jpg

3.      Central Function Module (say ZFMLIC_RFC_CENTRAL): This RFC calls RFC’s on respective destinations by passing the destination in a variable named ‘pv_rfcdest’ and imports the data in ‘gt_table’ (gt_table is an internal table of  table created in Child Systems (1.1)) and a status in ‘ev_status’ to ensure successful fetching of data. ‘ev_status’ gets value ‘E’ in case there is any error in fetching the data.

     

Sample Code:

CALL FUNCTION ‘ZLIC_RFC_CHILD’
DESTINATION pv_rfcdest
IMPORTING
ev_status
= ev_status
TABLES
gt_table 
= gt_table.

ENDFUNCTION.

4.      Centralized License Data Management Report (ZRPLIC_CENTRAL_MGMT_DATA): This report runs on Central System to collect data from each child systems to consolidate user master license data on central system:

  • In this report, we fetch destination from gt_connect  row wise where status is ‘X’ and corresponding to every destination, we call the RFC (ZFMLIC_RFC_CENTRAL) which asks for the destination name

  • After importing the data in ‘gt_table’, we delete the users with the user group as ‘TERMINATED’ or ‘COMMUSER’

  • Then we read the table ZTBLIC_CENTRAL_DATA  in order to ensure if the entry based on Account No, Full Name and User Group exists or not

  • If not, we create a new entry

  • We have created two subroutines ‘fill_data’ (to insert account number, full name, user group and email id) and ‘fill_things’ (to insert user id and license type) to populate ZTBLIC_CENTRAL_DATA  depending on whether entries exist or not.
  • Sample Source Code:

DATA gt_table         TYPE TABLE OF ZTBLIC_CHILD_DATA.
DATA gt_central_data  TYPE TABLE OF ZTBLIC_CENTRAL_DATA.
DATA gt_connect       TYPE TABLE OF ZTBLIC_CONNECT.

DELETE FROM ZTBLIC_CENTRAL_DATA.

START-OF-SELECTION.
PERFORM get_rfc_con_data.
PERFORM fetch_data.

END-OF-SELECTION.
PERFORM get_central_data.

IF gt_central_data IS INITIAL.
RETURN.
ENDIF.

PERFORM write_header.
PERFORM write_data.

FORM get_rfc_con_data.
SELECT *
INTO TABLE gt_connect
FROM ztblic_connect
WHERE status = ‘X’.
ENDFORM.                   

FORM fetch_data.
FIELD-SYMBOLS <connect>       LIKE LINE OF gt_connect.
FIELD-SYMBOLS <table>         LIKE LINE OF gt_table.
FIELD-SYMBOLS <central_data>  LIKE LINE OF gt_central_data.
DATA wa_central_data          LIKE LINE OF gt_central_data.
DATA lv_status                TYPE char1.
DATA lv_usergroup             TYPE xuclass.

PERFORM get_central_data.

LOOP AT gt_connect ASSIGNING <connect>.
CALL FUNCTION ‘ZFMLIC_RFC_CENTRAL’
EXPORTING
pv_rfcdest
= <connect>rfcdest
IMPORTING
ev_status 
= lv_status
TABLES
gt_table  
= gt_table.

DELETE gt_table WHERE usergroup = ‘TERMINATED’ OR usergroup = ‘COMMUSER’.

DELETE gt_table WHERE acc_no = AND usergroup = AND name = .

SORT gt_table BY acc_no usergroup name.

DELETE ADJACENT DUPLICATES FROM gt_table COMPARING acc_no usergroup name.

LOOP AT gt_table ASSIGNING <table>.
TRANSLATE <table>name TO UPPER CASE.

READ TABLE gt_central_data ASSIGNING <central_data>
WITH KEY acc_no = <table>acc_no
usergroup      
= <table>usergroup
name           
= <table>name.
IF sysubrc <> 0.
CLEAR wa_central_data.

SELECT SINGLE *
INTO wa_central_data
FROM ZTBLIC_CENTRAL_DATA
WHERE acc_no  = <table>acc_no
AND name      = <table>name.
IF sysubrc = 0.
<table>
usergroup = wa_central_datausergroup.
ENDIF.
ENDIF.

PERFORM fill_data USING <table>
CHANGING wa_central_data.

PERFORM fill_things USING <connect>rfctytext ‘LIC_TYPE’
CHANGING wa_central_data <table>.

PERFORM fill_things USING <connect>rfctytext ‘BNAME’
CHANGING wa_central_data <table>.

MODIFY ZTBLIC_CENTRAL_DATA FROM wa_central_data.
COMMIT WORK.

CLEAR wa_central_data.
UNASSIGN <central_data>
.
ENDLOOP.

UNASSIGN <table>.
CLEAR gt_table[].
ENDLOOP.
ENDFORM.                   

FORM get_central_data.
CLEAR gt_central_data[].

SELECT *
INTO TABLE gt_central_data
FROM ZTBLIC_CENTRAL_DATA.

SORT gt_central_data BY acc_no usergroup name.
ENDFORM.                   


FORM fill_data USING pw_table TYPE ZTBLIC_CHILD_DATA
CHANGING pw_central_data TYPE ZTBLIC_CENTRAL_DATA.
MOVE pw_tableacc_no    TO pw_central_dataacc_no.
MOVE pw_tablename      TO pw_central_dataname.
MOVE pw_tableusergroup TO pw_central_datausergroup.
MOVE pw_tableemail_id  TO pw_central_dataemail_id.
ENDFORM.                   

FORM fill_things USING pv_rfctext p_fname
CHANGING pw_central_data TYPE ZTBLIC_CENTRAL_DATA
pw_table
TYPE ZTBLIC_CHILD_DATA.

FIELD-SYMBOLS <fldname> TYPE any.
FIELD-SYMBOLS <fldname1> TYPE any.
DATA lv_txt TYPE char30.
DATA lv_txt1 TYPE char30.

CONCATENATE pv_rfctext ‘_’ p_fname
INTO lv_txt.
CONDENSE lv_txt.

ASSIGN COMPONENT lv_txt OF STRUCTURE pw_central_data TO <fldname>.
IF <fldname> IS ASSIGNED.
ASSIGN COMPONENT p_fname OF STRUCTURE pw_table TO <fldname1>.
IF <fldname1> IS ASSIGNED.
IF <fldname> <> <fldname1>.
<fldname>
= <fldname1>.
ENDIF.
ENDIF.
ENDIF.
ENDFORM.                
FORM write_header.
WRITE:/1(12) ‘ACC_NO’, 13(12) ‘USERGROUP’, 25(40) ‘NAME’, 65(35) ‘EMAIL_ID’,
100(12) ‘SYS1_BNAME’, 114(12) ‘SYS1_LIC_TYPE’, 128(12) ‘SYS2_BNAME’, 142(12) ‘SYS2_LIC_TYPE’,156(12) ‘SYS3_BNAME’, 170(12) ‘SYS3_LIC_TYPE’, 184(12) ‘SYS4_BNAME’, 198(12) ‘SYS4_LIC_TYPE’,212(12) ‘SYS5_BNAME’, 226(12) ‘SYS5_LIC_TYPE’, 240(12) ‘SYS6_BNAME’, 254(12) ‘SYS6_LIC_TYPE’.
ENDFORM.                   
FORM write_data.
FIELD-SYMBOLS <central_data> LIKE LINE OF gt_central_data.

LOOP AT gt_central_data ASSIGNING <central_data>.
WRITE:/1(12) <central_data>acc_no, 13(12) <central_data>usergroup, 25(40) <central_data>name, 65(35) <central_data>email_id, 100(12) <central_data>sts_bname, 114(12) <central_data>sts_lic_type,128(12) <central_data>wel_bname, 142(12) <central_data>wel_lic_type,156(12) <central_data>wal_bname, 170(12) <central_data>wal_lic_type, 184(12) <central_data>gtl_bname, 198(12) <central_data>gtl_lic_type,212(12) <central_data>crl_bname, 226(12) <central_data>crl_lic_type, 240(12) <central_data>bwp_bname, 254(12) <central_data>bwp_lic_type.
ENDLOOP.
ENDFORM.

Post Implementation steps

1. Centralized License Data Management Report (ZRPLIC_CENTRAL_MGMT_DATA) must be run every time you want to have current data in ZTBLIC_CENTRAL_DATA

2. Based on above consolidated report, you can perform manual actions to align following :

  • Correct assignment of User Groups
  • Incorrect Full Name
  • Incorrect Email Ids
  • Removing duplicate logons for same person
  • Correct license assignment

3. Above manual assignments can also be triggered automatically by sending data to child systems by means of RFC & changing corresponding user master

4. Automated reporting can be used by scheduling this report at due interval

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply