Enterprise Resource Planning Blogs by SAP
Get insights and updates about cloud ERP and RISE with SAP, SAP S/4HANA and SAP S/4HANA Cloud, and more enterprise management capabilities with SAP blog posts.
cancel
Showing results for 
Search instead for 
Did you mean: 
gerald_reinhard
Product and Topic Expert
Product and Topic Expert
29,139

Creating an custom object definition and maintain some data

Employee Central offers a powerful feature to create custom generic objects also called Metadata Framework (MDF) Objects. This feature is available via "Admin Tools-->Configure Object Definitions" if the logged in user has the corresponding permissions. The following screenshots shows such a custom generic object called cust_LMS_Trial. Each record of this object has a autogenerated code (externalCode), an associations to a user in employee central (externalName) and four fields of type string (cust_Field1,...cust_Field4). All other fields are system generated fields:

This object definition can be created using a simple UI without any coding required. And after saving the object definition above also a UI to enter data is available via "Admin Tools-->Manage data":

Hint: In some cases it might be required to refresh the OData API metadata after creating the object before a first successful API call. This refresh can be found in "Admin Tools-->OData API Metadata Refresh and Export" (after enabling this feature in permissions in group "Manage Integration Tools").

Retrieve data from the created generic object using OData

After saving this object definition OData API for reading and writing the data are available instantly. Note that this is only the case if

  • you select "API Visibility" accordingly while creating the custom generic object and
  • if the user used to call the API has proper permissions set  ("Permissions-->Manage Integration Tools-->Admin access to OData API" and "Metadata Framework-->Read/Write Permission on Metadata Framework". See also OData API Programmers Guide at http://help.sap.com/hr_api )

After creating an object definition as described above a rest client such as "Advanced Rest Client" in google chrome can be used to call APIs for the created object cust_LMS_Trial in employee central.

The easiest API call would be the retrieval of all records of the created object cust_LMS_Trial. A request for this would look like this in our salesdemo environment (note that the URL might differ in your environment, please refer to the OData API Programmers Guide for the right URL in your case):

Request-URL and Operation:

GET https://salesdemo4.successfactors.com/odata/v2/cust_LMS_Trial?$format=JSON

Request-Header:

Authorization: Basic dXNlckBjb21wYW55OnBhc3N3b3Jk

Remark: The cryptic authorization string above is the base64 encoding of the username, the instance or company you use to login and the corresponding password of the user in this company. To get the string above any base64 encoding tool can be used to encode the string user@company:password (for example notepad++ and the mime-tools available in this editor). The same request including parts of the repsonse in the advanced rest client:

The parameter $format is used to influence the output format and returns the data in JSON format (default value is ATOM/XML).

Create new data for the generic object using OData (POST)

In order to create new data via OData APIs, a POST operation is used (see also http://www.odata.org/documentation/odata-version-2-0/operations). To create data for our object cust_LMS_Trial we have to switch our operation to POST and add a content type parameter into the OData request header. This content type defines the format of the payload, in our case JSON, and the used character set (here utf-8):

Request URL and operation:

POST https://salesdemo4.successfactors.com/odata/v2/cust_LMS_Trial?$format=JSON

Request Header:

Authorization: Basic dXNlckBjb21wYW55OnBhc3N3b3Jk

Content-Type: application/json;charset=utf-8

Payload:

{

"cust_Field1": "15",

"cust_Field4": "40",

"cust_Field3": "30",

"cust_Field2": "20",

"externalName": "greinhard"

}

Response:

Status "201 Create" and  created data in response

The same create request in google chrome:

Update existing data for the generic object using OData (PUT)

In order to update existing data the PUT operation has to be used and the corresponding record has to be identified in the URL. A OData request to update a record for cust_LMS_Trial with key 162 would look like this. Pleas not that only the operation and the url changes compared to creating data:

Request URL and operation:

PUT https://salesdemo4.successfactors.com/odata/v2/cust_LMS_Trial(162L)?$format=JSON

Request Header:

Authorization: Basic dXNlckBjb21wYW55OnBhc3N3b3Jk

Content-Type: application/json;charset=utf-8

Payload:

{

"cust_Field1": "151",

"cust_Field4": "401",

"cust_Field3": "301",

"cust_Field2": "201",

"externalName": "greinhard"

}


Response:

Status "200 OK" and no data in response

Same request in google chrome:

Important remarks about updating links with OData

Using field "externalName" in the example above as a simple field is just a shortcut to allow easy creation of data. Usually associations have to be created using a dedicated navigation property. This shortcut version of creating data does not work anymore if the field is marked as required and the corresponding permission checks are enabled for those fields in the object definitions:

From that point of view it is a not a good idea to use the shortcut if you plan to switch later to permission enabled mode and make this field "externalName" required.

In such a case it is better to use a payload as follows:

{

"cust_Field1": "11",

"cust_Field4": "41",

"cust_Field3": "31",

"cust_Field2": "21",

"externalNameNav": {

   "__metadata": {

      "uri": "https://salesdemo4.successfactors.com:443/odata/v2/User('greinhard')",

      "type": "SFOData.User"

      }

   }

}

27 Comments
lukemarson
Active Contributor
0 Kudos

Great contribution Gerald!

former_member182468
Contributor
0 Kudos

Beautiful Blog !

Had a question- when we try to retrieve data from custom generic/metadata object using Odata API it provides details of all the records of that generic objects.

Is it possible to just get the username of logged in user/or the one you pass during base64 encoding through Odata API calls.

Thanks,
Sahiba Gandhi

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi,

I'm not 100% sure if I got your question right because if you are able to build the base64 string from username@company:password why would you want the API to return the username to you again? I would be really interested in your use case. May I ask you to explain what you want to achieve.

A view possible answers to your question:

Of cause an API call like this

https://salesdemo4.successfactors.com/odata/v2/User?$filter=username+eq+'admin'&$select=username&$fo...

would return the username only but you would have to know the username when building the query (or any other ID of the user)

To figure out the username used for an API call, an easy trick would be to create or change some data as mentioned above and read it it afterwards and using the createdBy or lastModifiedBy fields to get the userID (not the username). To get from the userID the username the following OData call can be used:

https://salesdemo4.successfactors.com/odata/v2/User?$filter=userId+eq+'admin'&$select=username&$form...

Please note that userId and username can be the same (in this case admin) but must not be the same. Fields like createdBy and lastModifiedBy contain the userId and not the username.

Best regards

  Gerald

former_member182468
Contributor
0 Kudos

Hi Gerald,

Thanks for your response.

What I want to achieve is - I would like to read the logged in user through an Odata API call in a custom portlet/tile.

Thanks,
Sahiba

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Sahiba,

if you are embedding an UI into employee central the EC system can be configures to send a SAML assertion to your application. Hence the application server will get the user ID via this SAML assertion. The user ID in this SAML assertion can be used to get further data from EC via OData APIs (see 2nd example above) and will also be used by your application to authenticate without having to login again. If you application is running on Hana Cloud Platform (HCP) you will get also further benefits like theming etc..

Best regards

   Gerald

former_member182468
Contributor
0 Kudos

Thanks Gerald for your inputs on this.

HCP is surely a great option,will check through the SAML way as well.

Thanks!

Sahiba

Former Member
0 Kudos

Nice blog Gerald,

Is it possible to link the custom object to external API for CRUD operations? actual data for the custom object will not reside in Success factor. Custom object will call the API that will push/pull the information in some other system.

Thanks,

Faisal

former_member50433
Discoverer
0 Kudos

Hi Gerald,

Great Blog!

I have a question is it possible to read data from multiple users in one call provided I have permissions?

Thanks,

Satish

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Faisal,

not sure what exactly is your use case but technically you can use a middleware to retrieve data from a third party system and put it into the custom object.

There is no way to call a 3rd party API directly from Success Factors in order to store data into the custom object you will require a part inbetween, for example HCI or HCP.

Best regards

   Gerald

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Satish,

thanks! And yes you can read data from multiple users, you would just use a corresponding filter, e.g. odata/v2/<customObject>?$filter=externalCode+eq+'user1'+and+'externalCode+eq+'user2' (assuming that the user is stored in the externalCode of the customObject)

If a single filter is not possible you could also batch several calls in a $BATCH call, see help.sap.com/hr_api for more details about OData.

Best regards

   Gerald

Former Member
0 Kudos

I have a question here. After some testing it does seem, the creating MDF Objects via OData API does not trigger any onSave Rules(e.g. starting a conditional Workflow) can anybody elaborate on that?

Regards

Mathias

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi, please post the payload.And the link/page number to the documentation you used to copy. BR gerald

Former Member
0 Kudos

I have a question here. When trying to update the entitie JobRequisition via PUT it says, templateId required, but templateId is not updatetable, neither does an upsert work.

Payload is only

{

    "internalStatus": "0"

}

Can somebody elaborate on that "feature" and tell me how to update Jobrequisitions? I check the documentation and in their examples they don't pass templateId.

Second question: How can I use MERGE? i tried it with X-HTTP-Method and X-HTTP-Method-Overwrite but same result as above..

Regards

Mathias

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

Rules should be triggered in case of OData API calls but Workflows are not triggered as of my knowledge in MDF.

gerald_reinhard
Product and Topic Expert
Product and Topic Expert
0 Kudos

I just tried the first JobRequisition in my system. I used the following URL:

URL:

PUT https://apisalesdemo2.successfactors.eu/odata/v2/JobRequisition(81L)

Header:

Content-Type: application/json

Payload:

{    "postalcode": "54497"  }

Result: 200

Did you do anything different (e.g. forgot the L in the ID etc.)

Former Member
0 Kudos

Well I had a lot of Rules which where not triggered, e.g. you change a field value via rule before save. Are there any plans to support workflows? especially for extensions it is often crucial (after all we are in HR :wink: )

Former Member
0 Kudos

No I figuered that the requisition was delted and as soon as the field delted is set you can't change the entity anymore. But many thanks for your time and effort!

Hi, I have been facing this error:

org.apache.olingo.odata2.api.uri.UriNotMatchingException: Could not find property with name: 'cust_payperstartdate'.

This is while upserting compensation data to one of the OData. The payload to this OData looks like this:

<?xml version="1.0" encoding="utf-8"?>
<Root>
<Record>
<RecordNo>1</RecordNo>
<EEID>17</EEID>
<COVERAGE_CATEGORY>N</COVERAGE_CATEGORY>
<CoverageCategory>2</CoverageCategory>
<Paygroup>UM</Paygroup>
<nextPayrollStartDate>2016-12-02T00:00:00.000</nextPayrollStartDate>
<Emp_Status>A</Emp_Status>
<Pay_component>7699</Pay_component>
<PayCompValue>600.0</PayCompValue>
</Record>
</Root>

And the <nextPayrollStartDate> is fetched from custom MDF Object filtered on other dates. So my query looks like this.

Operation: Query(GET)
ResourcePath : cust_payroll_calender?$select=cust_payperstartdate,cust_payperenddate,cust_paygroup,cust_nextpayperstartdate&$filter= cust_payperstartdate le datetime'${property.SFCurrentdate}' and cust_payperenddate ge datetime'${property.SFCurrentdate}'
Path to edmx : edmx/api4_successfactors_com_odata_v2.edmx
Can u please help check and advise.
former_member52530
Discoverer
0 Kudos
Very nice document.

 
0 Kudos

workflow can now the triggerd over the api if you are adding the following urlParameter in or Call

“workflowConfirmed” : “true”

 

Here is the sap note to it. I already tested it out. It is working now perfect 🙂

https://launchpad.support.sap.com/#/notes/2396714/E

 

 

Silvia

Former Member
0 Kudos
When I am trying to access the EC Odata Api from SAP ByD I am getting a Unauthorized error.I am passing the Username in the format "Basic username@companyId:password(base 64 format)",But I am facing a 401 Unauthorized error.

Kindly let me know what value should be passed for the  Username and Password to access the api's?
Former Member
0 Kudos
Hello,

How can i send custom generic objects to SAP ERP? We have success factors add-on in SAP ERP. Is there any standart configuration in SAP ( SOAP, or idoc) to get data for custom MDF Objetcs?

 

Regards,

Nurhan
Former Member
0 Kudos
Check whether the user is having OData API access Role is assigned or not? looking from your question that would be the possible cause.

 
0 Kudos
Hello Gerald,

 

If one of the fields of my custom generic object is of type Attachment, is it possible to upload an attachment to this field via oData post?

 

We have tried in this in our demo system but we cannot upload a document via oData. We were able to make a successful post of the custom object, however, the attachment was not created. Here is a sample of our Post body:
{
"externalCode": "user_a",
"externalName": "Sample Doc Postman 2",
"cust_DocumentNav": {
"userId": "admin",
"fileName": "sample Doc.txt",
"module": "GENERIC_OBJECT",
"fileContent": "VGhpcyBpcyBhIHNhbXBsZSBkb2N1bWVudC4=\r\n"
}
}

The cust_DocumentNav property is an Attachment entity.

 

Here is also a screenshot of our generic object:



 

We would highly appreciate it if you could help us with our problem.

 

Thanks,

Geoff
0 Kudos
Thanks, This helped me a lot and saved my time (y).
Former Member
0 Kudos
Hi,

How can i update the property "isPrimary" of an email address without knowing its value and consecutively add one more email address from my end and set it as primary.

Thanks,

Shivam Rajput
0 Kudos
Hello Gerald ,
i want to get the logged in user in order to use it in odata calls , i have developed java app on HCP and it has a destination to success factors , shall i use the SAML to get the loggedin user id or not?