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 新增对象】

image-20210609114327862

2.新建完对象后,根据需求新增ERP主从对象字段,操作可参考【3.4.3.1.2.1 新增字段】

image-20210609114133332

3.之后新建同步策略,拆分后的ERP主对象与CRM主对象映射,拆分后的ERP从对象与CRM从对象映射,如下图

image-20210609120016015

其余对接可参照以上示例配置

4.3 CRM一个对象,对接ERP的两个对象

CRM一个对象,对接ERP两个对象,先建立CRM对象的同步策略,后新增与两个ERP对象对接的策略明细即可

下面以CRM【开票申请】对象为例进行讲解。假设CRM【开票申请】对象,需要对接ERP【增值税销售发票】以及【销售普通发票】

则先新建CRM【开票申请】对象同步策略,然后再新增与ERP【增值税销售发票】以及【销售普通发票】对接的策略明细,如下图

image-20210608154044508

其余此需求可参照该示例进行对接

4.4 ERP一个对象下的数据,按条件对接到CRM两个独立的对象

ERP一个对象按条件对接到CRM两个独立的对象,要先建好ERP对象与CRM两个独立对象的策略明细,在策略明细中设置数据范围条件则可根据该条件过滤数据

下面以ERP出库单为例来进行讲解。假设ERP出库单需要对接到CRM预设对象【发货单】以及自定义对象【销售出库单】,当ERP出库单【销售组织】字段值等于“纷享销客”时,同步到CRM预设对象【发货单】;当ERP出库单【销售组织】字段值不等于“纷享销客”时同步到CRM自定义对象【销售出库单】,则按照如下步骤操作可实现该功能:

1、首先建立CRM【发货单】跟ERP出库单对接的策略明细以及CRM【销售出库单】跟ERP出库单对接的策略明细

image-20210607195928816

image-20210608111928444

2、根据条件当ERP出库单【销售组织】字段值等于“纷享销客”时,同步到CRM预设对象【发货单】;当ERP出库单【销售组织】字段值不等于“纷享销客”时同步到CRM自定义对象【销售出库单】,分别设置策略的数据范围条件如下

CRM【发货单】跟ERP出库单对接的同步策略,数据范围按如下设置

image-20210608111519126

CRM【销售出库单】跟ERP出库单对接的同步策略,数据范围按如下设置

image-20210608111713479

其他条件参照示例配置即可

4.5 CRM的数据同步到ERP后,ERP更改完数据回写到CRM

要完成此对接,需两个同步方向都建立同个CRM对象与同个ERP对象对接的同步策略,并在CRM往ERP方向策略的同步规则中,同步事件监听、同步事件写入只勾选新增,在ERP往CRM方向策略的同步规则中,同步事件监听、同步事件写入只勾选修改

下面以销售订单为例,假设销售订单数据是由CRM同步到ERP,在ERP更改完数据后回写到CRM

1.在两个同步方向都建立销售订单同步策略如下

image-20210609144406032

image-20210609144602503

2.在CRM同步到ERP方向同步策略的同步规则中,同步事件监听、同步事件写入只勾选新增;

image-20210609145243266

3.在ERP同步到CRM方向的同步策略的同步规则中,同步事件监听、同步事件写入只勾选修改;

image-20210609145018511

其余对接可参照以上示例配置

4.6 ERP调价后,快速同步到CRM的产品

4.7 U8新增、查询如何增加属性?

可查阅文档Openapi Eai Api 常见问题 的2.18、2.21节内容

新增接口添加属性

开放平台安装目录config\META-INF\templates下,存放各对象接口的数据格式,新增接口添加属性可在\add目录下,找到对应对象的xml文件,在其中添加属性,添加的属性是EAI数据字典里能查到的。

U8新增对象添加属性

查询接口添加属性

开放平台安装目录config\META-INF\datasource\query下是各对象查询的sql语句,可在sql语句中添加要查询的属性字段,config\META-INF\datasource\rules是各对象实际的openapi返回的字段,在field_list中配置过滤的字段和要添加的字段。

U8查询sql U8openapi返回字段

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 单据联查

在单据详情页可联查相关单据,图中示例为发货单上查、下查,其它单据同理 U8单据联查

1.2 单据快速定位

在单据列表(下图为销售订单列表),选中要定位的列下的任意一行数据,点击”定位“按钮,弹出框中下拉选择定位的内容,点击”定位下一个“按钮进行定位 U8单据快速定位

1.3 筛选查看范围

1.4 U8主键自增长设置

results matching ""

    No results matching ""