ERP集成平台产品手册
版本 | 作者 | 日期 | 说明 |
---|---|---|---|
v1.0 | 刘登跃 | 20210218 | |
v1.1 | 冯远华 | 20210414 | 修复目录跳转问题 |
v1.2 | 郑素兰 | 20210420 | 增加了配置demo的步骤 |
目录
[toc]
四. 功能点对接设置
4.1 不能按照时间查询数据的对接
4.2 ERP一个对象,要对接CRM的主从两个对象
ERP一个对象对接CRM主从两个对象,在新建ERP对象的时候需要把ERP对象的拆分类型选择为“ERP对象拆分为主从关系的中间对象”,然后再跟CRM主从对象对接
下面以ERP【销售订单】为例来进行讲解。
1.首先需要新建对象,进入ERP数据同步 -> 数据同步设置 -> ERP对象管理新增对象,拆分类型选择“ERP对象拆分为主从关系的中间对象”,ERP对象编码以及明细编码填写可参考【3.4.3.1.1 新增对象】
2.新建完对象后,根据需求新增ERP主从对象字段,操作可参考【3.4.3.1.2.1 新增字段】
3.之后新建同步策略,拆分后的ERP主对象与CRM主对象映射,拆分后的ERP从对象与CRM从对象映射,如下图
其余对接可参照以上示例配置
4.3 CRM一个对象,对接ERP的两个对象
CRM一个对象,对接ERP两个对象,先建立CRM对象的同步策略,后新增与两个ERP对象对接的策略明细即可
下面以CRM【开票申请】对象为例进行讲解。假设CRM【开票申请】对象,需要对接ERP【增值税销售发票】以及【销售普通发票】
则先新建CRM【开票申请】对象同步策略,然后再新增与ERP【增值税销售发票】以及【销售普通发票】对接的策略明细,如下图
其余此需求可参照该示例进行对接
4.4 ERP一个对象下的数据,按条件对接到CRM两个独立的对象
ERP一个对象按条件对接到CRM两个独立的对象,要先建好ERP对象与CRM两个独立对象的策略明细,在策略明细中设置数据范围条件则可根据该条件过滤数据
下面以ERP出库单为例来进行讲解。假设ERP出库单需要对接到CRM预设对象【发货单】以及自定义对象【销售出库单】,当ERP出库单【销售组织】字段值等于“纷享销客”时,同步到CRM预设对象【发货单】;当ERP出库单【销售组织】字段值不等于“纷享销客”时同步到CRM自定义对象【销售出库单】,则按照如下步骤操作可实现该功能:
1、首先建立CRM【发货单】跟ERP出库单对接的策略明细以及CRM【销售出库单】跟ERP出库单对接的策略明细
2、根据条件当ERP出库单【销售组织】字段值等于“纷享销客”时,同步到CRM预设对象【发货单】;当ERP出库单【销售组织】字段值不等于“纷享销客”时同步到CRM自定义对象【销售出库单】,分别设置策略的数据范围条件如下
CRM【发货单】跟ERP出库单对接的同步策略,数据范围按如下设置
CRM【销售出库单】跟ERP出库单对接的同步策略,数据范围按如下设置
其他条件参照示例配置即可
4.5 CRM的数据同步到ERP后,ERP更改完数据回写到CRM
要完成此对接,需两个同步方向都建立同个CRM对象与同个ERP对象对接的同步策略,并在CRM往ERP方向策略的同步规则中,同步事件监听、同步事件写入只勾选新增,在ERP往CRM方向策略的同步规则中,同步事件监听、同步事件写入只勾选修改
下面以销售订单为例,假设销售订单数据是由CRM同步到ERP,在ERP更改完数据后回写到CRM
1.在两个同步方向都建立销售订单同步策略如下
2.在CRM同步到ERP方向同步策略的同步规则中,同步事件监听、同步事件写入只勾选新增;
3.在ERP同步到CRM方向的同步策略的同步规则中,同步事件监听、同步事件写入只勾选修改;
其余对接可参照以上示例配置
4.6 ERP调价后,快速同步到CRM的产品
4.7 U8新增、查询如何增加属性?
可查阅文档Openapi Eai Api 常见问题 的2.18、2.21节内容
新增接口添加属性
开放平台安装目录config\META-INF\templates下,存放各对象接口的数据格式,新增接口添加属性可在\add目录下,找到对应对象的xml文件,在其中添加属性,添加的属性是EAI数据字典里能查到的。
查询接口添加属性
开放平台安装目录config\META-INF\datasource\query下是各对象查询的sql语句,可在sql语句中添加要查询的属性字段,config\META-INF\datasource\rules是各对象实际的openapi返回的字段,在field_list中配置过滤的字段和要添加的字段。
4.8 自定义函数
4.8.1ERP集成平台当前支持三种类型的自定义函数介绍
1.固定入参:Map syncArg
2.固定返回:return syncArg;
3.自定义函数校验:只要自定义函数代码中含有 Fx.object.create 、Fx.object.batchCreate 、Fx.object.update 、 Fx.object.batchUpdate 等其中一个字符串即表明函数body处于更新/新增/作废的调用。 场景:在自定义函数中加入上述字符串(字符串注释无效,同样会检测)并且含有与绑定字段apiName相同的字符串(注释也会检测),策略将无法开启,并报异常函数校验失败。
4.数据新增时:syncArg.objectData是对象主数据,syncArg.details是对象明细数据
5.数据更新时:syncArg.objectData有可能是主对象数据有可能是从对象数据,具体得通过objApiName来判断
4.8.2同步前自定义函数执行支持数据过滤:
即函中返回结果中包含"isExec":"false",即该次同步将不再往后执行,目标数据将不会做出相应的更改。
测试场景:在自定义函数返回的Map中加入"isExec":"false",或"isExec":false目标数据将不会发生更改。
函数代码: Map map = ["details":syncArg.details, "objectData":syncArg.objectData, "isExec":"false" ]; return map;
4.8.3同步中执行自定义函数:
函数执行后,在函数中编写的映射值修改,企业id和对象apiName不会更改。
测试场景:只有新增数据,才会携带从对象;更新时会更新对象映射值,因此如果没有对从对象做出特殊鉴别,更新的对象将不区分主从对象,一律更新,主从对象名称都会更新为自定义函数赋值
函数代码:
log.info("事件类型:" + syncArg.destEventType); log.info(syncArg.objectData); log.info(syncArg.details); Map objectData = syncArg.objectData as Map; objectData.name = "自定义函数修改" Map map = ["details":syncArg.details, "objectData":syncArg.objectData]; log.info(map); return map;
4.8.4同步后执行自定义函数:
函数执行后,在函数中编写的映射值修改,企业id和对象apiName不会更改。
测试场景:数据同步不会受到影响,只是将数据传给自定义函数即可,需要通过查看日志进行判断
函数代码: Map map = ["details":context.details, "objectData":context.data, "afterSync" : "yes001"]; return map;
具体入参字段(如果不清楚入参有什么字段就先把函数写好,然后打印入参看一下,注意新增和更新入参不一样)和函数例子如下
同步前:通过数据范围的校验之后
主要入参字段: { "destObjectApiName": "",//目标对象apiName "sourceData": {"字段apiName":"字段值"}//对象字段信息 }
简单例子:
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;//把这个字段设置为false,会过滤掉这条数据不同步 return syncArg;
同步中:写入目标系统之前
主要入参字段: { "destDetailSyncDataIdAndDestDataMap": {"":{"字段apiName":"字段值"}},//目标对象明细 "destData": {"字段apiName":"字段值"}//目标对象字段信息 //如果新增主对象在destData,明细数据在destDetailSyncDataIdAndDestDataMap,如果是更新主从数据都在destData(更新是单独更新的) }
简单例子:
//修改customerShortName字段值 log.info(syncArg); syncArg["objectData"]["customerShortName"]="dddddd" log.info(syncArg); return syncArg;
同步后:写入目标系统之后
主要入参字段: { "sourceDataId": "5fead1146660700001170e3d",//源数据id,只有crm->erp方向有这个字段 "sourceObjectApiName": "AccountObj",//源对象apiName "completeDataWriteResult": {//写入目标数据的结果 "detailWriteResults": [],//明细数据结果 "errCode": 0, "success": true, "destEventType": 1, "errMsg": "success", "writeResult": {//主数据结果,errCode为s106240000成功,其他的失败接口返回的错误码 "errCode": 5001, "success": false, "syncDataId": "3ab1c2c2ffe04111b3e713632d5a4f76", "errMsg": "预处理服务调用错误:调用外部http接口失败,错误信息:100,SAP系统BP名称已创建,不允许重复创建。::errCode=s306240003", "destDetailSyncDataIdAndDestDataMap": {} } }, "destObjectApiName": "AccountObj_1el03su6s",//目标数据对象apiName "objectData": {//目标数据 "tenant_id": "706089",//企业ei "object_describe_api_name": "AccountObj_1el03su6s",//对象apiName "_id": "5fead2696532bf0001e524e4" }, "details": {},//明细数据 }
简单例子:
//crm->erp,把目标对象的id写到crm源对象
log.info(syncArg)
if(syncArg["objectData"]["_id"]!=null&&syncArg["objectData"]["_id"]!=""
&&syncArg["sourceDataId"]!=null&&syncArg["sourceDataId"]!=""){
String destDataId=syncArg["objectData"]["_id"] as String;//目标数据id
String sourceDataId=syncArg["sourceDataId"] as String;//源数据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.9 数据中间表开放接口能力
自定义函数可以插入/修改/查询数据映射表,函数例子如下:
Map header=[:] //创建数据映射 Map param1=["ployDetailId":"155bd981457343f291e0edc13776217f",//策略明细id,如果策略被删除重新建了,这里需要改动 "sourceObjectApiName":"AccountObj",//源对象apiName,如果对象apiName变了,这里要改动 "destObjectApiName":"BD_Customer.BillHead",//目标对象apiName(虚拟的),如果对象apiName变了,这里要改动 "sourceDataId":"sourceDataId123",//源对象数据id "destDataId":"destDataId123666",//目标对象数据id "sourceDataName":"sourceDataName3666",//源对象数据name属性 "destDataName":"destDataName66",//目标对象数据name属性 "remark":"remark1341"];//备注 def result1=Fx.proxy.callAPI("erp.syncData.createSyncDataMapping",header,param1); //[false, HttpResult(statusCode=200, content={"errCode":"s106240000","errMsg":"成功"}, bytes=null), ] s106240000成功,其他失败 log.info(result1)
//根据源对象数据id更新目标对象数据id Map param2=["sourceObjectApiName":"AccountObj",//源对象apiName,如果对象apiName变了,这里要改动 "destObjectApiName":"BD_Customer.BillHead",//目标对象apiName(虚拟的),如果对象apiName变了,这里要改动 "sourceDataId":"sourceDataId123",//源对象数据id "destDataId":"destDataId123666"]//目标对象数据id def result2=Fx.proxy.callAPI("erp.syncData.updateSyncDataMapping",header,param2); //[false, HttpResult(statusCode=200, content={"errCode":"s106240000","errMsg":"成功"}, bytes=null), ] s106240000成功,其他失败 log.info(result2)
//查询源对象数据id是否存在映射关系 Map param3=["sourceObjectApiName":"AccountObj",//源对象apiName,如果对象apiName变了,这里要改动 "destObjectApiName":"BD_Customer.BillHead",//目标对象apiName(虚拟的),如果对象apiName变了,这里要改动 "sourceDataId":["sourceDataId123"]]//源对象数据ids,List //如果需要查询目标对象数据id是否存在映射关系,把sourceDataId改成destDataId,如果两个都传只会根据源数据id查询 def result3=Fx.proxy.callAPI("erp.syncData.getSyncDataMappingBySourceDataId",header,param3); // [false, HttpResult(statusCode=200, content={"data":{"sourceDataId123": //{"sourceDataId":"sourceDataId123","isCreated":true,"destDataId":"destDataId123666","sourceDataName":"sourceDataName1233","updateTime":1611047455451,"lastSyncStatus":6, //"destDataName":"destDataName123","destTenantId":"81138","sourceObjectApiName":"AccountObj","destObjectApiName":"BD_Customer.BillHead","sourceTenantId":"81138", //"statusName":"新增成功","id":"aa46ed320312476485e932a1ca4b4263","lastSyncDataId":"92c86fb175254e54b990bd86b6ce1145","status":1}},"errCode":"s106240000","errMsg":"成功"}, bytes=null), ] //s106240000成功,其他失败 //data是一个Map,存储着存在映射关系的数据,key是源数据id,value是已存在的对应关系, log.info(result3)
4.10 ERP导入历史到CRM
分下面几种情况处理:
1.已经把数据手工导入到CRM了。 需要把ERP和CRM数据ID映射关系导入中间表。请参考3.7节的内容写入中间表。
2.ERP这边不能提供读接口。按照第1条处理,手工导入历史数据。
3.ERP这边可以提供读接口。配置ERP到CRM的数据同步策略,测试增量数据同步是否正确。然后找研发处理全量的历史数据同步。
4.11 自定义函数新建erp字段映射表
//channel合法值有 ERP_K3CLOUD,ERP_SAP,ERP_U8,OA,STANDARD_CHANNEL //"dataType":"employee" 表示新建的是人员 //dataCenterId是数据中心id //fsDataId是crm上的数据id.对于人员,这里是员工ID,不是crm人员对象的数据id. //erpDataId是erp上的数据id //fsDataName是crm的数据名称 //erpDataName是erp上的数据名称
Map data = ["dataCenterId":"数据中心id", "channel":"ERP_K3CLOUD","dataType":"employee", "fsDataId":"fsDataId","fsDataName":"fsDataName","erpDataId":"erpDataId","erpDataName":"erpDataName"];
def ret = Fx.proxy.callAPI("erp.syncData.createErpfieldmapping", [:], data); Fx.log.info("ret is : "+ret)
4.12 沙盒拷贝
U8扩展自定义字段如何对接?
CRM->ERP方向的数据,会调用openapi的新增和修改接口,新增和修改接口默认是对扩展自定义字段开放的,需要在EAI接口设置上去掉忽略自定义项扩展信息配置
ERP->CRM方向的数据,会调用openapi的批量查询和单条数据查询的接口,批量查询是用于轮询时根据条件批量获取到数据,再根据这些获取到的数据的id调用单条数据查询的接口获取到详细的字段值,因此查询条件加在批量查询的接口上(见此文档【九.36】),对接的字段加在单条数据查询的接口上。
扩展自定义字段一般存放在【表名_extradefine】表中,如存货的扩展自定义字段存放在【Inventory_extradefine】中,单条数据查询接口想要开放出相应的字段,需修改相应的xml中的sql语句,下面以存货为例:
上图的cidefine2即为扩展自定义项2,用户根据自己的需求添加字段,扩展自定义项N则为cidefineN
t.cinvcode=i.cinvcode 为数据存放表和扩展自定义字段存放表之间的关联关系,在存货中为存货编码,一般为数据编码关联,具体关联可以查看下数据库中的数据
扩展表别名.cidefineN as 扩展字段别名(也可以不起别名)
left join 表名_extradefine 扩展表别名 on 扩展表别名.关联字段=主表别名.关联字段
修改完sql后,需要在rule中添加刚刚新加的字段,并重启开放平台客户端
ERP->CRM单独对接U8客户地址如何实现?
预设的客户地址为客户的子对象,子对象不允许单独创建策略,因此需要单独创建自定义对象对接客户地址,该自定义对象查找关联客户
ERP对象的主键要设置为 customeraddressId
八.ERP系统常见操作指引
1. 用友U8对接部分
1.1 单据联查
在单据详情页可联查相关单据,图中示例为发货单上查、下查,其它单据同理
1.2 单据快速定位
在单据列表(下图为销售订单列表),选中要定位的列下的任意一行数据,点击”定位“按钮,弹出框中下拉选择定位的内容,点击”定位下一个“按钮进行定位