Published at: 2025-10-30

4.3 [Function Components] Three Types of Custom Functions


4.21.1 Introduction to Three Types of Custom Functions Supported by the ERP Integration Platform

  1. Fixed Input Parameter: Map syncArg

picture coming soon:

  1. Fixed Return: return syncArg;

  2. Custom Function Validation:
    The function body is considered an update/create/invalidate call if it contains any of the following strings:
    • Fx.object.create
    • Fx.object.batchCreate
    • Fx.object.update
    • Fx.object.batchUpdate

    Scenario: If the custom function includes the above strings (even in comments) and contains a string matching the bound field’s apiName (comments are also checked), the strategy will fail to activate and throw a “Function Validation Failed” exception.

  3. Data Creation:
    • syncArg.objectData contains the Primary Object data.
    • syncArg.details contains the Sub-object data.
  4. Data Update:
    • syncArg.objectData may contain either Primary Object or Sub-object data. Use objApiName to determine the type.

4.21.2 Pre-Sync Custom Function Execution for Data Filtering

If the returned result includes "isExec": "false", the sync process will halt, and the target data will remain unchanged.

Test Scenario: Add "isExec": "false" or "isExec": false to the custom function’s return Map. The target data will not update.

Function Code:
java Map map = ["details":syncArg.details, "objectData":syncArg.objectData, "isExec":"false"]; return map;

4.21.3 Mid-Sync Custom Function Execution

After execution, mapped values written in the function will update, but the enterprise ID and object apiName remain unchanged.

Test Scenario:
- Only new data carries Sub-objects.
- Updates modify mapped values. Without distinguishing between Primary and Sub-objects, all objects will update with the assigned values from the custom function.

Function Code:
java log.info("Event Type: " + syncArg.destEventType); log.info(syncArg.objectData); log.info(syncArg.details); Map objectData = syncArg.objectData as Map; objectData.name = "Modified by Custom Function"; Map map = ["details":syncArg.details, "objectData":syncArg.objectData]; log.info(map); return map;

4.21.4 Post-Sync Custom Function Execution

After execution, mapped values written in the function will update, but the enterprise ID and object apiName remain unchanged.

Test Scenario: The sync process is unaffected. Data is passed to the custom function for logging purposes.

Function Code:
java Map map = ["details":context.details, "objectData":context.data, "afterSync": "yes001"]; return map;

Key Input Fields and Examples

Pre-Sync (After Data Scope Validation)

Primary Input Fields:
java { "destObjectApiName": "", // Target object apiName "sourceData": {"fieldApiName": "fieldValue"} // Object field info }

Example:
java 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 to false filters out the data from syncing return syncArg;

Mid-Sync (Before Writing to Target System)

Primary Input Fields:
java { "destDetailSyncDataIdAndDestDataMap": {"": {"fieldApiName": "fieldValue"}}, // Target Sub-object data "destData": {"fieldApiName": "fieldValue"} // Target Primary Object data // For new Primary Objects, data is in `destData`; Sub-objects are in `destDetailSyncDataIdAndDestDataMap`. Updates handle Primary/Sub-objects separately. }

Example:
java // Modify the customerShortName field log.info(syncArg); syncArg["objectData"]["customerShortName"] = "dddddd"; log.info(syncArg); return syncArg;

Post-Sync (After Writing to Target System)

Primary Input Fields:
java { "sourceDataId": "5fead1146660700001170e3d", // Source data ID (only for CRM→ERP direction) "sourceObjectApiName": "AccountObj", // Source object apiName "completeDataWriteResult": { // Target system write result "detailWriteResults": [], // Sub-object results "errCode": 0, "success": true, "destEventType": 1, "errMsg": "success", "writeResult": { // Primary Object result (errCode "s106240000" = success) "errCode": 5001, "success": false, "syncDataId": "3ab1c2c2ffe04111b3e713632d5a4f76", "errMsg": "Preprocessing error: External HTTP call failed. Error: 100, SAP system BP name already exists. ::errCode=s306240003", "destDetailSyncDataIdAndDestDataMap": {} } }, "destObjectApiName": "AccountObj_1el03su6s", // Target object apiName "objectData": { // Target data "tenant_id": "706089", // Enterprise ID "object_describe_api_name": "AccountObj_1el03su6s", // Object apiName "_id": "5fead2696532bf0001e524e4" }, "details": {} // Sub-object data }

Example:
java // CRM→ERP: Write target object ID back to CRM source object log.info(syncArg); if (syncArg["objectData"]["id"] != null && syncArg["objectData"]["id"] != "" && syncArg["sourceDataId"] != null && syncArg["sourceDataId"] != "") { String destDataId = syncArg["objectData"]["_id"] as String; // Target 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") { def (Boolean error, Map data, String errorMessage) = Fx.object.update( "AccountObj", sourceDataId, ["field_b25i7__c": destDataId], true ); log.info(errorMessage); } } return syncArg;

Submit Feedback