Published at: 2025-10-30

4.1 [Function Component] Pre-Sync, During-Sync, and Post-Sync Functions


1. Pre-sync: Custom Function Can Filter Data Execution

If the returned map from the custom function contains “isExec”:”false” or “isExec”:false, the current sync will stop executing and the target data will not be changed.

Test scenario: Add “isExec”:”false” or “isExec”:false in the returned Map of the custom function; the target data will not be modified.

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

2. Execute Custom Function During Sync

After the function runs, any mapping values modified inside the function will be applied; tenant_id and object_describe_api_name (object API name) will not change.

Test scenario: When only creating new records, the Sub-object will be included; during updates the object mapping values will be updated. Therefore, if you do not specially distinguish Primary Object and Sub-object, updated records will not differentiate them — both Primary Object and Sub-object names will be overwritten by values assigned in the custom function.

Function code: 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;

3. Execute Custom Function After Sync

After the function runs, mapping values modified inside the function will not change tenant_id or object_describe_api_name.

Test scenario: Data synchronization is unaffected; the system simply passes the data to the custom function. Check logs to verify behavior.

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

The following describes specific input parameters (if you are unsure what fields are available, implement the function first and log the input — note that create and update inputs differ) and provides example functions:

Pre-sync: after passing data scope validation

Main input fields: { “destObjectApiName” : “”,// destination object API name “sourceData” : {“fieldApiName”:”fieldValue”}// source object field data }

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 will filter out this record from syncing return syncArg;

During sync: before writing to destination system

Main input fields: { “destDetailSyncDataIdAndDestDataMap” : {“”:{“fieldApiName”:”fieldValue”}},// destination object detail “destData” : {“fieldApiName”:”fieldValue”}// destination object field data // If creating a Primary Object, destData contains primary data and destDetailSyncDataIdAndDestDataMap contains details; if updating, primary and Sub-object data are both in destData (updates are handled individually) }

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

Post-sync: after writing to destination system

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

Simple example: // CRM->ERP: write destination 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;// 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;

4. Log in to Kingdee K3 WebAPI to Retrieve Data

// Define request parameters: URL, username, password, data center String url = “”;//http://jxsz.fortiddns.com:58000/k3cloud/ String userName = “”; String passWord = “”; String acctId = “”;//62415a905fb572

// Request headers Map headMap = [“Content-Type”:”application/json”];

// Kingdee K3 cloud login authorization: parameters required — URL, login username, password, language, data center ID, service method name String login = “Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc”; // Query API method String queryMethod = “Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc”; Map bodyMap1 = [:]; // Return structure Map returnMap = [:]; bodyMap1.put(“lcid”, “2052”); bodyMap1.put(“userName”, userName); bodyMap1.put(“passWord”, passWord); bodyMap1.put(“acctId”, acctId); StringBody body = StringBody.builder().content(bodyMap1).build() Request request = Request.builder() .method(“POST”) .url(url+login) .timeout(7000) .retryCount(0) .header(“Content-Type”,”application/json”) .body(body) .build()

def(Boolean error1, HttpResult data1, String errorMessage1) = Fx.http.execute(request); if(error1){ log.info(“Login API call error: “+errorMessage1) } // Extract kdservice-sessionid and ASP.NET_SessionId from login result Map headers = data1[“headers”] as Map; if(headers==null){ Fx.message.throwErrorMessage(“Login failed: “+data1); } String Cookies = headers[“Cookies”] as String; log.info(“Cookies: “+Cookies); String sessionid=Cookies.split(“;”)[0]; String NET_SessionId=Cookies.split(“;”)[1]; sessionid=sessionid.split(“=”)[1]; NET_SessionId=NET_SessionId.split(“=”)[1]; // Request body Map bodyMap = [:]; // Max rows to return Integer TopRowCount=0; // Field keys to query String FieldKeys=”FCUSTID,FNumber”; // Business object form Id String FormId=”BD_Customer”; // Filter string String FilterString=”FNumber != ‘’”; // Max rows Integer Limit=10; // Start row index Integer StartRow=0; // Combine parameters // Combine query parameters Map data = [“TopRowCount”:TopRowCount,”FieldKeys”:FieldKeys,”FormId”:FormId,”FilterString”:FilterString,”Limit”:Limit,”StartRow”:StartRow]; bodyMap.put(“data”, data); // Query data StringBody body1 = StringBody.builder().content(bodyMap).build() Request request1 = Request.builder() .method(“POST”) .url(url+queryMethod) .timeout(7000) .retryCount(0) .header(“Content-Type”,”application/json”) .header(“kdservice-sessionid”,sessionid) .header(“ASP.NET_SessionId”,NET_SessionId) .body(body1) .build() //log.info(url+method); def(Boolean error, HttpResult Result, String Message) = Fx.http.execute(request1); log.info(“Returned data: “+Result); // Begin processing data String contentStr = Result[“content”] as String; if(contentStr){ // Query failed if(contentStr.contains(“ResponseStatus”)){ Fx.message.throwErrorMessage(contentStr); } // If data exists, process it; if empty, skip List contentList = Fx.json.parseList(contentStr); log.info(“contentList: “+contentList); String[] keyList = FieldKeys.split(“,”);

contentList.each{ item -> List eachDataList=item as List; log.info(“eachDataList:”+eachDataList) Map eachData=[:] // Each record eachDataList.eachWithIndex{ value,int i -> eachData.put(keyList[i], value) } log.info(“eachData:”+eachData) } }

Submit Feedback