海关179对接
1.背景
http://www.customs.gov.cn/customs/302249/302266/302267/2155884/index.html
跨境电子商务平台企业支付相关原始数据必须对接179,否则会清关失败。
例:清单[电商企业编码:xxxx,订单编号:xxxxxxxx]报文校验失败:电商平台[xxx]未对接海关总署179号公告数据实时抓取业务,无法正常申报。
2.准备
第一步去海关注册备案拿到法人卡(用于服务注册管理)和操作员卡(或者ukey)(用于上传支付信息加签)
如果操作员卡(或者ukey)丢失,可以去重新申请(需使用法人卡登录):互联网+门户登录
去中华人民共和国海关总署下载179号文档对接前先看一遍文档
添加微信说明情况会邀请你入群,进群先看公告(群公告很重要)
注意以上需要下载的文档,内容比较乱。
1步骤的两个卡是必须的。其他的可以先不看
3.代码设计
整体流程:整体流程就这几步,但是细节很多,相互影响。(这只是整体的调用流程,不是开发流程)
步骤 说明
1.海关发起调用
海关发起调用前提:
1.先登录(使用法人卡):互联网+海关主页
2.填写:见图1.可以开发完成再配置
2.电商平台接受请求
电商平台部署接口(步骤1配置的服务地址)
3.电商平台返回成功 步骤2接口返回成功
4.电商平台组装支付数据,加签,上传到海关平台 组装数据、加签(使用操作员卡)
图1:
注意:当海关调用电商平台的接口时,电商平台必须2分钟内上传数据。
整体流程设计(可根据上面注意事项,自行设计方案):以下是我司对接方案。
步骤说明:
1.调用(此步骤可以最后调试):电商平台提供http接口。服务地址必须是http开头的,不能带端口号,只能是默认的80端口,不能是https。
2.入库:入参的orderNo,sessionID直接入库
3.开启线程异步同步支付信息&直接返回成功:
4.组装参数:
5. 加签(加签流程见):加签会调用pc机。pc机上部署一个springboot应用(对外提供http接口,对内连接websocket服务)+海关提供的html(提供websocket服务)
6.调用海关上传信息接口&处理上传结果(更新db)
7.补偿job(每分钟执行一次):查询同步失败的记录,重新进行4/5/6步骤。
4.开发
按照上述步骤进行开发
此处详情说明下加签:
1.生成证书编号、证书(可在本地机器生成):
插入操作员卡,找到海关提供的资料:
按照这个操作。
2.加签逻辑部署在pc机,此pc机必须是windows系统(据说可以使用其他系统,但是我不会)。提供http接口,供自己应用调用。见:6.部署-pc机部署
5.测试
已经无测试环境,和xx确认过。直接把测试数据上传到线上
企业注册接口是企业公网请求接口测试完成后才提交审核的,不是企业测试接口的试验场。海关请求企业接口格式内容以及方式在公告资料里都有样例。
不用提交给xx任何资料,上传数据测试地址是正式环境地址:
https://customs.chinaport.gov.cn/ceb2grab/grab/realTimeDataUpload
企业在正式环境自行测试。没有联调环境。
测试方式:
企业模拟请求测试接口连通性。
通过样模拟样例中海关实时数据获取请求,按返回格式正确返回正常调用值。(模拟调用提供的http接口)
在相应时间内上传支付相关原始数据-https://customs.chinaport.gov.cn/ceb2grab/grab/realTimeDataUpload。(上传数据)
6.部署
1.pc机部署(操作员卡要一直插在此pc机上):
1.1.打开index.html(根据群公告中,下载的资料中有。)
效果:使用console中的地址连接此websocket,也可以使用127.0.0.1
1.2.启动springboot应用。
2.应用部署。
部署自己应用
3.配置
配置事项(要使用法人卡登录配置)互联网+门户登录:
证书编号、证书,使用操作员卡生成,生成后,进行上传。
审核订单编号:使用生产上订单号,如果没有,随便填写一个,但是要保证,电商平台提供http接口返回成功。否则服务地址审核不通过
企业联系人、联系方式:随便填写,联系方式格式要正确
服务地址:<电商平台提供http接口>就是填写这个接口。这个点击注册地址后,需要在微信群里@xx进行审核。格式:@xx 电商平台代码:xxxx ,麻烦审核一下,谢谢!
启用地址:审核通过后,选择审核通过的地址,然后启用,至此,整体流程结束。
7.问题盘点(附实现方式)
接收海关请求
海关发起数据查询
post方式(x-www-form-urlencoded)
从请求中获取openReq参数的值,该参数值是一个符合json标准的字符串,由于海关提交的请求是post方式(x-www-form-urlencoded),所以在url中是没有参数的,必须要从表单中获取该参数
海关数据示例
{"orderNo":"202009231454212140210352","sessionID":"032C3F56-0EE6-4558-B548-6C7A3451F07D","serviceTime":"1600852846372"}
接收完后需企业返回响应json格式数据 必须是json格式 10000表示成功 20000失败
{ "code":"10000","message":"","serviceTime":1533271903898}
3. 组装数据和上传报文
使用接收到的sessionID就可以进行加签(前期可以自己模拟请求)
使用ukey进行加签获取签名(使用操作员ukey)
按照179号文档进行数据拼装
获取签名
1. 使用官方js请求时需按以下格式来请求
数据格式
"sessionID":"032C3F56-0EE6-4558-B548-6C7A3451F07D"||"payExchangeInfoHead":"{"guid":"E4766021-21AC-1AA2-21DD-E974DF93C11D","initalRequest":"","initalResponse":" 202009231454212140210352 500 ","ebpCode":"11111111","payCode":"4403169D3W","payTransactionId":"4200000681202009235085032319","totalAmount":5,"currency":"142","verDept":"3","payType":"4","tradingTime":"20200923145426","note":""}"||"payExchangeInfoLists":"[{"orderNo":"202009231454218421271832","goodsInfo":[{"gname":"济州花梨精华面膜","itemLink":"https://填写自己的商品地址"}],"recpAccount":"111111111","recpCode":"22222222222","recpName":"填写在海关注册的公司"}]"||"serviceTime":"1601282210417" 500 20200923145426 500 4200000681202009235085032319
js请求示例
海关179 js加签,海关179号对接,海关165号对接
2. WebSocket请求
请求地址:
ws://127.0.0.1:61232 wss://wss.singlewindow.cn:61231
数据格式
{"_id":"1","_method":"cus-sec_SpcSignDataAsPEM","args":{"inData":"\"sessionID\":\"032C3F56-0EE6-4558-B548-6C7A3451F07D\"||\"payExchangeInfoHead\":\"{\"guid\":\"E4766021-21AC-1AA2-21DD-E974DF93C11D\",\"initalRequest\":\"<\/mch_id> 202009231454212140210352<\/out_trade_no> 500<\/total_fee> <\/xml>\",\"initalResponse\":\" 500<\/cash_fee> <\/mch_id> 202009231454212140210352<\/out_trade_no> 20200923145426<\/time_end> 500<\/total_fee> 4200000681202009235085032319<\/transaction_id><\/xml>\",\"ebpCode\":\"111111\",\"payCode\":\"4403169D3W\",\"payTransactionId\":\"4200000681202009235085032319\",\"totalAmount\":5,\"currency\":\"142\",\"verDept\":\"3\",\"payType\":\"4\",\"tradingTime\":\"20200923145426\",\"note\":\"\"}\"||\"payExchangeInfoLists\":\"[{\"orderNo\":\"202009231454218421271832\",\"goodsInfo\":[{\"gname\":\"\u6d4e\u5dde\u82b1\u68a8\u7cbe\u534e\u9762\u819c\",\"itemLink\":\"商品链接地址"}],\"recpAccount\":\"111111\",\"recpCode\":\"222222\",\"recpName\":\"测试测试"}]\"||\"serviceTime\":\"1601282210417\"","passwd":"88888888"}}
!!!把以上加签数据替换成你自己的信息!!!
获取到签名格式
{"Result":true,"Data":["KT1m7MkJ98/O5s33P0BpF34b7+gyW5WEpMvaTB+Ji0O9H3FabJuoRj8s2DxbglUbqA9mFDoCXbljgt+GaO73HE0eO8vl+eWx981S5hYumdK7sVovMTqkCKs211ZsB3edVUVfDau3D8ew8rwoda/zOBVBiDKmo3J5iQ5INxN3oF8=","证书"],"Error":[]}
4. 上传报文
请求地址:https://customs.chinaport.gov.cn/ceb2grab/grab/realTimeDataUpload
方式:POST
参数名:payExInfoStr
参数类型: JSON
报文格式
{"sessionID":"032C3F56-0EE6-4558-B548-6C7A3451F07D","payExchangeInfoHead":{"guid":"E4766021-21AC-1AA2-21DD-E974DF93C11D","initalRequest":"","initalResponse":" 11111111 202009231454212140210352 500 ","ebpCode":"请替换","payCode":"4403169D3W","payTransactionId":"4200000681202009235085032319","totalAmount":5,"currency":"142","verDept":"3","payType":"4","tradingTime":"20200923145426","note":""},"payExchangeInfoLists":[{"orderNo":"202009231454218421271832","goodsInfo":[{"gname":"济州花梨精华面膜","itemLink":"请替换"}],"recpAccount":"请替换","recpCode":"请替换","recpName":"请替换"}],"serviceTime":"1601282210417","certNo":"证书号要小写","signValue":"KT1m7MkJ98/O5s33P0BpF34b7+gyW5WEpMvaTB+Ji0O9H3FabJuoRj8s2DxbglUbqA9mFDoCXbljgt+GaO73HE0eO8vl+eWx981S5hYumdK7sVovMTqkCKs211ZsB3edVUVfDau3D8ew8rwoda/zOBVBiDKmo3J5iQ5INxN3oF8="} 500 11111111 202009231454212140210352 20200923145426 500 4200000681202009235085032319
返回信息
{"code":"20006","message":"上传失败,入库失败 java.sql.SQLException: ORA-00001: 违反唯一约束条件 (sessionID重复)","total":0,"serviceTime":1603684304670}
返回以上json如上就基本完成,因为这里sessionID是自己生成的或者第二次上传,才会返回sessionID重复。可以去海关http://ceb1.chinaport.gov.cn/填写测试订单号进行线上模拟测试
填写海关1791,165线上测试订单,海关179号对接,海关165号对接
{"code":"20004","message":"企业实时数据获取验签证书未在服务系统注册","total":0,"serviceTime":1603693566761}
未上传证书编号和证书,这里需要注意的事项!!!证书编号需要小写,并且页面上传的和上传支付数据的证书编号保持一致!!! 如果已上传请检查证书是否一致
海光179,165注册服务地址,海关179号对接,海关165号对接
{"code":"20005","message":"验签失败","total":0,"serviceTime":1603696878548}
查看数据格式是否出现问题,查看证书是否一致
有一些坑需要注意
文档中的payExchangeInfoList应该是payExchangeInfoLists
serviceTime必须是字符串类型
totalAmoun不是string类型
查看上传数据和加签数据的时间,guid是否一致
{"code":"10000","message":"上传成功","total":0,"serviceTime":1603696878548}
测试完成