Published at: 2025-10-30

4.3 [Function Components] Three Types of Custom Functions


4.21.1 Three types of custom functions currently supported by the ERP Integration Platform

  1. Fixed input parameter: Map syncArg

image

  1. Fixed return: return syncArg;

  2. Custom function validation: If the custom function code contains any of the following strings — Fx.object.create, Fx.object.batchCreate, Fx.object.update, Fx.object.batchUpdate — this indicates the function body performs create/update/void operations.
    Scenario: If the custom function body contains any of the above strings (string comments are also detected as valid matches) and also contains a string matching a bound field’s apiName (comments will also be detected), the synchronization policy cannot be enabled and an error “function validation failed” will be raised.

  3. When creating data: syncArg.objectData is the Primary Object data; syncArg.details contains the Sub-object (detail) data.

  4. When updating data: syncArg.objectData may contain either Primary Object data or Sub-object data — determine which by checking objApiName.

4.21.2 Pre-sync custom function execution supports data filtering

If the returned result from the function includes “isExec”:”false” (or “isExec”:false), this synchronization record will be filtered and will not proceed; the target data will not be changed.

Test scenario: Add “isExec”:”false” or “isExec”:false to the Map returned by the custom function — the target data will not be modified.

Function example: Map map = [“details”:syncArg.details, “objectData”:syncArg.objectData, “isExec”:”false” ]; return map;

4.21.3 Executing custom functions during sync (before writing to target)

After the function runs, any mapping values modified in the function will be used; tenant id and object apiName will not change.

Test scenario: Only create operations carry Sub-object data. During update, the function updates object mapping values; if you do not specially distinguish Sub-object from Primary Object, the update will not differentiate and will update both — names of Primary Object and Sub-object will be overwritten by the values set in the custom function.

Function example: log.info(“Event type:” + syncArg.destEventType); log.info(syncArg.objectData); log.info(syncArg.details); Map objectData = syncArg.objectData as Map; objectData.name = “Custom function modification” Map map = [“details”:syncArg.details, “objectData”:syncArg.objectData]; log.info(map); return map;

4.21.4 Executing custom functions after sync (after writing to target)

After the function runs, any mapping values modified in the function will be returned; tenant id and object apiName will not change.

Test scenario: Data synchronization is not affected; the system simply passes data to the custom function. Check the Report to determine behavior.

Function example: Map map = [“details”:context.details, “objectData”:context.data, “afterSync” : “yes001”]; return map;

The specific input fields (if you are not sure what input fields are available, implement the function first and log the input to inspect — note: create and update inputs differ) and function examples are as follows:

Pre-sync: after data-range validation

Main input fields: { “destObjectApiName”: “”, // target object apiName “sourceData”: {“fieldApiName”:”fieldValue”} // source object fields }

Simple example: log.info(syncArg); String destObjApiName=syncArg[“destObjectApiName”] as String; log.info(“destObjectApiName:”+destObjApiName); if(“object_xo21i__c”==destObjApiName){ return syncArg; } Map objectData=syncArg[“objectData”] as Map; String customerCode=objectData[“customerCodeHead”] as String; syncArg[“isExec”]=false; // setting this field to false filters out this record from syncing return syncArg;

During sync: before writing to the destination system

Main input fields: { “destDetailSyncDataIdAndDestDataMap”: {“”: {“fieldApiName”:”fieldValue”}}, // destination detail data “destData”: {“fieldApiName”:”fieldValue”} // destination primary object fields // If creating a Primary Object, main data is in destData and detail data is in destDetailSyncDataIdAndDestDataMap. // For updates, both Primary and Sub-object data are in destData (updates are single operations). }

Simple example: // modify customerShortName field log.info(syncArg); syncArg[“objectData”][“customerShortName”]=”dddddd” log.info(syncArg); return syncArg;

Post-sync: after writing to the destination system

Main input fields: { “sourceDataId”: “5fead1146660700001170e3d”, // source data id — present only for CRM -> ERP direction “sourceObjectApiName”: “AccountObj”, // source object apiName “completeDataWriteResult”: { // result of writing data to destination “detailWriteResults”: [], // detail-write results “errCode”: 0, “success”: true, “destEventType”: 1, “errMsg”: “success”, “writeResult”: { // primary-data result — errCode s106240000 means success; other codes indicate failure returned by the API “errCode”: 5001, “success”: false, “syncDataId”: “3ab1c2c2ffe04111b3e713632d5a4f76”, “errMsg”: “Preprocessing service call error: external HTTP call failed, error info:100, SAP BP name already exists, duplicate creation not allowed.::errCode=s306240003”, “destDetailSyncDataIdAndDestDataMap”: {} } }, “destObjectApiName”: “AccountObj_1el03su6s”, // destination object apiName “objectData”: { // destination data “tenant_id”: “706089”, // tenant id “object_describe_api_name”: “AccountObj_1el03su6s”, // object apiName “_id”: “5fead2696532bf0001e524e4” }, “details”: {} // detail data }

Simple example: // CRM -> ERP: write destination object id back to the CRM source record log.info(syncArg) if(syncArg[“objectData”][“id”]!=null && syncArg[“objectData”][“id”]!=”” && syncArg[“sourceDataId”]!=null && syncArg[“sourceDataId”]!=””){ String destDataId=syncArg[“objectData”][“_id”] as String; // destination data id String sourceDataId=syncArg[“sourceDataId”] as String; // source data id String errCode=syncArg[“completeDataWriteResult”][“writeResult”][“errCode”] as String; log.info(“–“+errCode) if (errCode ==”0”){ // && destDataId.length()<11 def (Boolean error,Map data,String errorMessage) = Fx.object.update(“AccountObj”,sourceDataId, [“field_b25i7__c”:destDataId],true); log.info(errorMessage) } } return syncArg;

Submit Feedback