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

This commit is contained in:
Jack 2025-03-11 17:01:31 +08:00
parent 66c4dc5065
commit 773d886aa6
16 changed files with 595 additions and 32 deletions

View File

@ -50,4 +50,8 @@ public class CommonConstant {
public static final Integer MCH_APPR_STA_NOPASS = 2;
public static final Integer MCH_APPR_STA_PADDING = 3;
public static final Integer MCH_APPR_STA_NONE = 4;
// 入驻商家主体类型企业或个人1-企业2-个人
public static final Integer MCH_ENTITY_TYPE_QY = 1;
public static final Integer MCH_ENTITY_TYPE_GR = 2;
}

View File

@ -32,9 +32,6 @@ public class EsignContract implements Serializable {
@ApiModelProperty(value = "自增ID")
private Long id;
@ApiModelProperty(value = "店铺编号")
private String store_id;
@ApiModelProperty(value = "合同编号,自定义生成")
private String contract_number;
@ -44,6 +41,21 @@ public class EsignContract implements Serializable {
@ApiModelProperty(value = "合同模版Id")
private String doc_template_id;
@ApiModelProperty(value = "合同文件Id")
private String contract_file_id;
@ApiModelProperty(value = "签署合同请求参数")
private String req_params;
@ApiModelProperty(value = "商家注册手机号")
private String mch_mobile;
@ApiModelProperty(value = "商家营业执照编号,如果是个人,可空")
private String mch_biz_license;
@ApiModelProperty(value = "商家公司名称")
private String mch_company;
@ApiModelProperty(value = "生成的未签署合同地址30天有效期")
private String unsigned_contract_url;
@ -53,6 +65,15 @@ public class EsignContract implements Serializable {
@ApiModelProperty(value = "未签署合同地址本地下载地址")
private String local_contract_url;
@ApiModelProperty(value = "合作方签署状态1-等待签署2 - 已完成所有签署方完成签署3 - 已撤销发起方撤销签署任务5 - 已过期签署截止日到期后触发7 - 已拒签(签署方拒绝签署)")
private Integer sign_flow_status;
@ApiModelProperty(value = "店铺编号")
private String store_id;
@ApiModelProperty(value = "签署流程ID")
private String sign_flow_id;
@ApiModelProperty(value = "记录状态:1-有效2-无效;")
private Integer status;

View File

@ -56,6 +56,12 @@ public class EsignContractFillingFile implements Serializable {
@ApiModelProperty(value = "未签署合同地址本地下载地址")
private String unsigned_contract_local_url;
@ApiModelProperty(value = "甲方签署印章XY位置")
private String mch_sign_position;
@ApiModelProperty(value = "乙方(平台方)签署印章XY位置")
private String plat_sign_position;
@ApiModelProperty(value = "合同排序")
private Integer seq;

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2025. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
* Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
* Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
* Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
* Vestibulum commodo. Ut rhoncus gravida arcu.
*/
package com.suisung.mall.shop.components;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 使用方法
*
* @Autowired private TaskService taskService;
* <p>
* public void run(String... args) throws Exception {
* // 定义一个任务
* Runnable task = () -> {
* System.out.println("任务正在执行,线程: " + Thread.currentThread().getName());
* try {
* Thread.sleep(2000);
* } catch (InterruptedException e) {
* e.printStackTrace();
* }
* System.out.println("任务执行完成,线程: " + Thread.currentThread().getName());
* };
* <p>
* // 使用线程池执行任务
* taskService.executeTask(task);
* <p>
* System.out.println("主线程继续执行其他任务");
* }
*/
@Service
public class TaskService {
private final ThreadPoolExecutor threadPoolExecutor;
@Autowired
public TaskService(ThreadPoolExecutor threadPoolExecutor) {
this.threadPoolExecutor = threadPoolExecutor;
}
public void executeTask(Runnable task) {
threadPoolExecutor.execute(task);
}
}

View File

@ -8,7 +8,9 @@
package com.suisung.mall.shop.esign.service;
import cn.hutool.json.JSONArray;
import com.suisung.mall.common.modules.esign.EsignContractFillingFile;
import org.springframework.data.util.Pair;
public interface EsignContractFillingFileService {
@ -21,6 +23,15 @@ public interface EsignContractFillingFileService {
*/
Boolean fillDocTemplate(String mchLicenseNumber, String platLicenseNumber);
/**
* 获取模版的甲方与乙方印章XY位置数据
*
* @param docTemplateId
* @param fileId
* @return
*/
Pair<JSONArray, JSONArray> getSignPosition(String docTemplateId, String fileId);
/**
* 根据注册手机号禁用合同
*
@ -44,4 +55,14 @@ public interface EsignContractFillingFileService {
* @return
*/
Boolean trySaveRecord(EsignContractFillingFile esignContractFillingFile);
/**
* 根据商家手机号和模版ID获取合同填充文件
*
* @param mchMobile
* @param templateId
* @return
*/
EsignContractFillingFile getEsignContractFillingFile(String mchMobile, String templateId);
}

View File

@ -11,4 +11,24 @@ package com.suisung.mall.shop.esign.service;
public interface EsignContractService {
Object signFlowCreateByFile();
/**
* 更新合同流程ID和文件地址
*
* @param mchMobile
* @param contractFileId
* @param signFlowId
* @param fileUrl
* @return
*/
Boolean updateContractFlowIdAndFileUrl(String mchMobile, String contractFileId, String signFlowId, String fileUrl);
/**
* 商家入驻审核通过模版就绪之后预创建签署流程
*
* @param mchMobile
* @param templateId
* @return
*/
Boolean preCreateSignFlow(String mchMobile, String templateId);
}

View File

@ -24,6 +24,7 @@ import com.suisung.mall.common.utils.StringUtils;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.esign.mapper.EsignContractFillingFileMapper;
import com.suisung.mall.shop.esign.service.EsignContractFillingFileService;
import com.suisung.mall.shop.esign.service.EsignContractService;
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.EsignHttpResponse;
@ -33,6 +34,8 @@ import com.suisung.mall.shop.page.service.OssService;
import com.suisung.mall.shop.store.service.ShopMerchEntryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@ -57,6 +60,9 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
@Value("${esign.app_secret}")
private String appSecret;
@Value("${esign.debug}")
private Boolean debug;
@Value("#{accountBaseConfigService.getConfig('tengxun_default_dir')}")
private String TENGXUN_DEFAULT_DIR;
@ -69,11 +75,18 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
@Resource
private EsignContractFillingFileService esignContractFillingFileService;
@Lazy
@Resource
private EsignContractService esignContractService;
@Resource
private OssService ossService;
/**
* 更加双方营业执照号码填充合同模版生成合同文件地址
* 根据双方营业执照号码填充合同模版生成合同文件地址
* <p>
* 后台管理员审核商家通过之后触发调用这个方法生成未签署合同文件预备签署
*
* @param mchLicenseNumber 入驻商家(甲方)的营业执照号
* @param platLicenseNumber 平台方代理商方乙方营业执照号
@ -81,17 +94,15 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
*/
@Override
public Boolean fillDocTemplate(String mchLicenseNumber, String platLicenseNumber) {
// 获取平台方的信息
EsignPlatformInfo esignPlatformInfo = new EsignPlatformInfo();
if (StrUtil.isNotEmpty(platLicenseNumber)) {
esignPlatformInfo = esignPlatformInfoService.getEsignPlatformInfo(null, platLicenseNumber);
}
if (ObjectUtils.isEmpty(esignPlatformInfo)) {
esignPlatformInfo = esignPlatformInfoService.getEsignPlatformInfo(0, "");
if (StrUtil.isEmpty(mchLicenseNumber)) {
log.error("商家营业执照号为空");
return false;
}
// 获取平台方的信息
EsignPlatformInfo esignPlatformInfo = esignPlatformInfoService.getEsignPlatformInfo(0, platLicenseNumber);
if (ObjectUtils.isEmpty(esignPlatformInfo)) {
log.error("缺少平台方(代理商方)信息");
log.error("请添加平台方(代理商方)信息");
return null;
}
@ -123,12 +134,11 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
int successCnt = 0;
// 模版文件里有三份合同顺序排列的: 1.平台商户入驻服务框架协议 2.小发同城服务费结算 3.结算授权委托书
for (Object template : templates) {
for (JSONObject template : templates.jsonIter()) {
// 从商家信息里获取模版的信息
JSONObject templateJson = (JSONObject) template;
String templateId = templateJson.getStr("template_id");
String fileName = templateJson.getStr("template_name");
int seq = templateJson.getInt("seq");
String templateId = template.getStr("template_id");
String fileName = template.getStr("template_name");
int seq = template.getInt("seq");
// 获取填充模版的数据
JSONObject fillJson = new JSONObject();
@ -141,7 +151,7 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_contracts");
put("componentValue", "平台商户入驻服务框架协议小发同城服务费结算");
put("componentValue", "平台商户入驻服务框架协议和小发同城服务费结算");
}});
// 签署时间
@ -245,9 +255,9 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
//生成签名鉴权方式的的header
Map<String, String> header = null;
try {
header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParma, requestType.name(), apiaddr, true);
header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParma, requestType.name(), apiaddr, debug);
//发起接口请求
EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParma, header, true);
EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParma, header, debug);
log.info("合同生成数据:{}", createByDocTemplate);
if (createByDocTemplate.getStatus() != 200) {
return false;
@ -257,6 +267,7 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
JSONObject jsonObject = JSONUtil.parseObj(createByDocTemplate.getBody()).getJSONObject("data");
esignContractFillingFile.setUnsigned_contract_url(jsonObject.getStr("fileDownloadUrl"));
String fileId = jsonObject.getStr("fileId");
// 把合同文件 url 上传到cos服务器
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract")
@ -265,7 +276,7 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
// 上传到cos服务器
String localFileUrl = ossService.uploadObject4OSS(esignContractFillingFile.getUnsigned_contract_url(), cosFileName);
esignContractFillingFile.setUnsigned_contract_local_url(localFileUrl);
esignContractFillingFile.setFile_id(jsonObject.getStr("fileId"));
esignContractFillingFile.setFile_id(fileId);
esignContractFillingFile.setDoc_template_id(templateId);
esignContractFillingFile.setContract_number(contractNumber + seq);
@ -276,8 +287,18 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
esignContractFillingFile.setSeq(seq);
esignContractFillingFile.setStatus(CommonConstant.Enable);
// 获取印章的位置信息写入数据库
Pair<JSONArray, JSONArray> signPositionPair = getSignPosition(templateId, fileId);
if (signPositionPair != null) {
esignContractFillingFile.setMch_sign_position(signPositionPair.getFirst().toString());
esignContractFillingFile.setPlat_sign_position(signPositionPair.getSecond().toString());
}
if (esignContractFillingFileService.trySaveRecord(esignContractFillingFile)) {
successCnt += 1;
// 预新增一个签署合同记录(要不要异步执行)
esignContractService.preCreateSignFlow(esignContractFillingFile.getMobile(), esignContractFillingFile.getDoc_template_id());
}
} catch (EsignDemoException e) {
@ -288,6 +309,78 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
return successCnt > 0;
}
/**
* 获取模版的甲方与乙方印章XY位置数据
*
* @param docTemplateId
* @param fileId
* @return
*/
@Override
public Pair<JSONArray, JSONArray> getSignPosition(String docTemplateId, String fileId) {
String apiaddr = "/v3/doc-templates/" + docTemplateId;
//请求参数body体,json格式get或者delete请求时jsonString传空json:"{}"或者null
String jsonParm = null;
try {
//请求方法
EsignRequestType requestType = EsignRequestType.GET;
//生成签名鉴权方式的的header
Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParm, requestType.name(), apiaddr, debug);
//发起接口请求
EsignHttpResponse resp = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParm, header, debug);
if (resp.getStatus() != 200 || StrUtil.isEmpty(resp.getBody())) {
return null;
}
JSONArray components = JSONUtil.parseObj(resp.getBody()).getJSONObject("data").getJSONArray("components");
if (CollectionUtil.isEmpty(components)) {
return null;
}
// 处理符合的数据
// Pair<JSONArray,JSONArray> pair = new Pair<>();
JSONArray retMchArr = new JSONArray();
JSONArray retPlatArr = new JSONArray();
for (JSONObject component : components.jsonIter()) {
String componentName = component.getStr("componentName");
String customBizNum = StringUtils.genLklOrderNo(4);
if (componentName.equals("甲方签署区")) {
JSONObject signFields = new JSONObject();
signFields.put("customBizNum", customBizNum);
signFields.put("fileId", fileId);
signFields.put("normalSignFieldConfig", component.getJSONArray("signFields"));
signFields.putByPath("normalSignFieldConfig.signFieldStyle", 1); //签章区样式 1 - 单页签章2 - 骑缝签章点击了解 骑缝盖章
JSONObject signFieldPosition = new JSONObject();
signFieldPosition.put("positionPage", component.getByPath("componentPosition.componentPageNum"));
signFieldPosition.put("positionX", component.getByPath("componentPosition.componentPositionX"));
signFieldPosition.put("positionY", component.getByPath("componentPosition.componentPositionY"));
signFields.putByPath("normalSignFieldConfig.signFieldPosition", signFieldPosition);
retMchArr.add(signFields);
} else if (componentName.equals("乙方签署区")) {
JSONObject signFields = new JSONObject();
signFields.put("customBizNum", customBizNum);
signFields.put("fileId", fileId);
signFields.put("normalSignFieldConfig", component.getJSONArray("signFields"));
signFields.putByPath("normalSignFieldConfig.signFieldStyle", 1); //签章区样式 1 - 单页签章2 - 骑缝签章点击了解 骑缝盖章
JSONObject signFieldPosition = new JSONObject();
signFieldPosition.put("positionPage", component.getByPath("componentPosition.componentPageNum"));
signFieldPosition.put("positionX", component.getByPath("componentPosition.componentPositionX"));
signFieldPosition.put("positionY", component.getByPath("componentPosition.componentPositionY"));
signFields.putByPath("normalSignFieldConfig.signFieldPosition", signFieldPosition);
retPlatArr.add(signFields);
}
}
return Pair.of(retMchArr, retPlatArr);
} catch (EsignDemoException e) {
log.error("获取模版的印章XY位置数据失败", e);
return null;
}
}
/**
* 更加双方营业执照号码填充合同模版生成合同文件地址
*
@ -494,9 +587,9 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
//生成签名鉴权方式的的header
Map<String, String> header = null;
try {
header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParma, requestType.name(), apiaddr, true);
header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParma, requestType.name(), apiaddr, debug);
//发起接口请求
EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParma, header, true);
EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParma, header, debug);
log.info("合同生成数据:{}", createByDocTemplate);
if (createByDocTemplate.getStatus() != 200) {
return false;
@ -584,4 +677,23 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
return true;
}
/**
* 根据商家手机号和模版ID获取合同填充文件
*
* @param mchMobile
* @param templateId
* @return
*/
@Override
public EsignContractFillingFile getEsignContractFillingFile(String mchMobile, String templateId) {
QueryWrapper<EsignContractFillingFile> queryWrapper = new QueryWrapper();
queryWrapper.eq("mobile", mchMobile).eq("doc_template_id", templateId).eq("status", CommonConstant.Enable);
List<EsignContractFillingFile> list = list(queryWrapper);
if (CollectionUtil.isEmpty(list)) {
return null;
}
return list.get(0);
}
}

View File

@ -8,16 +8,32 @@
package com.suisung.mall.shop.esign.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.suisung.mall.common.constant.CommonConstant;
import com.suisung.mall.common.modules.esign.EsignContract;
import com.suisung.mall.common.modules.esign.EsignContractFillingFile;
import com.suisung.mall.common.modules.esign.EsignPlatformInfo;
import com.suisung.mall.common.modules.merch.ShopMerchEntry;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.esign.mapper.EsignContractMapper;
import com.suisung.mall.shop.esign.service.EsignContractFillingFileService;
import com.suisung.mall.shop.esign.service.EsignContractService;
import com.suisung.mall.shop.esign.service.EsignPlatformInfoService;
import com.suisung.mall.shop.esign.utils.comm.EsignHttpHelper;
import com.suisung.mall.shop.esign.utils.enums.EsignRequestType;
import com.suisung.mall.shop.esign.utils.exception.EsignDemoException;
import com.suisung.mall.shop.page.service.OssService;
import com.suisung.mall.shop.store.service.ShopMerchEntryService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Map;
@Service
@ -32,20 +48,240 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
@Value("${esign.app_secret}")
private String appSecret;
@Value("${esign.debug}")
private Boolean debug;
@Value("#{accountBaseConfigService.getConfig('tengxun_default_dir')}")
private String TENGXUN_DEFAULT_DIR;
@Value("${main_domain}")
private String main_domain;
@Lazy
@Resource
private EsignContractFillingFileService esignContractFillingFileService;
@Resource
private ShopMerchEntryService shopMerchEntryService;
@Resource
private EsignPlatformInfoService esignPlatformInfoService;
@Resource
private OssService ossService;
@Override
public Object signFlowCreateByFile() {
String jsonParm = "{'docs':[{'fileId':'14042f4bf8ce4fc9ba798906c16c0333','fileName':'平台商户入驻合同协议.pdf'}],'signFlowConfig':{'signFlowTitle':'平台商户入驻合同协议','signFlowExpireTime':169111118000,'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':[{'customBizNum':'0987654321','fileId':'14042f4bf8ce4fc9ba798906c16c0333','normalSignFieldConfig':{'signFieldStyle':1}}]},{'signConfig':{'signOrder':2},'signerType':1,'signFields':[{'customBizNum':'1234567890','fileId':'14042f4bf8ce4fc9ba798906c16c0333','normalSignFieldConfig':{'autoSign':true,'signFieldStyle':1}}]}]}";
String apiaddr = "/v3/sign-flow/create-by-file";
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}}}]}]}";
//请求方法
EsignRequestType requestType = EsignRequestType.POST;
try {
//请求方法
EsignRequestType requestType = EsignRequestType.POST;
String apiaddr = "/v3/sign-flow/create-by-file";
Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParm, requestType.name(), apiaddr, true);
//发起接口请求
return EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParm, header, true);
return EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParm, header, debug);
} catch (EsignDemoException e) {
throw new RuntimeException(e);
}
}
/**
* 更新合同流程ID和正式盖章合同文件地址并上传到 oss 服务器
* <p>
* 发起合同签署流程后根据返回的流程Id 更改记录收到完成签署异步通知之后更改正式签署合同的地址
*
* @param mchMobile 商家注册手机号
* @param contractFileId 未签署合同文件Id
* @param signFlowId 合同签署流程IDsignFlowId和fileUrl 起码一个是必填的
* @param fileUrl E签宝的正式签署合同文件地址可空
* @return
*/
@Override
public Boolean updateContractFlowIdAndFileUrl(String mchMobile, String contractFileId, String signFlowId, String fileUrl) {
if (StrUtil.isBlank(mchMobile) || StrUtil.isBlank(contractFileId) || (StrUtil.isBlank(signFlowId) && StrUtil.isBlank(fileUrl))) {
return false;
}
UpdateWrapper<EsignContract> queryWrapper = new UpdateWrapper<>();
queryWrapper.eq("mch_mobile", mchMobile);
queryWrapper.eq("contract_file_id", contractFileId);
queryWrapper.eq("status", CommonConstant.Enable);
if (StrUtil.isNotBlank(signFlowId)) {
queryWrapper.set("sign_flow_id", signFlowId);
}
if (StrUtil.isNotBlank(fileUrl)) {
queryWrapper.set("signed_contract_url", fileUrl);
// REMARK 把合同文件 url 上传到cos服务器
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract")
.concat("/")
.concat("signed").concat("/")
.concat(contractFileId).concat(".pdf");
// 上传到cos服务器
String localFileUrl = ossService.uploadObject4OSS(fileUrl, cosFileName);
queryWrapper.set("local_contract_url", localFileUrl);
}
return this.update(queryWrapper);
}
/**
* 商家入驻审核通过模版就绪之后预创建签署流程
*
* @param mchMobile
* @param templateId
* @return
*/
@Override
public Boolean preCreateSignFlow(String mchMobile, String templateId) {
if (StrUtil.isBlank(mchMobile) || StrUtil.isBlank(templateId)) {
return false;
}
EsignContractFillingFile esignContractFillingFile = esignContractFillingFileService.getEsignContractFillingFile(mchMobile, templateId);
if (esignContractFillingFile == null || !esignContractFillingFile.getStatus().equals(CommonConstant.Enable)) {
return false;
}
// 获取商家审核通过的入驻信息
ShopMerchEntry shopMerchEntry = shopMerchEntryService.getShopMerchEntryByLicenseNumber(esignContractFillingFile.getMobile(), "", CommonConstant.MCH_APPR_STA_PASS);
if (shopMerchEntry == null) {
return false;
}
// 获取乙方平台方信息
EsignPlatformInfo esignPlatformInfo = esignPlatformInfoService.getEsignPlatformInfo(0, "");
if (esignPlatformInfo == null) {
return false;
}
// 未签合同文件ID
String fileId = esignContractFillingFile.getFile_id();
// 组织生成签署合同的请求参数
String reqParams = buildSignReqParams(shopMerchEntry, esignPlatformInfo, esignContractFillingFile);
// 保存签署合同记录
EsignContract esignContract = new EsignContract();
esignContract.setContract_number(esignContractFillingFile.getContract_number());
esignContract.setDoc_template_id(esignContractFillingFile.getDoc_template_id());
esignContract.setContract_name(esignContractFillingFile.getContract_name());
esignContract.setContract_file_id(fileId);
esignContract.setMch_mobile(esignContractFillingFile.getMobile());
esignContract.setMch_company(shopMerchEntry.getBiz_license_company());
esignContract.setMch_biz_license(shopMerchEntry.getBiz_license_number());
esignContract.setReq_params(reqParams);
esignContract.setUnsigned_contract_url(esignContractFillingFile.getUnsigned_contract_local_url());
esignContract.setStore_id(esignContractFillingFile.getStore_id());
esignContract.setSign_flow_status(-1);//合作方签署状态-1:预备数据阶段1-等待签署2 - 已完成所有签署方完成签署3 - 已撤销发起方撤销签署任务5 - 已过期签署截止日到期后触发7 - 已拒签签署方拒绝签署
return saveOrUpdateByMchMobile(esignContract);
}
/**
* 根据商家的注册手机号新增或更新签署合同记录
*
* @param esignContract
* @return
*/
public Boolean saveOrUpdateByMchMobile(EsignContract esignContract) {
if (esignContract == null || esignContract.getMch_mobile() == null) {
return false;
}
QueryWrapper<EsignContract> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mch_mobile", esignContract.getMch_mobile());
return saveOrUpdate(esignContract, queryWrapper);
}
/**
* 组织生成签署合同的请求参数
*
* @param shopMerchEntry
* @param esignPlatformInfo
* @param esignContractFillingFile
* @return
*/
protected String buildSignReqParams(ShopMerchEntry shopMerchEntry, EsignPlatformInfo esignPlatformInfo, EsignContractFillingFile esignContractFillingFile) {
if (shopMerchEntry == null || esignPlatformInfo == null || esignContractFillingFile == null) {
return "";
}
String fileId = esignContractFillingFile.getFile_id();
JSONObject reqParams = new JSONObject();
String contractName = esignContractFillingFile.getContract_name();
JSONArray docs = new JSONArray();
docs.add(new JSONObject().put("fileId", fileId).put("fileName", contractName + ".pdf"));
reqParams.put("docs", docs);
JSONObject signFlowConfig = new JSONObject();
signFlowConfig.put("signFlowTitle", contractName);
signFlowConfig.put("signFlowExpireTime", System.currentTimeMillis() + 90L * 24 * 60 * 60 * 1000); // 90天
signFlowConfig.put("autoFinish", true);
signFlowConfig.put("notifyUrl", main_domain + "/admin/shop/esign/asyn/notify");
signFlowConfig.putByPath("signFlowConfig.redirectUrl", "wechat://back");
reqParams.put("signFlowConfig", signFlowConfig);
// 签署双方信息
JSONArray signers = new JSONArray();
// 甲方商户信息
JSONObject mchSigner = new JSONObject();
mchSigner.putByPath("signConfig.signOrder", 1);
mchSigner.putByPath("noticeConfig.noticeTypes", "1");// 短信
mchSigner.putByPath("signFields", JSONUtil.parseArray(esignContractFillingFile.getMch_sign_position()));
if (shopMerchEntry.getEntity_type().equals(CommonConstant.MCH_ENTITY_TYPE_QY)) {
// 企业
mchSigner.put("signerType", 1);
mchSigner.putByPath("orgSignerInfo.orgName", shopMerchEntry.getBiz_license_company());
mchSigner.putByPath("orgSignerInfo.orgInfo.orgIDCardNum", shopMerchEntry.getBiz_license_number());
mchSigner.putByPath("orgSignerInfo.orgInfo.orgIDCardType", "CRED_ORG_USCC");
mchSigner.putByPath("orgSignerInfo.transactorInfo.psnAccount", shopMerchEntry.getLogin_mobile());
mchSigner.putByPath("orgSignerInfo.transactorInfo.psnInfo.psnName", shopMerchEntry.getLegal_person_name());
} else {
// 个人
mchSigner.put("signerType", 0);
mchSigner.putByPath("psnSignerInfo.psnAccount", shopMerchEntry.getLogin_mobile());
mchSigner.putByPath("psnSignerInfo.psnInfo.psnName", shopMerchEntry.getContact_name());
}
// 加入甲方信息
signers.add(mchSigner);
// 乙方平台方信息
JSONObject platSigner = new JSONObject();
platSigner.putByPath("signConfig.signOrder", 1);
platSigner.putByPath("noticeConfig.noticeTypes", "1,2"); // 短信和邮件
platSigner.putByPath("signFields", JSONUtil.parseArray(esignContractFillingFile.getPlat_sign_position()));
if (shopMerchEntry.getEntity_type().equals(CommonConstant.MCH_ENTITY_TYPE_QY)) {
// 企业
platSigner.put("signerType", 1);
platSigner.putByPath("orgSignerInfo.orgName", esignPlatformInfo.getLicense_company());
platSigner.putByPath("orgSignerInfo.orgInfo.orgIDCardNum", esignPlatformInfo.getLicense_number());
platSigner.putByPath("orgSignerInfo.orgInfo.orgIDCardType", "CRED_ORG_USCC");
platSigner.putByPath("orgSignerInfo.transactorInfo.psnAccount", esignPlatformInfo.getLegal_person_mobile());
platSigner.putByPath("orgSignerInfo.transactorInfo.psnInfo.psnName", esignPlatformInfo.getLegal_person_name());
} else {
// 个人
platSigner.put("signerType", 0);
platSigner.putByPath("psnSignerInfo.psnAccount", esignPlatformInfo.getLegal_person_mobile());
platSigner.putByPath("psnSignerInfo.psnInfo.psnName", shopMerchEntry.getLegal_person_name());
}
// 加入乙方平台方信息
signers.add(platSigner);
reqParams.put("signers", signers);
return reqParams.toString();
}
}

View File

@ -38,6 +38,8 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl<EsignPlatformI
queryWrapper.eq("status", CommonConstant.Enable);
if (!ObjectUtils.isEmpty(type)) {
queryWrapper.eq("type", type);
} else {
queryWrapper.eq("type", 0);
}
if (StrUtil.isNotBlank(licenseNumber)) {

View File

@ -37,6 +37,7 @@ public class ShopMerchEntryController extends BaseControllerImpl {
@Resource
private BaiduMapServiceImpl baiduMapService;
@ApiOperation(value = "测试", notes = "测试")
@RequestMapping(value = "/gencon", method = RequestMethod.POST)
public Object fillDocTemplate() {
@ -84,6 +85,7 @@ public class ShopMerchEntryController extends BaseControllerImpl {
ShopMerchEntry record = shopMerchEntryService.shopMerchEntryApprovalInfo(jsonParam.getStr("mobile"));
Map<String, Object> result = new HashMap<>();
if (record == null || record.getApproval_status() == null) {
// 配合前端的要求没有申请过入驻商城平台的时候返回未申请状态
result.put("id", 0L);
result.put("approval_status", 4);
result.put("approval_remark", "");

View File

@ -24,6 +24,8 @@ import com.suisung.mall.common.utils.StringUtils;
import com.suisung.mall.common.utils.phone.PhoneNumberUtils;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.base.service.AccountBaseConfigService;
import com.suisung.mall.shop.components.TaskService;
import com.suisung.mall.shop.esign.service.EsignContractFillingFileService;
import com.suisung.mall.shop.esign.service.EsignPlatformInfoService;
import com.suisung.mall.shop.message.service.ShopMessageTemplateService;
import com.suisung.mall.shop.store.mapper.ShopMerchEntryMapper;
@ -51,6 +53,13 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl<ShopMerchEntryMap
@Resource
private EsignPlatformInfoService esignPlatformInfoService;
@Resource
private EsignContractFillingFileService esignContractFillingFileService;
@Resource
private TaskService taskService;
/**
* 获取店铺的经营类目列表
*
@ -218,7 +227,6 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl<ShopMerchEntryMap
return CommonResult.failed("已经签署合同,不能再次申请!");
}
ShopMerchEntry record = JSONUtil.toBean(shopMerchEntryJSON, ShopMerchEntry.class);
if (record == null) {
log.error("###商家入驻参数转换失败###");
@ -371,10 +379,27 @@ public class ShopMerchEntryServiceImpl extends BaseServiceImpl<ShopMerchEntryMap
return CommonResult.failed("审批状态有误!");
}
ShopMerchEntry record = getById(id);
if (record == null) {
return CommonResult.failed("未找到入驻记录!");
}
// TODO 已经审核通过的不能再审核了
if (approvalStatus.equals(CommonConstant.Enable) && StrUtil.isBlank(approvalRemark)) {
// 审核通过
approvalRemark = "审核通过,后续将向您发起签署电子合同流程。";
// 多线程执行电子合同生成和填充
taskService.executeTask(() -> {
// 生成电子合同模版和填充模版数据并生该商家和平台方签署的未盖章合同文件
Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(record.getBiz_license_number(), "");
if (!genSuccess) {
log.error("###商家入驻电子合同生成失败###");
}
});
} else if (approvalStatus.equals(CommonConstant.Disable2) && StrUtil.isBlank(approvalRemark)) {
approvalRemark = "审核未通过,请继续完善入驻资料信息。";
}

View File

@ -116,6 +116,8 @@ logging:
io: error
reactor: error
springfox: error
# 项目主域名
main_domain: @project.domain@
# 个推
getui:
# Url前缀
@ -137,3 +139,20 @@ sf-express:
appkey: cd57608baa9c00fe1cda5f652b14240d
dev_id: 1711573316
enable: 2
#拉卡拉进件配置
lakala:
tk:
#服务地址
server_url: https://test.wsmsd.cn/sit/htkauth
client_id: lsycs
client_secret: XPa1HB5d55Ig0qV8
api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt
api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt
#e签宝配置
esign:
server_url: https://smlopenapi.esign.cn
#正式地址 https://openapi.esign.cn
app_id: 7439053575
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB
debug: true

View File

@ -116,6 +116,8 @@ logging:
io: error
reactor: error
springfox: error
# 项目主域名
main_domain: @project.domain@
# 个推
getui:
# Url前缀
@ -153,3 +155,4 @@ esign:
app_id: 7439053575
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB
debug: true

View File

@ -122,6 +122,8 @@ logging:
io: error
reactor: error
springfox: error
# 项目主域名
main_domain: @project.domain@
# 个推
getui:
# Url前缀
@ -161,4 +163,5 @@ esign:
#正式地址 https://openapi.esign.cn
app_id: 7439053575
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC
debug: false

View File

@ -120,6 +120,8 @@ logging:
io: error
reactor: error
springfox: error
# 项目主域名
main_domain: @project.domain@
# 个推
getui:
# Url前缀
@ -140,4 +142,21 @@ sf-express:
appid: 1711573316
appkey: cd57608baa9c00fe1cda5f652b14240d
dev_id: 1711573316
enable: 2
enable: 2
#拉卡拉进件配置
lakala:
tk:
#服务地址
server_url: https://test.wsmsd.cn/sit/htkauth
client_id: lsycs
client_secret: XPa1HB5d55Ig0qV8
api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt
api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt
#e签宝配置
esign:
server_url: https://smlopenapi.esign.cn
#正式地址 https://openapi.esign.cn
app_id: 7439053575
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB
debug: true

View File

@ -120,6 +120,8 @@ logging:
io: error
reactor: error
springfox: error
# 项目主域名
main_domain: @project.domain@
# 个推
getui:
# Url前缀
@ -140,4 +142,21 @@ sf-express:
appid: 1711573316
appkey: cd57608baa9c00fe1cda5f652b14240d
dev_id: 1711573316
enable: 2
enable: 2
#拉卡拉进件配置
lakala:
tk:
#服务地址
server_url: https://test.wsmsd.cn/sit/htkauth
client_id: lsycs
client_secret: XPa1HB5d55Ig0qV8
api_pub_key_path: payKey/lakala/dev/tk_api_public_key.txt
api_pri_key_path: payKey/lakala/dev/tk_api_private_key.txt
#e签宝配置
esign:
server_url: https://smlopenapi.esign.cn
#正式地址 https://openapi.esign.cn
app_id: 7439053575
app_secret: 8da2e1eeeaf88e09bcf432a2fdd3e4d7
app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC+fUc0+O9m45VEcGciJQ5QQNXs3NkHoHM2qDAdrXOnTwku0Be1IPeWUZ4s7w8xqubyirAAJDc3LpRkwCK84NicA2VwraD4on8MNtX8MLALZjLc1jZTmRAPKVfTKAcainR7ET78Y+QKJgezNvI7u45FO4Db+dWCC7pbedxBo+kHKA8im+/G0hpQaklxw1wjIMNv+x+YBnm8FOXRPWJZ+eItF5qJOT2C16QCY7hdeHknom+NMpZD8E/WAMtf03BcgigsoavTVnPI0xnN8BCrgykDWgO5bUXeIgNEF1LJS6r8s6BaMl+ZWbuODtbsrQ941GbFOe6x8tnhPIeehIa1AWQIDAQAB
debug: true