e签宝发起签署流程,多个方法调整

This commit is contained in:
Jack 2025-03-12 23:03:25 +08:00
parent 773d886aa6
commit 7ab60e5f57
7 changed files with 451 additions and 27 deletions

View File

@ -54,4 +54,12 @@ public class CommonConstant {
// 入驻商家主体类型企业或个人1-企业2-个人 // 入驻商家主体类型企业或个人1-企业2-个人
public static final Integer MCH_ENTITY_TYPE_QY = 1; public static final Integer MCH_ENTITY_TYPE_QY = 1;
public static final Integer MCH_ENTITY_TYPE_GR = 2; public static final Integer MCH_ENTITY_TYPE_GR = 2;
// 合作方签署状态-1预备数据阶段1-等待签署2 - 已完成所有签署方完成签署3 - 已撤销发起方撤销签署任务5 - 已过期签署截止日到期后触发7 - 已拒签签署方拒绝签署
public static final Integer CONTRACT_SIGN_STA_PREPARE = -1;
public static final Integer CONTRACT_SIGN_STA_ING = 1;
public static final Integer CONTRACT_SIGN_STA_FINISH = 2;
public static final Integer CONTRACT_SIGN_STA_CANCEL = 3;
public static final Integer CONTRACT_SIGN_STA_EXPIRED = 5;
public static final Integer CONTRACT_SIGN_STA_REJECT = 7;
} }

View File

@ -14,7 +14,7 @@ import org.springframework.stereotype.Service;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
/** /**
* 使用方法 * 多线异步程执行使用方法
* *
* @Autowired private TaskService taskService; * @Autowired private TaskService taskService;
* <p> * <p>

View File

@ -8,18 +8,24 @@
package com.suisung.mall.shop.esign.controller.admin; package com.suisung.mall.shop.esign.controller.admin;
import cn.hutool.json.JSONObject;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.service.impl.BaseControllerImpl; import com.suisung.mall.common.service.impl.BaseControllerImpl;
import com.suisung.mall.shop.esign.service.EsignContractFillingFileService; import com.suisung.mall.shop.esign.service.EsignContractFillingFileService;
import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.esign.service.EsignContractService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Api(tags = "店铺表-用户可以多店铺-需要分表") @Api(tags = "E签宝电子签控制器")
@RestController @RestController
@RequestMapping("/admin/shop/esign") @RequestMapping("/admin/shop/esign")
public class EsignController extends BaseControllerImpl { public class EsignController extends BaseControllerImpl {
@ -30,15 +36,21 @@ public class EsignController extends BaseControllerImpl {
@Resource @Resource
private EsignContractService esignContractService; private EsignContractService esignContractService;
@ApiOperation(value = "店铺基础信息表-查找所有店铺编号和名称", notes = "店铺基础信息表-查找所有店铺编号和名称") @ApiOperation(value = "测试填充模版控件", notes = "测试填充模版控件")
@RequestMapping(value = "/testcase", method = RequestMethod.POST) @RequestMapping(value = "/testcase", method = RequestMethod.POST)
public Object testCase() { public Object testCase() {
return esignContractFillingFileService.fillDocTemplate("yyzz787654566543", "91450881MADEQ92533"); return esignContractFillingFileService.fillDocTemplate("91450881MA5P8MWX69", "91450881MADEQ92533");
} }
@ApiOperation(value = "基于文件发起签署电子合同", notes = "基于文件发起签署电子合同") @ApiOperation(value = "基于文件发起签署电子合同", notes = "基于文件发起签署电子合同")
@RequestMapping(value = "/sign-flow/create-by-file", method = RequestMethod.POST) @RequestMapping(value = "/sign-flow/create-by-file", method = RequestMethod.POST)
public Object signFlowCreateByFile() { public CommonResult signFlowCreateByFile(@RequestBody JSONObject paramsJSON) {
return esignContractService.signFlowCreateByFile(); return esignContractService.signFlowCreateByFile(paramsJSON.getStr("mchMobile"));
}
@ApiOperation(value = "基于文件发起签署电子合同", notes = "基于文件发起签署电子合同")
@RequestMapping(value = "/async/notify", method = RequestMethod.POST)
public ResponseEntity<String> signAsyncNotify(HttpServletRequest request, ServerHttpResponse response, @RequestBody String requestBody) {
return esignContractService.signAsyncNotify(request, response, requestBody);
} }
} }

View File

@ -8,20 +8,62 @@
package com.suisung.mall.shop.esign.service; package com.suisung.mall.shop.esign.service;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.modules.esign.EsignContract;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpResponse;
import javax.servlet.http.HttpServletRequest;
public interface EsignContractService { public interface EsignContractService {
Object signFlowCreateByFile(); /**
* 根据商家注册手机号发起合同签署流程
*
* @param mchMobile
* @return
*/
CommonResult signFlowCreateByFile(String mchMobile);
/** /**
* 更新合同流程ID和文件地址 * 签署流程结束通知
*
* @return
*/
ResponseEntity<String> signAsyncNotify(HttpServletRequest request, ServerHttpResponse response, String requestBody);
/**
* 更新合同流程ID和文件地址和状态
* *
* @param mchMobile * @param mchMobile
* @param contractFileId * @param contractFileId
* @param signFlowStatus
* @param signFlowId * @param signFlowId
* @param fileUrl * @param fileUrl
* @return * @return
*/ */
Boolean updateContractFlowIdAndFileUrl(String mchMobile, String contractFileId, String signFlowId, String fileUrl); Boolean updateContractFlowIdAndFileUrl(String mchMobile, String contractFileId, String signFlowId, Integer signFlowStatus, String fileUrl);
/**
* 更新合同流程ID和文件地址和状态
*
* @param id
* @param signFlowId
* @param signFlowStatus
* @param fileUrl
* @return
*/
Boolean updateContractFlowIdAndFileUrl(Long id, String signFlowId, Integer signFlowStatus, String fileUrl);
/**
* 根据签署流程Id更新合同流程状态和文件地址
*
* @param signFlowId
* @param signFlowStatus
* @param fileUrl
* @return
*/
Boolean updateContractFlowStatusAndFileUrlBySignFlowId(String signFlowId, Integer signFlowStatus, String fileUrl);
/** /**
* 商家入驻审核通过模版就绪之后预创建签署流程 * 商家入驻审核通过模版就绪之后预创建签署流程
@ -31,4 +73,29 @@ public interface EsignContractService {
* @return * @return
*/ */
Boolean preCreateSignFlow(String mchMobile, String templateId); Boolean preCreateSignFlow(String mchMobile, String templateId);
/**
* 根据商家注册手机号获取合同信息
*
* @param mchMobile
* @return
*/
EsignContract getEsignContractByMchMobile(String mchMobile);
/**
* 根据合同流程ID获取合同信息
*
* @param signFlowId
* @return
*/
EsignContract getEsignContractBySignFlowId(String signFlowId);
/**
* 根据合同流程ID获取完成签署生效的合同文件地址
*
* @param signFlowId
* @return
*/
String getSignedContractFileUrl(String signFlowId);
} }

View File

@ -339,7 +339,6 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
} }
// 处理符合的数据 // 处理符合的数据
// Pair<JSONArray,JSONArray> pair = new Pair<>();
JSONArray retMchArr = new JSONArray(); JSONArray retMchArr = new JSONArray();
JSONArray retPlatArr = new JSONArray(); JSONArray retPlatArr = new JSONArray();
for (JSONObject component : components.jsonIter()) { for (JSONObject component : components.jsonIter()) {

View File

@ -8,12 +8,15 @@
package com.suisung.mall.shop.esign.service.impl; package com.suisung.mall.shop.esign.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray; import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.constant.CommonConstant; import com.suisung.mall.common.constant.CommonConstant;
import com.suisung.mall.common.modules.esign.EsignContract; import com.suisung.mall.common.modules.esign.EsignContract;
import com.suisung.mall.common.modules.esign.EsignContractFillingFile; import com.suisung.mall.common.modules.esign.EsignContractFillingFile;
@ -25,17 +28,30 @@ import com.suisung.mall.shop.esign.service.EsignContractFillingFileService;
import com.suisung.mall.shop.esign.service.EsignContractService; import com.suisung.mall.shop.esign.service.EsignContractService;
import com.suisung.mall.shop.esign.service.EsignPlatformInfoService; import com.suisung.mall.shop.esign.service.EsignPlatformInfoService;
import com.suisung.mall.shop.esign.utils.comm.EsignHttpHelper; import com.suisung.mall.shop.esign.utils.comm.EsignHttpHelper;
import com.suisung.mall.shop.esign.utils.comm.EsignHttpResponse;
import com.suisung.mall.shop.esign.utils.enums.EsignRequestType; import com.suisung.mall.shop.esign.utils.enums.EsignRequestType;
import com.suisung.mall.shop.esign.utils.exception.EsignDemoException; import com.suisung.mall.shop.esign.utils.exception.EsignDemoException;
import com.suisung.mall.shop.page.service.OssService; import com.suisung.mall.shop.page.service.OssService;
import com.suisung.mall.shop.store.service.ShopMerchEntryService; import com.suisung.mall.shop.store.service.ShopMerchEntryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j
@Service @Service
public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMapper, EsignContract> implements EsignContractService { public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMapper, EsignContract> implements EsignContractService {
@ -68,28 +84,177 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
@Resource @Resource
private EsignPlatformInfoService esignPlatformInfoService; private EsignPlatformInfoService esignPlatformInfoService;
// @Resource
// private EsignContractService esignContractService;
@Resource @Resource
private OssService ossService; private OssService ossService;
@Override /***
public Object signFlowCreateByFile() { * 获取请求签名值
String jsonParm = "{\"docs\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"fileName\":\"平台商户入驻合同协议.pdf\"}],\"signFlowConfig\":{\"signFlowTitle\":\"平台商户入驻合同协议\",\"signFlowExpireTime\":1746844718000,\"autoFinish\":true,\"notifyUrl\":\"https://mall.gpxscs.cn/asyn/notify\",\"redirectConfig\":{\"redirectUrl\":\"https://mall.gpxscs.cn/\"}},\"signers\":[{\"signConfig\":{\"signOrder\":1},\"noticeConfig\":{\"noticeTypes\":\"1\"},\"signerType\":0,\"psnSignerInfo\":{\"psnAccount\":\"13128997057\",\"psnInfo\":{\"psnName\":\"潘军杰\"}},\"signFields\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":40,\"positionX\":472.3607,\"positionY\":277.19104}}},{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":5,\"positionX\":470.58798,\"positionY\":589.14496}}}]},{\"signConfig\":{\"signOrder\":2},\"noticeConfig\":{\"noticeTypes\":\"1\"},\"signerType\":1,\"orgSignerInfo\":{\"orgName\":\"桂平发发网络有限公司\",\"orgInfo\":{\"orgIDCardNum\":\"91450881MADEQ92533\",\"orgIDCardType\":\"CRED_ORG_USCC\"},\"transactorInfo\":{\"psnAccount\":\"17777525395\",\"psnInfo\":{\"psnName\":\"谢能坤\"}}},\"signFields\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":2,\"positionX\":479.04996,\"positionY\":357.2327}}},{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":5,\"positionX\":255.96832,\"positionY\":588.4553}}}]}]}"; *
* @param data
* 加密前数据
* @param key
* 密钥
* @param algorithm
* HmacMD5 HmacSHA1 HmacSHA256 HmacSHA384 HmacSHA512
* @param encoding
* 编码格式
* @return HMAC加密后16进制字符串
* @throws Exception
*/
public static String getSignature(String data, String key, String algorithm, String encoding) {
Mac mac = null;
try {
mac = Mac.getInstance(algorithm);
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(encoding), algorithm);
mac.init(secretKey);
mac.update(data.getBytes(encoding));
} catch (NoSuchAlgorithmException e) {
log.error("获取Signature签名信息异常{}", e.getMessage());
return null;
} catch (UnsupportedEncodingException e) {
log.error("获取Signature签名信息异常{}", e.getMessage());
return null;
} catch (InvalidKeyException e) {
log.error("获取Signature签名信息异常{}", e.getMessage());
return null;
}
return byte2hex(mac.doFinal());
}
/***
* 将byte[]转成16进制字符串
*
* @param data
*
* @return 16进制字符串
*/
public static String byte2hex(byte[] data) {
StringBuilder hash = new StringBuilder();
String stmp;
for (int n = 0; data != null && n < data.length; n++) {
stmp = Integer.toHexString(data[n] & 0XFF);
if (stmp.length() == 1)
hash.append('0');
hash.append(stmp);
}
return hash.toString();
}
/**
* 基于文件发起签署电子合同
*
* @return
*/
@Override
public CommonResult signFlowCreateByFile(String mchMobile) {
if (StrUtil.isBlank(mchMobile)) {
return CommonResult.failed("缺少必要参数!");
}
EsignContract esignContract = getEsignContractByMchMobile(mchMobile);
if (esignContract == null) {
return CommonResult.failed("未找到商家合同信息");
}
//"{\"docs\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"fileName\":\"平台商户入驻合同协议.pdf\"}],\"signFlowConfig\":{\"signFlowTitle\":\"平台商户入驻合同协议\",\"signFlowExpireTime\":1746844718000,\"autoFinish\":true,\"notifyUrl\":\"https://mall.gpxscs.cn/asyn/notify\",\"redirectConfig\":{\"redirectUrl\":\"https://mall.gpxscs.cn/\"}},\"signers\":[{\"signConfig\":{\"signOrder\":1},\"noticeConfig\":{\"noticeTypes\":\"1\"},\"signerType\":0,\"psnSignerInfo\":{\"psnAccount\":\"13128997057\",\"psnInfo\":{\"psnName\":\"潘军杰\"}},\"signFields\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":40,\"positionX\":472.3607,\"positionY\":277.19104}}},{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":5,\"positionX\":470.58798,\"positionY\":589.14496}}}]},{\"signConfig\":{\"signOrder\":2},\"noticeConfig\":{\"noticeTypes\":\"1\"},\"signerType\":1,\"orgSignerInfo\":{\"orgName\":\"桂平发发网络有限公司\",\"orgInfo\":{\"orgIDCardNum\":\"91450881MADEQ92533\",\"orgIDCardType\":\"CRED_ORG_USCC\"},\"transactorInfo\":{\"psnAccount\":\"17777525395\",\"psnInfo\":{\"psnName\":\"谢能坤\"}}},\"signFields\":[{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":2,\"positionX\":479.04996,\"positionY\":357.2327}}},{\"fileId\":\"ab30d2c5600441f4a7daf512e4d69157\",\"normalSignFieldConfig\":{\"signFieldStyle\":1,\"signFieldPosition\":{\"positionPage\":5,\"positionX\":255.96832,\"positionY\":588.4553}}}]}]}";
// esignContractService.
String jsonParams = esignContract.getReq_params();
try { try {
//请求方法 //请求方法
EsignRequestType requestType = EsignRequestType.POST; EsignRequestType requestType = EsignRequestType.POST;
String apiaddr = "/v3/sign-flow/create-by-file"; String apiAddr = "/v3/sign-flow/create-by-file";
Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParm, requestType.name(), apiaddr, true); Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParams, requestType.name(), apiAddr, true);
//发起接口请求 //发起接口请求
return EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParm, header, debug); EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiAddr, requestType, jsonParams, header, debug);
if (createByDocTemplate.getStatus() != 200 || createByDocTemplate.getBody() == null) {
throw new EsignDemoException("请求失败,返回状态码:" + createByDocTemplate.getStatus());
}
JSONObject jsonObject = JSONUtil.parseObj(createByDocTemplate.getBody());
Integer code = jsonObject.getInt("code");
String signFlowId = (String) jsonObject.getByPath("data.signFlowId");
if (code == null || code != 0 || StrUtil.isBlank(signFlowId)) {
throw new RuntimeException("请求失败,返回状态码:" + createByDocTemplate.getStatus());
}
//合作方签署状态-1预备数据阶段1-等待签署2 - 已完成所有签署方完成签署3 - 已撤销发起方撤销签署任务5 - 已过期签署截止日到期后触发7 - 已拒签签署方拒绝签署
Boolean success = updateContractFlowIdAndFileUrl(esignContract.getId(), signFlowId, CommonConstant.CONTRACT_SIGN_STA_ING, null);
if (!success) {
throw new RuntimeException("更新合同流程状态失败");
}
return CommonResult.success("合同流程创建成功合同流程ID" + signFlowId);
} catch (EsignDemoException e) { } catch (EsignDemoException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* 签署流程结束通知
*
* @return
*/
@Override
public ResponseEntity<String> signAsyncNotify(HttpServletRequest request, ServerHttpResponse response, String requestBody) {
log.debug("签署流程结束通知:body >>> {}", requestBody);
log.debug("签署流程结束通知:header >>> {}", request.getParameterMap());
//异步通知获取到的header头中的签名值X-Tsign-Open-App-Id
String reqAppId = request.getHeader("X-Tsign-Open-App-Id");
//异步通知获取到的header头中的签名值X-Tsign-Open-SIGNATURE
String signture = request.getHeader("X-Tsign-Open-SIGNATURE");
//异步通知获取到的header头中的时间戳X-Tsign-Open-TIMESTAMP
String timestamp = request.getHeader("X-Tsign-Open-TIMESTAMP");
if (StrUtil.isBlank(reqAppId) || StrUtil.isBlank(signture) || StrUtil.isBlank(timestamp)) {
return new ResponseEntity<>(new JSONObject().put("code", 400).put("msg", "缺少必要参数").toString(), HttpStatus.INTERNAL_SERVER_ERROR);
}
if (!reqAppId.equals(appId)) {
return new ResponseEntity<>(new JSONObject().put("code", 400).put("msg", "appId 校验失败").toString(), HttpStatus.INTERNAL_SERVER_ERROR);
}
//按照规则进行加密
String signData = timestamp + requestBody;
String mySignature = getSignature(signData, appSecret, "HmacSHA256", "UTF-8");
log.debug("加密出来的签名值:----------->>>>>>" + mySignature);
log.debug("header里面的签名值---------->>>>>>" + signture);
if (!mySignature.equals(signture)) {
return new ResponseEntity<>(new JSONObject().put("code", 400).put("msg", "签名校验不匹配").toString(), HttpStatus.INTERNAL_SERVER_ERROR);
}
// 处理业务逻辑
JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody);
String action = reqBodyJSON.getStr("action");
String signFlowId = reqBodyJSON.getStr("signFlowId");
String signFlowStatus = reqBodyJSON.getStr("signFlowStatus");
if (StrUtil.isBlank(action) || StrUtil.isBlank(signFlowId) || StrUtil.isBlank(signFlowStatus)) {
return new ResponseEntity<>(new JSONObject().put("code", 400).put("msg", "返回数据不全").toString(), HttpStatus.INTERNAL_SERVER_ERROR);
}
// 获取正式盖章合同文件上传到 oss 服务器更状态,保存数据
if (action.equals("SIGN_FLOW_COMPLETE")) {// 签署流程完毕
// 获取正式盖章合同文件地址
String downloadUrl = getSignedContractFileUrl(signFlowId);
// 更新合同流程状态和文件地址
boolean success = updateContractFlowStatusAndFileUrlBySignFlowId(signFlowId, CommonConstant.CONTRACT_SIGN_STA_FINISH, downloadUrl);
if (success && StrUtil.isNotBlank(downloadUrl)) {
return new ResponseEntity<>(new JSONObject().put("code", 200).put("msg", "success").toString(), HttpStatus.OK);
}
}
return new ResponseEntity<>(new JSONObject().put("code", 400).put("msg", "更新数据失败").toString(), HttpStatus.INTERNAL_SERVER_ERROR);
}
/** /**
* 更新合同流程ID和正式盖章合同文件地址并上传到 oss 服务器 * 更新合同流程ID和正式盖章合同文件地址并上传到 oss 服务器
* <p> * <p>
@ -97,33 +262,125 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
* *
* @param mchMobile 商家注册手机号 * @param mchMobile 商家注册手机号
* @param contractFileId 未签署合同文件Id * @param contractFileId 未签署合同文件Id
* @param signFlowId 合同签署流程IDsignFlowId和fileUrl 起码一个是必填的 * @param signFlowId 合同签署流程IDsignFlowId和fileUrlsignFlowStatus 起码一个是必填的
* @param fileUrl E签宝的正式签署合同文件地址可空 * @param signFlowStatus 签署流程状态signFlowId和fileUrlsignFlowStatus 起码一个是必填的
* @param fileUrl E签宝的正式签署合同文件地址可空signFlowId和fileUrlsignFlowStatus 起码一个是必填的
* @return * @return
*/ */
@Override @Override
public Boolean updateContractFlowIdAndFileUrl(String mchMobile, String contractFileId, String signFlowId, String fileUrl) { public Boolean updateContractFlowIdAndFileUrl(String mchMobile, String contractFileId, String signFlowId, Integer signFlowStatus, String fileUrl) {
if (StrUtil.isBlank(mchMobile) || StrUtil.isBlank(contractFileId) || (StrUtil.isBlank(signFlowId) && StrUtil.isBlank(fileUrl))) { if (StrUtil.isBlank(mchMobile) || StrUtil.isBlank(contractFileId) || (StrUtil.isBlank(signFlowId) && StrUtil.isBlank(fileUrl))) {
return false; return false;
} }
EsignContract esignContract = getEsignContractByMchMobile(mchMobile);
if (esignContract == null) {
return false;
}
UpdateWrapper<EsignContract> queryWrapper = new UpdateWrapper<>(); UpdateWrapper<EsignContract> queryWrapper = new UpdateWrapper<>();
queryWrapper.eq("mch_mobile", mchMobile); queryWrapper.eq("id", esignContract.getId());
queryWrapper.eq("contract_file_id", contractFileId);
queryWrapper.eq("status", CommonConstant.Enable);
if (StrUtil.isNotBlank(signFlowId)) { if (StrUtil.isNotBlank(signFlowId)) {
queryWrapper.set("sign_flow_id", signFlowId); queryWrapper.set("sign_flow_id", signFlowId);
} }
if (signFlowStatus != null) {
queryWrapper.set("sign_flow_status", signFlowStatus);
}
if (StrUtil.isNotBlank(fileUrl)) { if (StrUtil.isNotBlank(fileUrl)) {
queryWrapper.set("signed_contract_url", fileUrl); queryWrapper.set("signed_contract_url", fileUrl);
// REMARK 把合同文件 url 上传到cos服务器 // REMARK 把合同文件 url 上传到cos服务器
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract") String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract")
.concat("/") .concat("/")
.concat(esignContract.getMch_biz_license()).concat("/")
.concat("signed").concat("/") .concat("signed").concat("/")
.concat(contractFileId).concat(".pdf"); .concat(esignContract.getContract_file_id()).concat(".pdf");
// 上传到cos服务器
String localFileUrl = ossService.uploadObject4OSS(fileUrl, cosFileName);
queryWrapper.set("local_contract_url", localFileUrl);
}
return this.update(queryWrapper);
}
/**
* 更新合同流程ID和文件地址和状态
*
* @param id 自增Id
* @param signFlowId 签署流程Id
* @param signFlowStatus 签署流程状态
* @param fileUrl 盖章合同文件地址
* @return
*/
@Override
public Boolean updateContractFlowIdAndFileUrl(Long id, String signFlowId, Integer signFlowStatus, String fileUrl) {
if (ObjectUtil.isEmpty(id) || (StrUtil.isBlank(signFlowId) && ObjectUtil.isEmpty(signFlowStatus) && StrUtil.isBlank(fileUrl))) {
return false;
}
EsignContract esignContract = get(id);
if (esignContract == null) {
return false;
}
UpdateWrapper<EsignContract> queryWrapper = new UpdateWrapper<>();
queryWrapper.eq("id", id);
if (StrUtil.isNotBlank(signFlowId)) {
queryWrapper.set("sign_flow_id", signFlowId);
}
if (signFlowStatus != null) {
queryWrapper.set("sign_flow_status", signFlowStatus);
}
if (StrUtil.isNotBlank(fileUrl)) {
queryWrapper.set("signed_contract_url", fileUrl);
// REMARK 把合同文件 url 上传到cos服务器
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract")
.concat("/")
.concat(esignContract.getMch_biz_license()).concat("/")
.concat("signed").concat("/")
.concat(esignContract.getContract_file_id()).concat(".pdf");
// 上传到cos服务器
String localFileUrl = ossService.uploadObject4OSS(fileUrl, cosFileName);
queryWrapper.set("local_contract_url", localFileUrl);
}
return this.update(queryWrapper);
}
@Override
public Boolean updateContractFlowStatusAndFileUrlBySignFlowId(String signFlowId, Integer signFlowStatus, String fileUrl) {
if (StrUtil.isBlank(signFlowId) || (ObjectUtil.isEmpty(signFlowStatus) && StrUtil.isBlank(fileUrl))) {
return false;
}
EsignContract esignContract = getEsignContractBySignFlowId(signFlowId);
if (esignContract == null) {
return false;
}
UpdateWrapper<EsignContract> queryWrapper = new UpdateWrapper<>();
queryWrapper.eq("id", esignContract.getId());
if (signFlowStatus != null) {
queryWrapper.set("sign_flow_status", signFlowStatus);
}
if (StrUtil.isNotBlank(fileUrl)) {
queryWrapper.set("signed_contract_url", fileUrl);
// REMARK 把合同文件 url 上传到cos服务器
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract")
.concat("/")
.concat(esignContract.getMch_biz_license()).concat("/")
.concat("signed").concat("/")
.concat(esignContract.getContract_file_id()).concat(".pdf");
// 上传到cos服务器 // 上传到cos服务器
String localFileUrl = ossService.uploadObject4OSS(fileUrl, cosFileName); String localFileUrl = ossService.uploadObject4OSS(fileUrl, cosFileName);
queryWrapper.set("local_contract_url", localFileUrl); queryWrapper.set("local_contract_url", localFileUrl);
@ -185,6 +442,85 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
return saveOrUpdateByMchMobile(esignContract); return saveOrUpdateByMchMobile(esignContract);
} }
/**
* 根据商家注册手机号获取一条合同信息
*
* @param mchMobile
* @return
*/
@Override
public EsignContract getEsignContractByMchMobile(String mchMobile) {
QueryWrapper<EsignContract> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mch_mobile", mchMobile);
queryWrapper.eq("status", CommonConstant.Enable);
List<EsignContract> esignContractList = this.list(queryWrapper);
if (CollectionUtil.isEmpty(esignContractList)) {
return null;
}
return esignContractList.get(0);
}
@Override
public EsignContract getEsignContractBySignFlowId(String signFlowId) {
QueryWrapper<EsignContract> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("sign_flow_id", signFlowId);
queryWrapper.eq("status", CommonConstant.Enable);
List<EsignContract> esignContractList = this.list(queryWrapper);
if (CollectionUtil.isEmpty(esignContractList)) {
return null;
}
return esignContractList.get(0);
}
/**
* 根据合同流程ID获取完成签署生效的合同文件地址
* <p>
* 收到异步通知签署完成之后获取合同文件地址保存并上传到 oss
*
* @param signFlowId
* @return
*/
@Override
public String getSignedContractFileUrl(String signFlowId) {
String apiAddr = "/v3/sign-flow/" + signFlowId + "/file-download-url";
try {
//请求方法
EsignRequestType requestType = EsignRequestType.GET;
//生成签名鉴权方式的的header
Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, null, requestType.name(), apiAddr, true);
//发起接口请求
EsignHttpResponse esignHttpResponse = EsignHttpHelper.doCommHttp(serverUrl, apiAddr, requestType, null, header, debug);
if (esignHttpResponse.getStatus() != 200 || StrUtil.isEmpty(esignHttpResponse.getBody())) {
return null;
}
JSONObject jsonObject = JSONUtil.parseObj(esignHttpResponse.getBody());
if (jsonObject == null || !jsonObject.getInt("code").equals(0)
|| ObjectUtil.isEmpty(jsonObject.get("data"))
|| ObjectUtil.isEmpty(jsonObject.getByPath("data.files"))) {
return null;
}
JSONArray files = jsonObject.getJSONArray("data.files");
if (CollectionUtil.isEmpty(files)) {
return null;
}
return files.getJSONObject(0).getStr("downloadUrl");
} catch (EsignDemoException e) {
// throw new RuntimeException(e);
log.error(e.getMessage(), e);
return null;
}
}
// e签宝签名相关方法
/** /**
* 根据商家的注册手机号新增或更新签署合同记录 * 根据商家的注册手机号新增或更新签署合同记录
* *
@ -203,7 +539,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
} }
/** /**
* 组织生成签署合同的请求参数 * 重要组织生成签署合同的请求参数
* *
* @param shopMerchEntry * @param shopMerchEntry
* @param esignPlatformInfo * @param esignPlatformInfo
@ -229,7 +565,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
signFlowConfig.put("signFlowTitle", contractName); signFlowConfig.put("signFlowTitle", contractName);
signFlowConfig.put("signFlowExpireTime", System.currentTimeMillis() + 90L * 24 * 60 * 60 * 1000); // 90天 signFlowConfig.put("signFlowExpireTime", System.currentTimeMillis() + 90L * 24 * 60 * 60 * 1000); // 90天
signFlowConfig.put("autoFinish", true); signFlowConfig.put("autoFinish", true);
signFlowConfig.put("notifyUrl", main_domain + "/admin/shop/esign/asyn/notify"); signFlowConfig.put("notifyUrl", main_domain + "/admin/shop/esign/async/notify");
signFlowConfig.putByPath("signFlowConfig.redirectUrl", "wechat://back"); signFlowConfig.putByPath("signFlowConfig.redirectUrl", "wechat://back");
reqParams.put("signFlowConfig", signFlowConfig); reqParams.put("signFlowConfig", signFlowConfig);
@ -275,7 +611,7 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
// 个人 // 个人
platSigner.put("signerType", 0); platSigner.put("signerType", 0);
platSigner.putByPath("psnSignerInfo.psnAccount", esignPlatformInfo.getLegal_person_mobile()); platSigner.putByPath("psnSignerInfo.psnAccount", esignPlatformInfo.getLegal_person_mobile());
platSigner.putByPath("psnSignerInfo.psnInfo.psnName", shopMerchEntry.getLegal_person_name()); platSigner.putByPath("psnSignerInfo.psnInfo.psnName", esignPlatformInfo.getLegal_person_name());
} }
// 加入乙方平台方信息 // 加入乙方平台方信息
signers.add(platSigner); signers.add(platSigner);

View File

@ -31,6 +31,7 @@ import com.suisung.mall.shop.message.service.ShopMessageTemplateService;
import com.suisung.mall.shop.store.mapper.ShopMerchEntryMapper; import com.suisung.mall.shop.store.mapper.ShopMerchEntryMapper;
import com.suisung.mall.shop.store.service.ShopMerchEntryService; import com.suisung.mall.shop.store.service.ShopMerchEntryService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair; import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -56,7 +57,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl<ShopMerchEntryMap
@Resource @Resource
private EsignContractFillingFileService esignContractFillingFileService; private EsignContractFillingFileService esignContractFillingFileService;
@Resource @Autowired
private TaskService taskService; private TaskService taskService;
@ -392,6 +393,7 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl<ShopMerchEntryMap
// 多线程执行电子合同生成和填充 // 多线程执行电子合同生成和填充
taskService.executeTask(() -> { taskService.executeTask(() -> {
log.debug("###开始异步执行生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件###");
// 生成电子合同模版和填充模版数据并生该商家和平台方签署的未盖章合同文件 // 生成电子合同模版和填充模版数据并生该商家和平台方签署的未盖章合同文件
Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(record.getBiz_license_number(), ""); Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(record.getBiz_license_number(), "");
if (!genSuccess) { if (!genSuccess) {