[toc] # 审批对接API 则一提供了不同规范的API,调用服务端API前,需了解开发前须知及调用流程。本文提供了调用则一服务端API示例,供开发者参考。 ## 白名单 则一服务端API接口访问有IP白名单限制,需要接口调用方提供调用API的服务器IP地址。 ## 数据加签 采用md5(32位小写)算法生成签名 appKey(则一提供) + appSecret(则一提供) + timestamp(当前时间戳毫秒) + nonce(6位随机码大小写字母数子组合) + data(请求数据) ### 生成签名示例 ```java public static String getMD5Lower(String input) { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(input.getBytes()); StringBuilder sb = new StringBuilder(); for (byte b : digest) { String hex = Integer.toHexString(b & 0xff); if (hex.length() == 1) { sb.append("0"); } sb.append(hex); } return sb.toString(); } ``` ## 数据加密 数据加密采用AES算法 加密模式: CBC 填充方式:PKCS5Padding 加密内容:data(加密数据) 密钥:aesSecret(则一提供) 输出:base64 字符集:utf-8 注:无敏感数据则无需加密 ### 数据加密示例 ```java public static String encrypt(String plaintext, String aesSecret) { byte[] keyBytes = Base64.getDecoder().decode(keyBase64); SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES"); byte[] iv = new byte[16]; SecureRandom secureRandom = new SecureRandom(); secureRandom.nextBytes(iv); IvParameterSpec ivParam = new IvParameterSpec(iv); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(1, secretKey, ivParam); byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); byte[] result = new byte[16 + ciphertext.length]; System.arraycopy(iv, 0, result, 0, 16); System.arraycopy(ciphertext, 0, result, 16, ciphertext.length); return Base64.getEncoder().encodeToString(result); } ``` ## 业务接口 * __1.发起审批__ * __2.撤销审批__ * __3.审批回调__ ## 1.发起审批 ### 简要描述 发起审批接口,接收金润发起审批请求数据 ### 调用方式 金润---->则一 ### 请求URL · 测试环境:https://test.shjiuze.cn/tms-service-api/audit/send · 生产环境:https://gw.shjiuze.cn/tms-service-api/audit/send ### 请求方式 * POST * Content-Type: application/json ### Headers参数 | 名称 | 类型 | 必填 | 示例值 | 描述 | | ------------- | ------ | -------------------------- | -------------------------------- | ------------------------------------------------------------ | | appKey | String | 是 | 0867ef5f23ef446483749e19e1692b40 | 则一提供 | | timestamp | String | 是 | 1643251533306 | 当前时间戳毫秒值 | | nonce | String | 是 | gdst9t | 6位小写字母数字组合随机串 | | sign | String | 是 | fa3ed338d6dfe18e7273c8692234ee70 | 签名:appKey(则一提供) + appSecret(则一提供) + timestamp + nonce(6位随机码) + data(body参数)通过md5(32位小写)算法生成 | ### Body参数 | 参数名 | 必传 | 类型 | 说明 | |-------------------------------------|----|--------|--------------------------------------| | code | 是 | string | 审批单号(确定数据唯一性,同一单号最多只能有1个审核通过或审核中的审批) | | auditType | 是 | string | 审批类型(则一提供) | | username | 是 | string | 发起人工号(则一员工工号) | | auditFormList | 是 | array | 审批表单字段列表 | |     type | 是 | string | 字段类型(1.text 文本格式 2.file 文件格式) | |     name | 是 | string | 字段名称 | |     value | 是 | string | 字段值(文本格式对应文本内容, 文件格式对应文件url) | |     extendValue | 否 | string | 字段附加值 | | conditionParamList | 否 | array | 条件参数字段列表 | |     name | 是 | string | 属性名 | |     value | 是 | string | 属性值 | ### 返回参数 | 参数名 | 必传 | 类型 | 说明 | |---------------------------------|----|---------|--------------------------------| | success | 是 | boolean | 是否成功, true表示请求成功, false表示产生了异常 | | businessException | 是 | boolean | 是否业务异常, false表示无业务异常, true表示产生了业务异常 | | errorCode | 否 | string | 错误码 | | message | 否 | string | 异常原因 | | result | 否 | object | 返回结果数据, 请求成功返回,异常不返回 | |     code | 是 | string | 审批单号 | |     auditId | 是 | string | 审批ID | #### 请求Body示例 ```json { "code": "JR202510110000001", "auditType": "JINRUN_VEHICLE_FEE_AUDIT", "username": "001073", "auditFormList": [ { "type": "text", "name": "feeType", "value": "车辆保险费用" }, { "type": "text", "name": "applyAmount", "value": "200000" }, { "type": "file", "name": "billAttachment", "value": "https://example.com/path/1.jpg" } ], "conditionParamList": [ { "name": "businessType", "value": "BULK_BUSINESS_TYPE" } ] } ``` #### 请求示例Java-SDK方式 ##### [下载SDK](https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/file/jar/java-sdk/zy-java-sdk-2.0.0.jar) ```java public static void main(String[] args) { String appKey = "bd95591ce63f4a78a54658c2d8ad5ff6"; String appSecret = "734a18117f614e60859efb8eea27c680"; String aesSecret = "wJ3472SLpkZLnjtwMArhRg=="; ZYClient zyClient = new ZYClient(appKey, appSecret); String data = "{\n" + " \"code\": \"JR202510200000003\",\n" + " \"auditType\": \"JINRUN_VEHICLE_FEE_AUDIT\",\n" + " \"username\": \"001073\",\n" + " \"auditFormList\": [\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"feeType\",\n" + " \"value\": \"车辆保险费用\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"applyAmount\",\n" + " \"value\": \"200000\"\n" + " },\n" + " {\n" + " \"type\": \"file\",\n" + " \"name\": \"billAttachment\",\n" + " \"value\": \"https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/image/tms/d05b7f1b-1844-49b6-9931-11ac4cd783ea.jpg\"\n" + " }\n" + " ],\n" + " \"conditionParamList\": [\n" + " {\n" + " \"name\": \"businessType\",\n" + " \"value\": \"BULK_BUSINESS_TYPE\"\n" + " }\n" + " ]\n" + "}"; HttpResponseData httpResponseData = zyClient.doPost(Constants.TEST_HOST + "/tms-service-api/audit/send", AesUtils.encrypt(data, aesSecret)); } ``` #### 完整示例 ```java String appKey = "bd95591ce63f4a78a54658c2d8ad5ff6"; String appSecret = "734a18117f614e60859efb8eea27c680"; String aesSecret = "wJ3472SLpkZLnjtwMArhRg=="; ZYClient zyClient = new ZYClient(appKey, appSecret); String data = "{\n" + " \"code\": \"JR202511060000016\",\n" + " \"auditType\": \"JINRUN_VEHICLE_FEE_AUDIT\",\n" + " \"username\": \"001073\",\n" + " \"auditFormList\": [\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"billCode\",\n" + " \"value\": \"FYBX251106001\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"billMonth\",\n" + " \"value\": \"2025-11\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"amount\",\n" + " \"value\": \"2100\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"detail\",\n" + " \"value\": \"[{\\\"车牌号\\\":\\\"沪A11111\\\",\\\"金额\\\":\\\"1000\\\",\\\"费用类型\\\":\\\"行车费用\\\",\\\"项目\\\":\\\"宁德项目\\\",\\\"备注\\\":\\\"沪A11111 2025年11月6号住宿费\\\"}]\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"paySubject\",\n" + " \"value\": \"金润\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"accountName\",\n" + " \"value\": \"大车队长有限公司\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"accountNo\",\n" + " \"value\": \"6220022221000221\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"openBankName\",\n" + " \"value\": \"浦东发展银行\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"openBankBranchName\",\n" + " \"value\": \"浦发银行青浦支行\"\n" + " },\n" + " {\n" + " \"type\": \"text\",\n" + " \"name\": \"remark\",\n" + " \"value\": \"账单备注\"\n" + " },\n" + " {\n" + " \"type\": \"file\",\n" + " \"name\": \"billAttachment\",\n" + " \"value\": \"https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/image/tms/d05b7f1b-1844-49b6-9931-11ac4cd783ea.jpg\"\n" + " }\n" + " ],\n" + " \"conditionParamList\": [\n" + " {\n" + " \"name\": \"businessType\",\n" + " \"value\": \"BULK_BUSINESS_TYPE\"\n" + " }\n" + " ]\n" + "}"; HttpResponseData httpResponseData = zyClient.doPost(Constants.TEST_HOST + "/tms-service-api/audit/send", AesUtils.encrypt(data, aesSecret)); ``` #### 返回示例 ```json { "success": true, // true表示请求成功, false表示产生了异常,需要看messge异常原因 "businessException": false, // false表示无业务异常, true表示产生了业务异常,需要看messge异常原因 "errorCode": null, "message": null, "result": { "code": "JR202510110000001", // 审批单号 "auditId": "2369f6c4c15440cdada803047d664546" // 审批ID } } ``` ## 2.撤销审批 ### 简要描述 撤销审批接口,接收金润撤销审批请求数据 ### 调用方式 金润---->则一 ### 请求URL · 测试环境:https://test.shjiuze.cn/tms-service-api/audit/cancel · 生产环境:https://gw.shjiuze.cn/tms-service-api/audit/cancel ### 请求方式 * POST * Content-Type: application/json ### Headers参数 | 名称 | 类型 | 必填 | 示例值 | 描述 | | ------------- | ------ | -------------------------- | -------------------------------- | ------------------------------------------------------------ | | appKey | String | 是 | 0867ef5f23ef446483749e19e1692b40 | 则一提供 | | timestamp | String | 是 | 1643251533306 | 当前时间戳毫秒值 | | nonce | String | 是 | gdst9t | 6位小写字母数字组合随机串 | | sign | String | 是 | fa3ed338d6dfe18e7273c8692234ee70 | 签名:appKey(则一提供) + appSecret(则一提供) + timestamp + nonce(6位随机码) + data(body参数)通过md5(32位小写)算法生成 | ### Body参数 | 参数名 | 必传 | 类型 | 说明 | |------------|----|--------|---------------------------| | code | 是 | string | 审批单号(确定数据唯一性) | | auditId | 是 | string | 审批ID | | auditType | 是 | string | 审批类型(则一提供) | | remark | 是 | string | 撤销原因 | | username | 否 | string | 撤销人员工号(发起人则一员工工号, 不传则为系统撤销) | ### 返回参数 | 参数名 | 必传 | 类型 | 说明 | |---------------------------------|----|---------|--------------------------------| | success | 是 | boolean | 是否成功, true表示请求成功, false表示产生了异常 | | businessException | 是 | boolean | 是否业务异常, false表示无业务异常, true表示产生了业务异常 | | errorCode | 否 | string | 错误码 | | message | 否 | string | 异常原因 | | result | 否 | object | 返回结果数据, 请求成功返回,异常不返回 | |     code | 是 | string | 审批单号 | |     auditId | 是 | string | 审批ID | #### 请求Body示例 ```json { "code": "JR202510110000001", "auditId": "2369f6c4c15440cdada803047d664546", "auditType": "BILL_APPLY_PAY_AUDIT", "remark": "付款金额错误, 撤销重新提交", "username": "001001" } ``` #### 请求示例Java-SDK方式 ##### [下载SDK](https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/file/jar/java-sdk/zy-java-sdk-2.0.0.jar) ```java public static void main(String[] args) { String appKey = "bd95591ce63f4a78a54658c2d8ad5ff6"; String appSecret = "734a18117f614e60859efb8eea27c680"; String aesSecret = "wJ3472SLpkZLnjtwMArhRg=="; ZYClient zyClient = new ZYClient(appKey, appSecret); String data = "{\n" + " \"code\": \"JR202510200000002\",\n" + " \"auditId\": \"LgXYezIUQYC1WxnzMpZatA03781760922998\",\n" + " \"auditType\": \"JINRUN_VEHICLE_FEE_AUDIT\",\n" + " \"remark\": \"付款金额错误, 撤销重新提交\",\n" + " \"username\": \"001073\"\n" + "}"; HttpResponseData httpResponseData = zyClient.doPost(Constants.TEST_HOST + "/tms-service-api/audit/cancel", AesUtils.encrypt(data, aesSecret)); } ``` #### 返回示例 ```json { "success": true, // true表示请求成功, false表示产生了异常,需要看messge异常原因 "businessException": false, // false表示无业务异常, true表示产生了业务异常,需要看messge异常原因 "errorCode": null, "message": null, "result": { "code": "JR202510110000001", //审批单号 "auditId": "2369f6c4c15440cdada803047d664546" //审批ID } } ``` ## 3.审批回调 ### 简要描述 审批结果回调接口,审批同意、拒绝、撤销、删除时接收审批结果数据. ### 调用方式 则一---->金润 ### 请求URL 需要金润提供,以金润提供为准 · 测试环境:https://example.com/path/audit/callback · 生产环境:https://example.com/path/audit/callback ### 请求方式 * POST * Content-Type: application/json ### Headers参数 具体以金润提供为准 | 名称 | 类型 | 必填 | 示例值 | 描述 | | ------------- | ------ | -------------------------- | -------------------------------- |---------------------------------------------------------------------------------------------| | appKey | String | 是 | 0867ef5f23ef446483749e19e1692b40 | 金润提供 | | timestamp | String | 是 | 1643251533306 | 当前时间戳毫秒值 | | nonce | String | 是 | gdst9t | 6位小写字母数字组合随机串 | | sign | String | 是 | fa3ed338d6dfe18e7273c8692234ee70 | 签名:appKey(金润提供) + appSecret(金润提供) + timestamp + nonce(6位随机码) + data(body参数)通过md5(32位小写)算法生成 | ### Body参数 | 参数名 | 必传 | 类型 | 说明 | |-----------|----| ------ |-----------------------------------------------| | code | 是 | string | 审批单号 | | auditId | 是 | string | 审批ID | | auditCode | 是 | string | 审批编号 | | auditType | 是 | string | 审批类型 | | type | 是 | string | 审批正常结束(同意或拒绝)的type为finish,审批终止的type为terminate | | result | 否 | string | 正常结束时(agree:同意, refuse:拒绝) | | auditUser | 否 | string | 最终审核人 | | remark | 否 | string | 审批意见 | #### 请求Body示例 ```json { "code": "JR202510110000001", "auditId": "2369f6c4c15440cdada803047d664546", "auditCode": "202510131759000353053", "auditType": "BILL_APPLY_PAY_AUDIT", "type": "finish", "result": "agree", "auditUser": "001001", "remark": "同意出款" } ``` ------------------------------------------------------------------------------------------ ## 附录 ### 则一Java-sdk ##### [下载Java-sdk](https://zeyi-tms-product.oss-cn-hangzhou.aliyuncs.com/file/jar/java-sdk/zy-java-sdk-2.0.0.jar) ## 更新日志 ### 2025-10-11 1. 接口初始化 ### 2025-10-17 1. 更新加密逻辑 ### 2025-10-20 1. 增加请求示例