前言
客户升级ERP 从U8升级到U9C,由之前的U8数据库对接 更换U9C 的OpenApi对接,中间踩了不少坑,网上的资料比较少,这里做个记录分享喜,大部分接口官方有提供,我这边就补充几个踩坑的接口需要注意
注:如果是数据同步采用的是直接数据库对接参考(https://blog.csdn.net/u014287572/article/details/135689794)
接口对接
OpenApi接口文档:https://openapi.yyu9c.com/doc.html#/home 或https://localhost/U9C/swagger(因考虑安全因素,swager本地访问只能在服务器上使用http://自己U9服务器的地址/swagger来访问了,不支持IP访问了
重点👇👇👇👇👇
U9的OpenApi里面有个说明文档,可以下载U9测试过的JSON,里面有个对接测试的JSON案例,可以少踩坑(虽然也有坑)
U9C.postman_(接口测试JSON串集合)可以导入.json
下面这部分是直接从U9的文档搬过来的👇
公共说明
接口返回值公共参数说明:
ResCode:0成功,其他失败
- 0 执行成功
- 401 未授权
- 402 token已过期
- 403 请求已过期
- 404 路由错误
- 405 授权码已过期
- 406 用户名不存在
- 407 ClientID未启用
- 408 组织编码不存在
- 500 系统内部错误
- 501 验签失败
- 502 参数错误
- 503 登录失败
- 504 token已失效
- 601 客户端IP未授权
业务接口都支持批量操作(批量操作数据直接互不影响,即失败的数据不影响其他操作成功的数据),参数ResCode返回0,只是接口调用成功,并非业务数据操作成功,业务数据批量传入则会批量返回对应的数据,返回对象会放入Data字段中(序列化后),Data中数据m_isSucess/IsSucess表示这条业务数据操作成功或失败,失败会返回m_errorMsg/ErrorMsg的值
调用说明
接口文档通过访问:https://www.yyu9c.com/swagger或https://www.yyu9c.com/swagger 可以打开接口文档说明,如果本地环境也可以打开:http://本地U9地址/swagger也可以打开接口文档。
接口地址
U9访问地址/webapi/定义的Controller/Controller下的方法名
如:http://localhost/u9c/webapi/Department/Create定义的Controller可以从第一步中获取,方法名点开第一步中具体的Controller即可看到方法名,如下图
接口调用
第一步: 获取授权码 使用U9系统分配的应用ID和应用秘钥获取授权码
(EA账号进入系统,在“第三方应用接口授权”中配置应用ID和应用秘钥作为clientid和clientsecret的值)
GET请求 接口地址:http://localhost/u9c/webapi/OAuth2/GetAuthorizeCode?clientid=XXX&clientsecret=XXX
参数:clientid(EA登录U9系统,“第三方应用接口授权”中配置应用ID,可任意配置,无限制,比如给MES用的可以叫MES,给OA用的可以叫OA即可)
clientsecret(EA登录U9系统,“第三方应用接口授权”中配置应用秘钥,自动生成,不能更改)
返回值:
ResCode为0,Data为返回的授权码值
第二步:获取Token调用接口获取token
GET请求
接口地址:http://localhost/u9c/webapi/OAuth2/Login?userCode=luo&entcode=009&orgcode=100&code=2cb6786b7b044bd59084de197e9197ff
entcode为企业编码(U9的管理控制台打开后,企业管理里面的代码值),userCode为用户编码,orgcode为组织编码,code为第二步获取的授权码值。
这几个值非常非常关键,特别是entcode,不知道请问用友的实施顾问!!!
企业编码截图:
获取Token:
返回值:
ResCode为0,Data为返回的token值
第一步和第二步特殊说明:
获取token也可以一步式调用获取,即第一步和第二步合在一个接口调用,即一步调用即可获取到token值(参数和第一步、第二步参数一致):
调用接口获取token
GET请求接口地址:http://localhost/u9c/webapi/OAuth2/AuthLogin?userCode=demo&entcode=001&orgcode=001&clientid=API1&clientsecret=36462bf7ecf74edd8bfadbb7b71a6607
踩坑接口
采购退货(无来源)
接口文档里面没有标注采购退货,测试后发现应该是一个接口,字段ReceivementType 分开 0 收货 1退货,以下是测试成功的数据
API:/webapi/Receivement/CreateReceivement
{
"rcvDTO": {
"BusinessDate": "2024-01-17T05:55:31.024Z",
"SrcDocType": 0,
"Supplier": {
"m_code": "M413"
},
"RcvDocType": {
"m_code": "RCV21"
},
"RcvLines": [
{
"RejectQtyTU": 10,
"RtnDeductQtyTU": 10,
"ItemInfo": {
"m_itemCode": "101021101203"
},
"DocLineNo": 1,
"Wh": {
"m_code": "11"
},
"OrderPriceTC": 1,
"StorageType": 2,
"FinallyPriceTC": 1
}
],
"Memo": "",
"ReceivementType": 1,
"IsLineApprove": false
},
"OtherID": ""
}
调拨入库(来源调拨出)
API:/webapi/TransferIn/CreateTransferInBySrcTransferOut
[
{
"OtherID": "IT2312250001",
"DocStatus": 2,
"IsApproved": true,
"SplitBy": [
],
"TransOutToTransInS": [
{
"SubDocLineId": "1002401200000019",
"StoreUomQty": 1,
"TransInDocType_Code": "TransIn002",
"TransOutInDept_Code": "",
"TransInWh_Code": "02",
"TransOutWh_Code": "01"
}
]
}
]
生产领料 审核/反审核/确认/反确认
// 👇的参数是接口 文档写的 但是没说明
[
{
"DocNo": "",
"IsSucceed": true,
"ErrorMsg": "",
"OperateType": true,
"OtherID": "",
"IsNotNewTransaction": true,
"IsAutoApp": true
}
]
// 经测试这样子传就行了 对于审核和 反审核接口 OperateType:true=审核/确认 false=反审核/反确认
[
{
"DocNo": "LL-0014",
"OtherID": "PRDPM2312270005",
"OperateType": true
}
]
完工汇报
注意:这里很坑生产订单必须传入ID!!!!!!!
[
{
"OtherID": "202208170002",
"Org": {
"Code": "101"
},
"Description": "测试",
"CompleteDate": "2024-01-23T14:35:16",
"CompleteDocType": {
"Code": "1"
},
"CompleteOp": "",
"Direction": 0,
"HandleDept": {
"Code": ""
},
"HandlePerson": {
"Code": ""
},
"MO": {
"ID": 1002312060000526,
"Code": "101--23120001"
},
"WhshipmentReason": -1,
"CompleteQty": 1,
"ReworkReason": -1,
"ScrapReason": -1,
"BusinessDate": "",
"ActualRcvTime": "",
"RcvWh": {
"Code": "01"
},
"CompleteRptRcvLines": [
{
"Wh": {
"Code": "G01"
},
"StorageType": 4,
"RcvQtyByProductUOM": 1,
"SnData": [],
"Remark": "",
"RcvLotEffectivedate": ""
}
],
"ItemMaster": {
"Code": "A068100-0078"
}
}
]
完工汇报取消/确认
注意:部分接口可能没有webapi的 例如 完工汇报单,没有完工确认和取消的接口,但是查文档发现有相关 WebService 的接口可以采用U9自带的工具WebServiceStudio.exe 进行测试 获取到WebService的请求信息,这块我直接采用post发送请求
@Override
public void deleteMoComplete(String wmsBill, String erpBill) {
// 取消入库
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n" +
" <soap:Body>\n" +
" <Do xmlns=\"http://www.UFIDA.org\">\n" +
" <context xmlns:q1=\"http://schemas.datacontract.org/2004/07/UFSoft.UBF.Util.Context\"\n" +
" xsi:type=\"q1:ThreadContext\">\n" +
" <q1:nameValueHas>\n" +
" <KeyValueOfanyTypeanyType xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">\n" +
" <Key xsi:type=\"xsd:string\">EnterpriseID</Key>\n" +
" <Value xsi:type=\"xsd:string\">{}</Value>\n" +
" </KeyValueOfanyTypeanyType>\n" +
" <KeyValueOfanyTypeanyType xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/Arrays\">\n" +
" <Key xsi:type=\"xsd:string\">OrgID</Key>\n" +
" <Value xsi:type=\"xsd:string\">{}</Value>\n" +
" </KeyValueOfanyTypeanyType>\n" +
" </q1:nameValueHas>\n" +
" <q1:EntCode>{}</q1:EntCode>\n" +
" <q1:OrgID>{}</q1:OrgID>\n" +
" </context>\n" +
" <docNoList>\n" +
" <UFIDA.U9.ISV.MO.CompRptKeyDTOData xmlns=\"http://www.UFIDA.org/EntityData\">\n" +
" <m_docNo>{}</m_docNo>\n" +
" <m_iD>0</m_iD>\n" +
" <m_operateType>{}</m_operateType>\n" +
" </UFIDA.U9.ISV.MO.CompRptKeyDTOData>\n" +
" </docNoList>\n" +
" <isNotNewTransaction>true</isNotNewTransaction>\n" +
" </Do>\n" +
" </soap:Body>\n" +
"</soap:Envelope>";
JSONObject parameter = U9Util.getParameter();
Long ordId = baseSqlU9SaveMapper.getOrgId(parameter.getStr("orgCode"));
Assert.notNull(ordId, "无法获取组织ID【{}】", parameter.getStr("orgCode"));
xml = StrUtil.format(xml, parameter.getStr("entCode"), ordId, parameter.getStr("entCode"), ordId, erpBill, false);
String url = "{}/Services/UFIDA.U9.ISV.MO.IRcvCompleteRpt4ExternalSrv.svc";
url = StrUtil.format(url, parameter.getStr("url"));
try {
String xmlResult = WebServicePostSoapUtils.doPostSoap(url, xml, "http://www.UFIDA.org/UFIDA.U9.ISV.MO.IRcvCompleteRpt4ExternalSrv/Do");
//判断是否包含 m_errorMsg
if (StrUtil.contains(xmlResult, "m_errorMsg")) {
// 截取 <a:m_errorMsg>xxxxxx</a:m_errorMsg>
String errorMsg = StrUtil.subBetween(xmlResult, "a:m_errorMsg", "a:m_errorMsg");
errorMsg = StrUtil.subBetween(errorMsg, ">", "</");
throw new BusinessException(errorMsg);
}
// 反审核
} catch (Exception e) {
log.warn("反确认失败:{}", e.getMessage());
}
删减了部分代码只保留了完工回写取消/和确认的逻辑
注意事项(踩坑)
- 回写尽量日期字段可以不填的就不填让接口自动,因为U9Cloud可以指定系统的账期和咱们系统日期不一致会回写有问题
- 接口调用日志可以 在服务器的:D:\yonyou\U9CE\Portal\log U9 的目录里面看
- 接口有些地方没有做参数校验,报错只会返回“未将对象引用设置到对象的实例。” 这个时候一般是 因为坑部分字段 需要传入ID 作为参数!不能只传入编码,例如完工汇总接口必须传生产订单ID 不能只传入单号,但是这些点并没有在接口文档里面标注
- 关于接口日期参数某些接口没有做校验,虽然可以 允许不填但是你必须传个空 不能不写值否则会 “未将对象引用设置到对象的实例。”
参考文档
U9 OpenApi:https://openapi.yyu9c.com/doc.html#/U9C%20OPENAPI/Department/Department_Create
U9论坛:https://www.oyonyou.com/forum-u9-1.html
或https://localhost/U9C/swagger(因考虑安全因素,swager本地访问只能在服务器上使用http://自己U9服务器的地址/swagger来访问了,不支持IP访问了