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
- Fixed input parameter: Map syncArg

-
Fixed return: return syncArg;
-
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. -
When creating data: syncArg.objectData is the Primary Object data; syncArg.details contains the Sub-object (detail) data.
-
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;