From 773d886aa603ca4bd5e51d251f3f38a2126e5d44 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 11 Mar 2025 17:01:31 +0800 Subject: [PATCH] =?UTF-8?q?e=E7=AD=BE=E5=AE=9D=E5=8F=91=E8=B5=B7=E7=AD=BE?= =?UTF-8?q?=E7=BD=B2=E6=B5=81=E7=A8=8B=EF=BC=8C=E5=A4=9A=E4=B8=AA=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/common/constant/CommonConstant.java | 4 + .../common/modules/esign/EsignContract.java | 27 +- .../esign/EsignContractFillingFile.java | 6 + .../mall/shop/components/TaskService.java | 51 ++++ .../EsignContractFillingFileService.java | 21 ++ .../esign/service/EsignContractService.java | 20 ++ .../EsignContractFillingFileServiceImpl.java | 152 +++++++++-- .../impl/EsignContractServiceImpl.java | 246 +++++++++++++++++- .../impl/EsignPlatformInfoServiceImpl.java | 2 + .../mobile/ShopMerchEntryController.java | 2 + .../impl/ShopMerchEntryServiceImpl.java | 27 +- .../src/main/resources/bootstrap-dev.yml | 19 ++ .../src/main/resources/bootstrap-local.yml | 3 + .../src/main/resources/bootstrap-prod.yml | 5 +- .../src/main/resources/bootstrap-test.yml | 21 +- .../src/main/resources/bootstrap-uat.yml | 21 +- 16 files changed, 595 insertions(+), 32 deletions(-) create mode 100644 mall-shop/src/main/java/com/suisung/mall/shop/components/TaskService.java diff --git a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java index a9aedeb8..2baae62b 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java +++ b/mall-common/src/main/java/com/suisung/mall/common/constant/CommonConstant.java @@ -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; } diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java index b4f7e357..741fdf42 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContract.java @@ -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; diff --git a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java index 045b1f12..7e2491be 100644 --- a/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java +++ b/mall-common/src/main/java/com/suisung/mall/common/modules/esign/EsignContractFillingFile.java @@ -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; diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/components/TaskService.java b/mall-shop/src/main/java/com/suisung/mall/shop/components/TaskService.java new file mode 100644 index 00000000..7bccc8c9 --- /dev/null +++ b/mall-shop/src/main/java/com/suisung/mall/shop/components/TaskService.java @@ -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; + *

+ * 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()); + * }; + *

+ * // 使用线程池执行任务 + * taskService.executeTask(task); + *

+ * 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); + } +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java index 0a10b95e..b74357c8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractFillingFileService.java @@ -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 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); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java index 9bcfeb9d..13966ccf 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/EsignContractService.java @@ -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); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java index 15196a91..1e9cf72f 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractFillingFileServiceImpl.java @@ -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 + * 后台管理员审核商家通过之后,触发调用这个方法,生成未签署合同文件,预备签署 * * @param mchLicenseNumber 入驻商家(甲方)的营业执照号 * @param platLicenseNumber 平台方(代理商方)(乙方)营业执照号 @@ -81,17 +94,15 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl() {{ put("componentKey", "plat_contracts"); - put("componentValue", "《平台商户入驻服务框架协议》和《小发同城服务费结算》"); + put("componentValue", "平台商户入驻服务框架协议和小发同城服务费结算"); }}); // 签署时间 @@ -245,9 +255,9 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl 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 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 0; } + /** + * 获取模版的甲方与乙方印章XY位置数据 + * + * @param docTemplateId + * @param fileId + * @return + */ + @Override + public Pair 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 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 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 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 queryWrapper = new QueryWrapper(); + queryWrapper.eq("mobile", mchMobile).eq("doc_template_id", templateId).eq("status", CommonConstant.Enable); + List list = list(queryWrapper); + if (CollectionUtil.isEmpty(list)) { + return null; + } + + return list.get(0); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java index eb0fe9c6..55eaacd7 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignContractServiceImpl.java @@ -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 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 服务器 + *

+ * 发起合同签署流程后,根据返回的流程Id 更改记录;收到完成签署异步通知之后,更改正式签署合同的地址 + * + * @param mchMobile 商家注册手机号 + * @param contractFileId 未签署合同文件Id + * @param signFlowId 合同签署流程ID(signFlowId和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 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 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(); + } } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java index d37503ef..93963837 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/service/impl/EsignPlatformInfoServiceImpl.java @@ -38,6 +38,8 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl result = new HashMap<>(); if (record == null || record.getApproval_status() == null) { + // 配合前端的要求,没有申请过入驻商城平台的时候,返回未申请状态 result.put("id", 0L); result.put("approval_status", 4); result.put("approval_remark", ""); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java index f6019da3..1b17c1b4 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMerchEntryServiceImpl.java @@ -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 { + // 生成电子合同模版和填充模版数据,并生该商家和平台方签署的未盖章合同文件 + Boolean genSuccess = esignContractFillingFileService.fillDocTemplate(record.getBiz_license_number(), ""); + if (!genSuccess) { + log.error("###商家入驻电子合同生成失败###"); + } + }); + + } else if (approvalStatus.equals(CommonConstant.Disable2) && StrUtil.isBlank(approvalRemark)) { approvalRemark = "审核未通过,请继续完善入驻资料信息。"; } diff --git a/mall-shop/src/main/resources/bootstrap-dev.yml b/mall-shop/src/main/resources/bootstrap-dev.yml index 8ce5a8c4..24364d7b 100644 --- a/mall-shop/src/main/resources/bootstrap-dev.yml +++ b/mall-shop/src/main/resources/bootstrap-dev.yml @@ -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 diff --git a/mall-shop/src/main/resources/bootstrap-local.yml b/mall-shop/src/main/resources/bootstrap-local.yml index bbd357d4..3a19a2d7 100644 --- a/mall-shop/src/main/resources/bootstrap-local.yml +++ b/mall-shop/src/main/resources/bootstrap-local.yml @@ -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 \ No newline at end of file diff --git a/mall-shop/src/main/resources/bootstrap-prod.yml b/mall-shop/src/main/resources/bootstrap-prod.yml index 824d9aa1..890b72d7 100644 --- a/mall-shop/src/main/resources/bootstrap-prod.yml +++ b/mall-shop/src/main/resources/bootstrap-prod.yml @@ -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 \ No newline at end of file + app_rsa: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiC + debug: false \ No newline at end of file diff --git a/mall-shop/src/main/resources/bootstrap-test.yml b/mall-shop/src/main/resources/bootstrap-test.yml index 3409fbac..5b3c59a3 100644 --- a/mall-shop/src/main/resources/bootstrap-test.yml +++ b/mall-shop/src/main/resources/bootstrap-test.yml @@ -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/mall-shop/src/main/resources/bootstrap-uat.yml b/mall-shop/src/main/resources/bootstrap-uat.yml index 3409fbac..5b3c59a3 100644 --- a/mall-shop/src/main/resources/bootstrap-uat.yml +++ b/mall-shop/src/main/resources/bootstrap-uat.yml @@ -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 \ No newline at end of file + 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 \ No newline at end of file