Write Back Email, Username and Phone to SAP HR Using SailPoint IIQ

Frustrated with writing back new username and email to SAP HR? You’re not alone.

Most joiner processes for new hires generate an username and email address dynamically, but a problem can arise when using SAP HR systems because there is no direct way to write back the newly generated username and email to SAP HR 105 records. SailPoint IdentityIQ provides a simple solution. The rule below can be used to write back to SAP HR using IIQ.

Pre-Requisite

The SAP service account should have permission to update the SAP HR records. Please refer to SailPoint connector reference guide for SAP HR configuration.

Steps

  1. Import the rule to SailPoint
  2. Edit application SAP HR and goto Rules-> Connector Rules -> Select Radio By Operation Rule-> Select the Rule name “SAP HR Provisioning Rule” as Modify Provision Rule.
  3. Go to Identity Mapping -> Edit Email attribute -> Set Target Mapping with SAP “Email” Attribute.
  4. Go to Identity Mapping -> Edit UserName attribute -> Set Target Mapping with SAP “System user name (SY-UNAME)” Attribute.
  5. Go to Identity Mapping -> Edit Phone attribute -> Set Target Mapping with SAP “Telephone” Attribute.
  6. Enable attribute sync in the Refresh Identity Cube and execute.
  7. The modify plan will be generated for the newly created identities and it will call the below rule to write back to SAP.

Rule

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Rule PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Rule language="beanshell" name="SAP HR Provisioning Rule" type="SapHrOperationProvisioning">
  <Description>This rule is used by the SAP HR connector for provisioning of the data .</Description>
  <Signature returnType="ProvisioningResult">
    <Inputs>
      <Argument name="log">
        <Description>
          The log object associated with the SailPointContext.
        </Description>
      </Argument>
      <Argument name="context">
        <Description>
          A sailpoint.api.SailPointContext object that can be used to query the database if necessary.
        </Description>
      </Argument>
      <Argument name="application">
        <Description>The application whose data file is being processed.</Description>
      </Argument>
      <Argument name="schema">
        <Description>The Schema currently in use.</Description>
      </Argument>
      <Argument name="destination">
        <Description>A connected/ready to use
          com.sap.conn.jco.JCoDestination object that can be used to call
          bapi, function modules and call to SAP tables. This is the main
          object used in making BAPI calls using the JCo interface.This
          destination object is shared with the connector implementation and
          the connector controls the destination lifecycle.</Description>
      </Argument>
      <Argument name="plan">
        <Description>The ProvisioningPlan created against the SAP
          application.</Description>
      </Argument>
      <Argument name="request">
        <Description>The ProvisioningRequest created against the SAP
          application.</Description>
      </Argument>
      <Argument name="connector">
        <Description>The SAP connector that is being used to communicate
          with SAP. This class is here for convenience as there are many
          utility methods that make calling Function Modules and doing table
          lookup easier.</Description>
      </Argument>
    </Inputs>
    <Returns>
      <Argument name="result">
        <Description>A Provisioning Result object is desirable to return the
          status.IT can be a new object or part of Provisioning Plan</Description>
      </Argument>
    </Returns>
  </Signature>
  <Source>
  import sailpoint.object.*;
  import sailpoint.object.ProvisioningPlan.AccountRequest;
  import sailpoint.object.ProvisioningPlan.AttributeRequest;
  import sailpoint.object.ProvisioningPlan.ObjectOperation;
  import sailpoint.object.ProvisioningPlan.AccountRequest.Operation;
  import sailpoint.tools.Util;
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import java.util.Map;
  import java.util.HashMap;
  import com.sap.conn.jco.AbapException;
  import com.sap.conn.jco.JCoDestination;
  import com.sap.conn.jco.JCoException;
  import sailpoint.connector.ConnectorException;
  import com.sap.conn.jco.JCoFunction;
  import com.sap.conn.jco.JCoParameterField;
  import com.sap.conn.jco.JCoParameterFieldIterator;
  import com.sap.conn.jco.JCoParameterList;
  import com.sap.conn.jco.JCoStructure;
  import com.sap.conn.jco.JCoTable;
  import com.sap.conn.jco.JCoContext;
  import com.sap.conn.jco.*;
  import sailpoint.api.*;
  import sailpoint.transformer.*;
  import sailpoint.tools.*;
  import sailpoint.tools.Message.Type.*;
  import sailpoint.connector.*;
  import java.text.*;

  // subtype values for email , Telephone or system user name
  String SUBTYPE_EMAIL = "0010"; //Sub info type for email address
  String SUBTYPE_PHONE= "0020"; //Sub info type for telephone number 
  String SUBTYPE_SY_USERNAME= "0001";   //Sub info type for sy-username which can be mapped to SAMAccountName of AD or RACFID
  ProvisioningResult result = new ProvisioningResult();

  //This function will modify the SAP User data email address , Telephone or system user name if recieved in the plan
  public void doProvision() throws Exception 
  {
    List<AccountRequest> accReqList = plan.getAccountRequests();
    String accNativeIdentity = null;
    String beginDateStr ="" ;
    String  endDateStr ="" ;
    SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");    
    if (!Util.isEmpty(accReqList)) 
    {
      for( AccountRequest accountReq : accReqList ) 
      {
        result.setStatus( ProvisioningResult.STATUS_COMMITTED );
        accNativeIdentity = accountReq.getNativeIdentity();
		
        // For update operation only Email,Telephone,SY-UNAME atrribute are supported
        AttributeRequest emailAttr = accountReq.getAttributeRequest("Email");
        AttributeRequest phoneAttrib = accountReq.getAttributeRequest("Telephone");
        AttributeRequest syUserAttrib = accountReq.getAttributeRequest("System user name (SY-UNAME)");

        HashMap beginEndDateList = getCommunicationData(accNativeIdentity);
      
     	  //Finding the email attribute in provisioning plan and trying to modify the account's email id
        if ( null != emailAttr ) 
        {
          if(null !=beginEndDateList &amp;&amp; beginEndDateList.containsKey("emailBegin")) 
          {
            beginDateStr = formatter.format(beginEndDateList.get("emailBegin"));
            endDateStr = formatter.format(beginEndDateList.get("emailEnd"));
          }
          modifyCommunicationData(accNativeIdentity, emailAttr.getValue(), SUBTYPE_EMAIL,beginDateStr,endDateStr);
        }

        //Finding the Telephone attribute in provisioning plan and trying to modify the account's phone
        if ( null != phoneAttrib ) 
        {
          if(null !=beginEndDateList &amp;&amp; beginEndDateList.containsKey("phoneBegin")) 
          {
            beginDateStr = formatter.format(beginEndDateList.get("phoneBegin"));
            endDateStr = formatter.format(beginEndDateList.get("phoneEnd"));
          }
          modifyCommunicationData(accNativeIdentity, phoneAttrib.getValue(), SUBTYPE_PHONE,beginDateStr,endDateStr);
        }

        //Finding the system user name attribute in provisioning plan and trying to modify the account's System User Name
        if ( null != syUserAttrib) 
        {
          if(null !=beginEndDateList &amp;&amp; beginEndDateList.containsKey("syUserBegin")) 
          {
            beginDateStr = formatter.format(beginEndDateList.get("syUserBegin"));
            endDateStr = formatter.format(beginEndDateList.get("syUserEnd"));
          }
          modifyCommunicationData(accNativeIdentity,syUserAttrib.getValue(), SUBTYPE_SY_USERNAME,beginDateStr,endDateStr);
        }
      }
    }
  }

  
  // This function will get the communication details about a given employee
  // In this example the email, Telephone and system user name begin and end date will be retrieved
  public HashMap getCommunicationData( String id ) throws Exception 
  {
    HashMap commAttrsList = new HashMap();
    JCoFunction getCommDetail = connector.getFunction(destination, "BAPI_EMPLCOMM_GETDETAILEDLIST");
    getCommDetail.getImportParameterList().setValue("EMPLOYEENUMBER", id);
    getCommDetail.getImportParameterList().setValue("TIMEINTERVALLOW", new Date());
    getCommDetail.getImportParameterList().setValue("TIMEINTERVALHIGH", new Date());
    try 
    {
      getCommDetail.execute(destination);
    } catch (Exception e) 
    {
      connector.checkForExceptions(getCommDetail);
      throw new Exception(e);
    }
    JCoTable commTable = getCommDetail.getTableParameterList().getTable("COMMUNICATION");
    if ( commTable != null ) 
    {
      int rows = commTable.getNumRows();
      for (int i = 0; i &lt; rows; i++) 
      {
        commTable.setRow(i);
        String commType = commTable.getString("SUBTYPE");
        commAttrsList = getDateData(commTable, commAttrsList, commType);
      }
    }
    //log.error("commAttrsList :::"+commAttrsList);
    return commAttrsList;
  }


  // function captures the begin date and end date
  public HashMap getDateData(JCoTable commTable, HashMap commAttrsList, String commType) 
  {
    Date validBegDate = commTable.getDate("VALIDBEGIN");
    Date validEndDate = commTable.getDate("VALIDEND");
    if ( validBegDate != null &amp;&amp; validEndDate != null ) 
    {
      if (commType.equals(SUBTYPE_EMAIL)) 
      {
        commAttrsList.put("emailBegin", validBegDate);
        commAttrsList.put("emailEnd", validEndDate);
      } else if (commType.equals(SUBTYPE_PHONE)) 
      {
        commAttrsList.put("phoneBegin", validBegDate);
        commAttrsList.put("phoneEnd", validEndDate);
      }else if (commType.equals(SUBTYPE_SY_USERNAME)) 
      {
        commAttrsList.put("syUserBegin", validBegDate);
        commAttrsList.put("syUserEnd", validEndDate);
      }

    }
    return commAttrsList;
  }


  /**Function modifies the email address , Telephone number and System user name of SAP HR record.
            If Email or Phone is present(assigned) then used BAPI_EMPLCOMM_CHANGE
            If Email or Phone is not present(assigned) then used BAPI_EMPLCOMM_CREATE
          * @param userId
          * @param parValue
          * @param type
          * @param begDate
          * @param endDate
          * @throws ConnectorException
          */
  private void modifyCommunicationData( String userId, String parValue, String type,String begDate,String endDate )  throws ConnectorException 
  {
    JCoFunction jcoFunctionObject;
    if (begDate.length() > 1 ) { //If date is alreday present then use BAPI_EMPLCOMM_CHANGE to modify data
      jcoFunctionObject = connector.getFunction(destination,"BAPI_EMPLCOMM_CHANGE");
    } else { //If date is not present then use BAPI_EMPLCOMM_CREATE to add data
      jcoFunctionObject = connector.getFunction(destination,"BAPI_EMPLCOMM_CREATE");
    }
    //log.error("userId::"+userId);
    //log.error("parValue::"+parValue);
    //log.error("type::"+type);
    //log.error("begDate::"+begDate);
    //log.error("endDate::"+endDate);
    if(begDate.equals(""))
    {
      Date today = new Date();  
      Calendar cal = Calendar.getInstance();  
      cal.setTime(today);  
      cal.add(Calendar.DATE, -1);  

      SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");  
      begDate = sdf.format(cal.getTime());  
    }
    if(endDate.equals(""))
    {
      endDate = "99991231";
    }
    // BAPI locks the record for processing
    JCoFunction functionEnqueue = destination.getRepository().getFunction("BAPI_EMPLOYEE_ENQUEUE");
    functionEnqueue.getImportParameterList().setValue("NUMBER", userId);
    if ( functionEnqueue == null )
      throw new RuntimeException("BAPI_EMPLOYEE_ENQUEUE not found in SAP.");
    // BAPI to modify Communication data - email and phone
    if ( jcoFunctionObject == null )
      throw new RuntimeException("BAPI_EMPLCOMM_CHANGE  not found in SAP.");
    String returnPersonnelID = null;
    jcoFunctionObject.getImportParameterList().setValue("EMPLOYEENUMBER", userId); // Personal Number
    jcoFunctionObject.getImportParameterList().setValue("SUBTYPE", type); // SubType 0010/0020 - Email/Phone
    jcoFunctionObject.getImportParameterList().setValue("VALIDITYBEGIN", begDate); // Begin Date
    jcoFunctionObject.getImportParameterList().setValue("VALIDITYEND", endDate); // End Date
    jcoFunctionObject.getImportParameterList().setValue("COMMUNICATIONID", parValue); // Email Address to modify
    // BAPI unlocks the record after processing
    JCoFunction functionDequeue = destination.getRepository().getFunction("BAPI_EMPLOYEE_DEQUEUE");
    functionDequeue.getImportParameterList().setValue("NUMBER", userId);
    if ( functionDequeue == null )
      throw new RuntimeException("BAPI_EMPLOYEE_DEQUEUE not found in SAP.");
    try {
      // executing Bapis
      JCoContext.begin(destination);
      functionEnqueue.execute(destination);
      jcoFunctionObject.execute(destination);
      //log.error("Function executed successfully");
      functionDequeue.execute(destination);
    } catch (ConnectorException e) {
      throw e;
    } finally {
      JCoContext.end(destination);
    }
  }


  //////////////////// BEGIN CODE ///////////////////
  
  doProvision(); // UPDATE SAP HR EMAIL and RACFID//

  //////////////////// END CODE ///////////////////

  
  return result;</Source>
</Rule>

We hope this helps as you work with SAP HR and SailPoint IdentityIQ.