Technical Articles
How to use generateNextPersonID and $batch operation for hiring an employee in SuccessFactor’s using CPI
Introduction :
In this post I want to show you how to use generate personID and hire employee in SF’s using $batch operation in CPI.
How to use generate personID API?
Step 1:
Add one HTTP Connection and put Address : https://{datacenterAPIserver}/odata/v2/generateNextPersonID
Step 2 :
Reponse will come like this where “10010” is the next personID:
<d:GenerateNextPersonIDResponse xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:type="SFOData.GenerateNextPersonIDResponse">
<d:personID>10010</d:personID>
</d:GenerateNextPersonIDResponse>
Step 3 :
I am removing “d:” using groovy script for storing personID in a property using content modifier for later use.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import java.lang.*
def Message processData(Message message) {
def body = message.getBody(java.lang.String) as String;
body = body.replaceAll("d:", "");
message.setBody(body);
return message;
}
Why I am using $batch for creating employee?
For hiring an employee in SF’s, there are some mandatory entities which we need to create in sequence. The entities sequence are as follows:
- User
- PerPerson
- EmpEmployment
- EmpJob
- PerPersonal
And additionally we are creating other entities like PerNationalId, PerAddressDEFLT and PerPhone for creating an employee in this post.
As partial creation of an employee is not supported, so I am using $batch operation because if any one these entites got errored out then employee will not get created. Only if all the entities are having correct value and are in correct format then only the employee will get created in SuccessFactor’s.
Step 1:
Converting XML To JSON after mapping all the mandatory fields of the all entities.
Step 2:
I am taking only the fields names from the JSON body of the entities and storing in a property.
For Example :
Original JSON body :
{"User":{"User":{"userId":"10010","firstName":"Peggy","lastName":"Carter","hireDate":"2023-02-27T00:00:00.000","gender":"F","nationality":"999999999999","status":"t"}}}
JSON body after using groovy script :
"userId":"10010","firstName":"Peggy","lastName":"Carter","hireDate":"/Date(1677456000000)/","gender":"F","nationality":"999999999999","status":"t"
And storing this body in property with the help of content modifier
Note : You also need to convert the date time to EPOCH format, you can do it by the given script :
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import groovy.xml.XmlUtil;
import groovy.xml.StreamingMarkupBuilder;
import java.text.SimpleDateFormat;
import java.util.Date;
import groovy.xml.*; def Message processData(Message message) {
def properties = message.getProperties();
def hiredate = properties.get("hiredate");
if(hiredate!=''){
def sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss")
def date = sdf.parse(hiredate)
def epoch = date.time
dotNetDate = "/Date(" + epoch + ")/"
}
else{
dotNetDate='';
}
message.setProperty("hiredate", dotNetDate);
return message;
}
Step 3 :
Plain Concatenate all the entites by using Gather and add Content Modifier for defining body:
Add Header in Content Modifier and put
Content-Type – Constant – multipart/mixed; boundary=batch_mybatch
Use the below format in Message Body for creating an employee :
--batch_mybatch
Content-Type: multipart/mixed; boundary=changeset_mychangeset1
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "User(userId='${property.personID}')"
},
${property.userbody}
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "PerPerson(personIdExternal='${property.personID}')"
},
${property.personbody}
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "EmpEmployment(personIdExternal='${property.personID}',userId='${property.personID}')"
},
${property.emplbody},"isContingentWorker":true
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "WorkOrder(effectiveStartDate=datetime'${property.startdate}',userSysId='${property.personID}')"
},
${property.workbody}
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "EmpJob(seqNumber=1,startDate=datetime'${property.startdate}',userId='${property.personID}')"
},
${property.jobbody}
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "PerPersonal(personIdExternal='${property.personID}',startDate=datetime'${property.startdate}')"
},
${property.personalbody}
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "PerNationalId(cardType='MisparZehut',country='ISR',personIdExternal='${property.personID}')"
},
${property.nationalbody},"isPrimary":true
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "PerAddressDEFLT(addressType='home',personIdExternal='${property.personID}',startDate=datetime'${property.startdate}')"
},
${property.addressbody}
}
--changeset_mychangeset1
Content-Type: application/http
Content-Transfer-Encoding: binary
POST upsert HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"__metadata": {
"uri": "PerPhone(phoneType='${property.optionPT}',personIdExternal='${property.personID}')"
},
${property.phonebody},"isPrimary":true
}
--changeset_mychangeset1--
--batch_mybatch--
Step 4 :
Add one HTTP Connection for calling $batch :
where Address will be : https://{datacenterAPIserver}/odata/v2/$batch
The response will come like, if it was a succes and you can also see in SF’s :
--batch_a6a959f5-0d6a-48a6-9d2f-20f9ac746080
Content-Type: multipart/mixed; boundary=changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 150
{
"d" : [
{
"key" : "10010", "status" : "OK", "editStatus" : "INSERTED", "message" : null, "index" : 0, "httpCode" : 201, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 177
{
"d" : [
{
"key" : "PerPerson/personIdExternal=10010", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 208
{
"d" : [
{
"key" : "EmpEmployment/personIdExternal=10138,EmpEmployment/userId=10010", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 229
{
"d" : [
{
"key" : "WorkOrder/effectiveStartDate=2023-02-27T00:00:00.000+01:00,WorkOrder/userSysId=10010", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 559
{
"d" : [
{
"key" : "EmpJob/seqNumber=1,EmpJob/startDate=2023-02-27T00:00:00.000+01:00,EmpJob/userId=10010", "status" : "OK", "editStatus" : "UPSERTED","message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 231
{
"d" : [
{
"key" : "PerPersonal/personIdExternal=10010,PerPersonal/startDate=2023-02-27T00:00:00.000+01:00", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 242
{
"d" : [
{
"key" : "PerNationalId/cardType=MisparZehut,PerNationalId/country=ISR,PerNationalId/personIdExternal=10010", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 272
{
"d" : [
{
"key" : "PerAddressDEFLT/addressType=home,PerAddressDEFLT/personIdExternal=10010,PerAddressDEFLT/startDate=2023-02-27T00:00:00.000+01:00", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76
Content-Type: application/http
Content-Transfer-Encoding: binary
HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
DataServiceVersion: 1.0
successfactors-message: X-SF-Correlation-Id, successfactors-sourcetype are missing in request headers
Content-Length: 201
{
"d" : [
{
"key" : "PerPhone/personIdExternal=10010,PerPhone/phoneType=526", "status" : "OK", "editStatus" : "UPSERTED", "message" : null, "index" : 0, "httpCode" : 200, "inlineResults" : null
}
]
}
--changeset_2e0455d6-79e3-4161-871e-0cb754f8ff76--
--batch_a6a959f5-0d6a-48a6-9d2f-20f9ac746080--
Conclusion :
In this blog post you will know how to hire an employee using generateNextPersonID and $batch operation.
Hi Rahul,
Good read!!
I would like to know how are you parsing the responses received from SF post creating an employee for successful and unsuccessful cases for monitoring and debugging for future troubleshooting. Because the payload which is being used can’t be parsed either via json/xml reader.
Regards,
Sai Krishna V
LinkedIn
Hi Sai,
Thanks for reading,
Yes the response payload can't be parsed either via json/xml reader, so I am searching for "HTTP/1.1 200 OK" in the payload using groovy script. If it contains "HTTP/1.1 200 OK" in the payload, then the employee is successfully created. As I am using $batch operation, partial creation of an employee is not supported.
And in case of error the response of an error body will show one entity error at a time, so you can store that error in a custom field and debug.
BR,
Rahul