取消订单,同时也要取消顺丰同城的配送订单

This commit is contained in:
Jack 2025-12-01 17:35:52 +08:00
parent dcaf638b58
commit 2ea022091c
13 changed files with 745 additions and 497 deletions

View File

@ -50,7 +50,7 @@ public class EsignController extends BaseControllerImpl {
@ApiOperation(value = "管理员发起签署电子合同流程", notes = "基于文件发起签署电子合同")
@RequestMapping(value = "/sign-flow/create-by-file", method = RequestMethod.POST)
public CommonResult signFlowCreateByFile(@RequestBody JSONObject paramsJSON) {
return esignContractService.signFlowCreateByFile(paramsJSON.getStr("mchMobile"));
return esignContractService.signFlowCreateByFile(paramsJSON.getInt("store_id"));
}
@ApiOperation(value = "签署电子合同流程通知接收", notes = "签署电子合同流程通知接收")
@ -62,6 +62,6 @@ public class EsignController extends BaseControllerImpl {
@ApiOperation(value = "查看已签署的电子合同文件", notes = "管理员查看已签署的电子合同文件")
@RequestMapping(value = "/signed/contract/file", method = RequestMethod.POST)
public CommonResult getSignedContactFile(@RequestBody JSONObject paramsJSON) {
return esignContractService.getSignedContactFile(paramsJSON.getStr("mchMobile"));
return esignContractService.getSignedContactFile(paramsJSON.getInt("store_id"));
}
}

View File

@ -18,11 +18,10 @@ public interface EsignContractFillingFileService {
/**
* 填充合同模版生成合同文件地址
*
* @param mchMobile 入驻商家注册手机号
* @param platLicenseNumber 平台方代理商方营业执照号
* @param storeId 入驻成功商家的店铺Id
* @return
*/
Boolean fillDocTemplate(String mchMobile, String platLicenseNumber);
Boolean fillDocTemplate(Integer storeId);
/**
* 获取模版的甲方与乙方印章XY位置数据

View File

@ -21,18 +21,18 @@ public interface EsignContractService {
/**
* 根据商家注册手机号发起合同签署流程
*
* @param mchMobile
* @param storeId
* @return
*/
CommonResult signFlowCreateByFile(String mchMobile);
CommonResult signFlowCreateByFile(Integer storeId);
/**
* 内部调用发起合同签署流程
*
* @param mchMobile
* @param storeId
* @return
*/
Pair<Boolean, String> innerSignFlowCreateByFile(String mchMobile);
Pair<Boolean, String> innerSignFlowCreateByFile(Integer storeId);
/**
* 签署流程结束异步通知由e签宝通知
@ -44,10 +44,10 @@ public interface EsignContractService {
/**
* 管理员查看已签署的电子合同文件
*
* @param mchMobile
* @param storeId
* @return
*/
CommonResult getSignedContactFile(String mchMobile);
CommonResult getSignedContactFile(Integer storeId);
/**
* 更新合同流程ID和文件地址和状态
@ -131,4 +131,20 @@ public interface EsignContractService {
* @return
*/
Boolean updateContractStoreId(String mchMobile, Integer storeId);
/**
* 根据店铺Id获取一条合同信息
*
* @param storeId
* @return
*/
EsignContract getEsignContractByStoreId(Integer storeId);
/**
* 根据店铺Id获取合同状态和下载地址
*
* @param storeId
* @return
*/
EsignContract getEsignContractStatusUrl(Integer storeId);
}

View File

@ -9,6 +9,7 @@
package com.suisung.mall.shop.esign.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
@ -21,6 +22,8 @@ import com.suisung.mall.common.constant.CommonConstant;
import com.suisung.mall.common.modules.esign.EsignContractFillingFile;
import com.suisung.mall.common.modules.esign.EsignPlatformInfo;
import com.suisung.mall.common.modules.store.ShopMchEntry;
import com.suisung.mall.common.modules.store.ShopStoreBase;
import com.suisung.mall.common.utils.CheckUtil;
import com.suisung.mall.common.utils.StringUtils;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.esign.mapper.EsignContractFillingFileMapper;
@ -33,6 +36,7 @@ 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.ShopMchEntryService;
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
@ -41,6 +45,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@ -79,6 +84,10 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
@Resource
private EsignContractService esignContractService;
@Lazy
@Resource
private ShopStoreBaseService shopStoreBaseService;
@Resource
private OssService ossService;
@ -86,112 +95,134 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
/**
* 根据双方营业执照号码(或个人身份证)填充合同模版生成合同文件地址
* <p>
* 后台管理员审核商家通过之后触发调用这个方法生成未签署合同文件预备签署
* 拉卡拉审核通过之后触发调用这个方法生成未签署合同文件预备签署
*
* @param mchMobile 入驻商家(甲方)的注册手机号
* @param platLicenseNumber 平台方代理商方乙方营业执照号
* @return
* @param storeId 入驻成功商家的店铺Id
* @return Boolean 是否成功生成合同文件
*/
@Override
public Boolean fillDocTemplate(String mchMobile, String platLicenseNumber) {
if (StrUtil.isEmpty(mchMobile)) {
log.error("商家手机号为空");
public Boolean fillDocTemplate(Integer storeId) {
// 1. 参数校验
if (CheckUtil.isEmpty(storeId)) {
log.error("商家店铺Id为空");
return false;
}
// 获取平台方信息
EsignPlatformInfo esignPlatformInfo = esignPlatformInfoService.getEsignPlatformInfo(0, platLicenseNumber);
// 2. 获取平台方信息
EsignPlatformInfo esignPlatformInfo = esignPlatformInfoService.getEsignPlatformInfo(0, "");
if (ObjectUtils.isEmpty(esignPlatformInfo)) {
log.error("请添加平台方(代理商方)信息");
return null;
return false;
}
// 获取入驻商家(审批通过的)的信息
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByCondition(mchMobile, "", CommonConstant.MCH_APPR_STA_PASS);
// 3. 获取入驻商家(审批通过的)的信息
ShopMchEntry shopMchEntry = shopMchEntryService.getShopMerchEntryByStoreId(storeId);
if (shopMchEntry == null) {
log.error("缺少商家入驻信息");
return null;
log.error("缺少商家入驻信息, storeId: {}", storeId);
return false;
}
// 代理商信息
// 4. 检查商家审批状态
if (!CommonConstant.MCH_APPR_STA_PASS.equals(shopMchEntry.getApproval_status())) {
log.error("入驻商家审批未通过,当前状态: {}, storeId: {}", shopMchEntry.getApproval_status(), storeId);
return false;
}
ShopStoreBase shopStoreBase = shopStoreBaseService.getShopStoreBaseByStoreId(storeId);
if (ObjectUtils.isEmpty(shopStoreBase)) {
log.error("缺少商家店铺信息, storeId: {}", storeId);
return false;
}
BigDecimal splitRatio = shopStoreBase.getSplit_ratio();
if (CheckUtil.isEmpty(splitRatio)) {
log.error("缺少商家店铺分账比例,从入驻申请数据获取分账比例, storeId: {}", storeId);
splitRatio = shopMchEntry.getSplit_ratio();
}
// 5. 获取代理商信息
EsignPlatformInfo distributor = esignPlatformInfoService.getDistributorInfoById(shopMchEntry.getDistributor_id());
String apiaddr = "/v3/files/create-by-doc-template";
String apiAddr = "/v3/files/create-by-doc-template";
EsignRequestType requestType = EsignRequestType.POST;
// 获取平台方代理商方合同模版信息
// 6. 获取平台方合同模版信息
JSONArray templates = JSONUtil.parseArray(esignPlatformInfo.getDoc_template());
if (ObjectUtils.isEmpty(templates) || templates.size() <= 0) {
if (templates == null || templates.isEmpty()) {
log.error("缺少平台方(代理商方)合同模版信息");
return null;
return false;
}
// 7. 准备基础数据
String today = DateUtil.format(new Date(), "yyyy年MM月dd日");
// 甲方公司名称甲方是个人的时候没有公司名直接用店铺名个人实名
String mchCompany = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()) ? shopMchEntry.getBiz_license_company() : shopMchEntry.getStore_name() + "" + shopMchEntry.getContact_name() + ")";
String mchCompany = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type())
? shopMchEntry.getBiz_license_company()
: shopMchEntry.getStore_name() + "" + shopMchEntry.getContact_name() + ")";
String platCompany = esignPlatformInfo.getLicense_company();
// 甲方法人姓名甲方是个人的时候没有法人直接用个人实名
String legalPersonName = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()) ? shopMchEntry.getLegal_person_name() : shopMchEntry.getContact_name();
String LegalPersonMobile = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()) ? shopMchEntry.getLegal_person_mobile() : shopMchEntry.getLogin_mobile();
String legalPersonName = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type())
? shopMchEntry.getLegal_person_name()
: shopMchEntry.getContact_name();
String legalPersonMobile = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type())
? shopMchEntry.getLegal_person_mobile()
: shopMchEntry.getLogin_mobile();
// 甲方法人身份证号甲方是个人的时候没有法人直接用个人身份证
String legalPersonIdNumber = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()) ? shopMchEntry.getLegal_person_id_number() : shopMchEntry.getIndividual_id_number();
String legalPersonIdNumber = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type())
? shopMchEntry.getLegal_person_id_number()
: shopMchEntry.getIndividual_id_number();
String contractNumber = StringUtils.genLklOrderNo(4);
int successCnt = 0;
// 模版文件里有三份合同顺序排列的: 1.平台商户入驻服务框架协议 2.小发同城服务费结算 3.结算授权委托书
log.info("开始为商家生成合同文件, storeId: {}, mobile: {}", storeId, shopMchEntry.getLogin_mobile());
// 8. 遍历模版文件生成合同模版文件里有三份合同顺序排列的: 1.平台商户入驻服务框架协议 2.小发同城服务费结算 3.结算授权委托书
for (JSONObject template : templates.jsonIter()) {
// 从商家信息里获取模版的信息
String templateId = template.getStr("template_id");
String fileName = template.getStr("template_name");
int seq = template.getInt("seq");
try {
// 从商家信息里获取模版的信息
String templateId = template.getStr("template_id");
String fileName = template.getStr("template_name");
int seq = template.getInt("seq");
// 获取填充模版的数据
JSONObject fillJson = new JSONObject();
fillJson.put("docTemplateId", templateId)
.put("fileName", fileName);
log.debug("处理合同模版: templateId={}, fileName={}, seq={}", templateId, fileName, seq);
// 9. 构建填充模版的数据
JSONObject fillJson = new JSONObject();
fillJson.put("docTemplateId", templateId)
.put("fileName", fileName);
JSONArray list = new JSONArray();
EsignPlatformInfo finalEsignPlatformInfo = esignPlatformInfo;
JSONArray list = new JSONArray();
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_contracts");
put("componentValue", "《平台商户入驻服务框架协议》和《小发同城服务费结算》");
}});
// 签署时间
for (int i = 1; i <= 3; i++) {
int finalI = i;
// 10. 填充合同组件数据
// 平台合同名称
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_sign_date" + finalI);
put("componentValue", today);
put("componentKey", "plat_contracts");
put("componentValue", "《平台商户入驻服务框架协议》和《小发同城服务费结算》");
}});
}
for (int i = 1; i <= 3; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_sign_date" + finalI);
put("componentValue", today);
}});
}
if (CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type())) {
// 甲方公司名称甲方是个人的时候没有公司名直接用店铺名
for (int i = 1; i <= 17; i++) {
// 签署时间甲方
for (int i = 1; i <= 3; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_company" + finalI);
put("componentValue", mchCompany);
put("componentKey", "mch_sign_date" + finalI);
put("componentValue", today);
}});
}
} else {
// 甲方公司名称甲方是个人的时候没有公司名直接用店铺名
for (int i = 1; i <= 16; i++) {
// 签署时间乙方
for (int i = 1; i <= 3; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_sign_date" + finalI);
put("componentValue", today);
}});
}
// 甲方公司名称
int mchCompanyCount = CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type()) ? 17 : 16;
for (int i = 1; i <= mchCompanyCount; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_company" + finalI);
@ -199,233 +230,239 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
}});
}
//特殊甲方收款账方企业是公司名个人是个人实名
// 特殊处理甲方收款账户方企业是公司名个人是个人实名
if (!CommonConstant.MCH_ENTITY_TYPE_QY.equals(shopMchEntry.getEntity_type())) {
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_company17");
put("componentValue", shopMchEntry.getContact_name());
}});
}
}
// 甲方法人姓名甲方是个人的时候没有法人直接用个人实名
for (int i = 1; i <= 4; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_legal_person_name" + finalI);
put("componentValue", legalPersonName);
}});
}
// 甲方法人手机号
for (int i = 1; i <= 3; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_legal_person_mobile" + finalI);
put("componentValue", LegalPersonMobile);
}});
}
// 甲方身份证号码
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_legal_person_id_number1");
put("componentValue", legalPersonIdNumber);
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_store_name1");
put("componentValue", shopMchEntry.getStore_name());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "rule_no");
put("componentValue", 3);
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_ratio");
put("componentValue", shopMchEntry.getSplit_ratio());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "settlement_method");
put("componentValue", shopMchEntry.getSettlement_method());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_address1");
put("componentValue", shopMchEntry.getStore_address());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_bank1");
put("componentValue", shopMchEntry.getBank_name());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_account_number1");
put("componentValue", shopMchEntry.getAccount_number());
}});
// 乙方公司名称
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_company1");
put("componentValue", platCompany + "和代理商");
}});
for (int i = 2; i <= 5; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_company" + finalI);
put("componentValue", platCompany);
}});
}
for (int i = 1; i <= 2; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_mobile" + finalI);
put("componentValue", finalEsignPlatformInfo.getLegal_person_mobile());
}});
}
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", finalEsignPlatformInfo.getEmail());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", finalEsignPlatformInfo.getEmail());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", finalEsignPlatformInfo.getEmail());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", finalEsignPlatformInfo.getEmail());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", finalEsignPlatformInfo.getEmail());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", finalEsignPlatformInfo.getEmail());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_bank1");
put("componentValue", finalEsignPlatformInfo.getRec_acc_bank_name());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_account_number1");
put("componentValue", finalEsignPlatformInfo.getRec_acc_card_no());
}});
// 代理商相关
if (distributor != null) {
// 有代理商的时候才填充代理商的信息
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company1");
put("componentValue", distributor.getLicense_company());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_mobile1");
put("componentValue", distributor.getLegal_person_mobile());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company2");
put("componentValue", distributor.getLicense_company());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_bank1");
put("componentValue", distributor.getRec_acc_bank_name());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_account_number1");
put("componentValue", distributor.getRec_acc_card_no());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_sign_date1");
put("componentValue", today);
}});
} else {
// 有代理商的时候才填充代理商的信息
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company1");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_mobile1");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company2");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_bank1");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_account_number1");
put("componentValue", "");
}});
}
fillJson.put("components", list);
String jsonParma = fillJson.toString();
//生成签名鉴权方式的的header
Map<String, String> header = null;
try {
header = EsignHttpHelper.signAndBuildSignAndJsonHeader(appId, appSecret, jsonParma, requestType.name(), apiaddr, debug);
//发起接口请求
EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(serverUrl, apiaddr, requestType, jsonParma, header, debug);
log.info("合同生成数据:{}", createByDocTemplate);
if (createByDocTemplate.getStatus() != 200) {
return false;
// 甲方法人姓名
for (int i = 1; i <= 4; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_legal_person_name" + finalI);
put("componentValue", legalPersonName);
}});
}
EsignContractFillingFile esignContractFillingFile = new EsignContractFillingFile();
// 甲方法人手机号
for (int i = 1; i <= 3; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_legal_person_mobile" + finalI);
put("componentValue", legalPersonMobile);
}});
}
// 甲方身份证号码
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_legal_person_id_number1");
put("componentValue", legalPersonIdNumber);
}});
// 甲方店铺名称
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_store_name1");
put("componentValue", shopMchEntry.getStore_name());
}});
// 规则编号
list.add(new HashMap<String, Object>() {{
put("componentKey", "rule_no");
put("componentValue", 3);
}});
// 分账比例
BigDecimal finalSplitRatio = splitRatio;
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_ratio");
put("componentValue", finalSplitRatio);
}});
// 结算方式
list.add(new HashMap<String, Object>() {{
put("componentKey", "settlement_method");
put("componentValue", shopMchEntry.getSettlement_method());
}});
// 甲方地址
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_address1");
put("componentValue", shopMchEntry.getStore_address());
}});
// 甲方银行
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_bank1");
put("componentValue", shopMchEntry.getBank_name());
}});
// 甲方账户号
list.add(new HashMap<String, Object>() {{
put("componentKey", "mch_account_number1");
put("componentValue", shopMchEntry.getAccount_number());
}});
// 乙方公司名称
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_company1");
put("componentValue", platCompany + "和代理商");
}});
// 其他乙方公司名称
for (int i = 2; i <= 5; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_company" + finalI);
put("componentValue", platCompany);
}});
}
// 乙方手机号
for (int i = 1; i <= 2; i++) {
int finalI = i;
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_mobile" + finalI);
put("componentValue", esignPlatformInfo.getLegal_person_mobile());
}});
}
// 乙方邮箱重复填充但保持原逻辑
for (int i = 0; i < 6; i++) {
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_email1");
put("componentValue", esignPlatformInfo.getEmail());
}});
}
// 乙方银行
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_bank1");
put("componentValue", esignPlatformInfo.getRec_acc_bank_name());
}});
// 乙方账户号
list.add(new HashMap<String, Object>() {{
put("componentKey", "plat_account_number1");
put("componentValue", esignPlatformInfo.getRec_acc_card_no());
}});
// 11. 处理代理商相关数据
if (distributor != null) {
// 有代理商的时候填充代理商的信息
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company1");
put("componentValue", distributor.getLicense_company());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_mobile1");
put("componentValue", distributor.getLegal_person_mobile());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company2");
put("componentValue", distributor.getLicense_company());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_bank1");
put("componentValue", distributor.getRec_acc_bank_name());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_account_number1");
put("componentValue", distributor.getRec_acc_card_no());
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_sign_date1");
put("componentValue", today);
}});
log.debug("已填充代理商信息: {}", distributor.getLicense_company());
} else {
// 无代理商时填充默认值
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company1");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_mobile1");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_company2");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_bank1");
put("componentValue", "");
}});
list.add(new HashMap<String, Object>() {{
put("componentKey", "distr_account_number1");
put("componentValue", "");
}});
log.debug("未配置代理商信息,使用默认值");
}
fillJson.put("components", list);
String jsonParam = fillJson.toString();
// 12. 调用e签宝API生成合同文件
Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(
appId, appSecret, jsonParam, requestType.name(), apiAddr, debug);
// 发起接口请求
EsignHttpResponse createByDocTemplate = EsignHttpHelper.doCommHttp(
serverUrl, apiAddr, requestType, jsonParam, header, debug);
log.info("合同生成API调用结果: status={}, body={}",
createByDocTemplate.getStatus(), createByDocTemplate.getBody());
if (createByDocTemplate.getStatus() != 200) {
log.error("调用e签宝生成合同文件接口失败, status: {}", createByDocTemplate.getStatus());
continue; // 继续处理下一个模版
}
// 13. 解析API返回结果
JSONObject jsonObject = JSONUtil.parseObj(createByDocTemplate.getBody()).getJSONObject("data");
esignContractFillingFile.setUnsigned_contract_url(jsonObject.getStr("fileDownloadUrl"));
String fileDownloadUrl = jsonObject.getStr("fileDownloadUrl");
String fileId = jsonObject.getStr("fileId");
// 把合同文件 url 上传到cos服务器
// String contractPath = StrUtil.isBlank(shopMchEntry.getBiz_license_number()) ? mchMobile : shopMchEntry.getBiz_license_number();
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/").concat("contract")
.concat("/").concat(shopMchEntry.getLogin_mobile()).concat("/")
.concat(jsonObject.getStr("fileId")).concat(".pdf");
// 上传到cos服务器
String localFileUrl = ossService.uploadObject4OSS(esignContractFillingFile.getUnsigned_contract_url(), cosFileName);
esignContractFillingFile.setUnsigned_contract_local_url(localFileUrl);
if (StrUtil.isBlank(fileDownloadUrl) || StrUtil.isBlank(fileId)) {
log.error("e签宝返回的合同文件信息不完整, fileDownloadUrl: {}, fileId: {}", fileDownloadUrl, fileId);
continue;
}
// 14. 创建合同填充文件记录
EsignContractFillingFile esignContractFillingFile = new EsignContractFillingFile();
esignContractFillingFile.setUnsigned_contract_url(fileDownloadUrl);
esignContractFillingFile.setFile_id(fileId);
// 15. 上传合同文件到OSS
String cosFileName = TENGXUN_DEFAULT_DIR.concat("/contract/")
.concat(shopMchEntry.getLogin_mobile()).concat("/")
.concat(fileId).concat(".pdf");
String localFileUrl = ossService.uploadObject4OSS(fileDownloadUrl, cosFileName);
if (StrUtil.isBlank(localFileUrl)) {
log.error("上传合同文件到OSS失败, fileId: {}", fileId);
continue;
}
esignContractFillingFile.setUnsigned_contract_local_url(localFileUrl);
esignContractFillingFile.setDoc_template_id(templateId);
esignContractFillingFile.setContract_number(contractNumber + seq);
esignContractFillingFile.setContract_name("商户入驻小发同城平台合同协议");
esignContractFillingFile.setStore_id(contractNumber);
esignContractFillingFile.setMobile(mchMobile);
esignContractFillingFile.setDoc_template_filling_values(jsonParma);
esignContractFillingFile.setStore_id(Convert.toStr(storeId));
esignContractFillingFile.setMobile(shopMchEntry.getLogin_mobile());
esignContractFillingFile.setDoc_template_filling_values(jsonParam);
esignContractFillingFile.setSeq(seq);
esignContractFillingFile.setStatus(CommonConstant.Enable);
// 获取印章的位置信息写入数据库
// 16. 获取印章位置信息
Map<String, JSONArray> signPositionMap = getSignPosition(templateId, fileId);
if (signPositionMap != null) {
if (signPositionMap.get("mch") != null) {
@ -441,22 +478,34 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl<EsignCo
}
}
// 17. 保存合同填充记录并预创建签署流程
if (esignContractFillingFileService.trySaveRecord(esignContractFillingFile)) {
successCnt += 1;
log.debug("合同填充记录保存成功, fileId: {}", fileId);
// 预新增一个签署合同记录(要不要异步执行)
esignContractService.preCreateSignFlow(esignContractFillingFile.getMobile(), esignContractFillingFile.getDoc_template_id());
// 预新增一个签署合同记录
boolean preCreateResult = esignContractService.preCreateSignFlow(
esignContractFillingFile.getMobile(), esignContractFillingFile.getDoc_template_id());
log.debug("预创建签署流程结果: {}, mobile: {}, templateId: {}",
preCreateResult, esignContractFillingFile.getMobile(), esignContractFillingFile.getDoc_template_id());
} else {
log.error("保存合同填充记录失败, fileId: {}", fileId);
}
} catch (EsignDemoException e) {
throw new RuntimeException(e);
} catch (Exception e) {
log.error("处理合同模版时发生异常, templateId: {}", template.getStr("template_id"), e);
// 继续处理下一个模版不中断整个流程
}
}
return successCnt > 0;
boolean result = successCnt > 0;
log.info("合同文件生成完成, storeId: {}, 总模版数: {}, 成功处理数: {}, 结果: {}",
storeId, templates.size(), successCnt, result);
return result;
}
/**
* 获取模版的甲方与乙方印章XY位置数据
*

View File

@ -14,6 +14,7 @@ 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.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.suisung.mall.common.api.CommonResult;
@ -22,6 +23,7 @@ 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.store.ShopMchEntry;
import com.suisung.mall.common.utils.CheckUtil;
import com.suisung.mall.core.web.service.impl.BaseServiceImpl;
import com.suisung.mall.shop.components.TaskService;
import com.suisung.mall.shop.esign.mapper.EsignContractMapper;
@ -32,11 +34,8 @@ 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.exception.EsignDemoException;
import com.suisung.mall.shop.lakala.service.LakalaApiService;
import com.suisung.mall.shop.lakala.service.LklLedgerMemberService;
import com.suisung.mall.shop.page.service.OssService;
import com.suisung.mall.shop.store.service.ShopMchEntryService;
import com.suisung.mall.shop.store.service.ShopStoreBaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
@ -91,18 +90,6 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
@Resource
private EsignPlatformInfoService esignPlatformInfoService;
@Resource
private ShopStoreBaseService shopStoreBaseService;
@Lazy
@Resource
private LakalaApiService lakalaApiService;
@Lazy
@Resource
private LklLedgerMemberService lklLedgerMemberService;
@Resource
private OssService ossService;
@ -169,8 +156,8 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
* @return
*/
@Override
public CommonResult signFlowCreateByFile(String mchMobile) {
Pair<Boolean, String> ret = innerSignFlowCreateByFile(mchMobile);
public CommonResult signFlowCreateByFile(Integer storeId) {
Pair<Boolean, String> ret = innerSignFlowCreateByFile(storeId);
if (!ret.getFirst()) {
return CommonResult.failed(ret.getSecond());
}
@ -179,21 +166,25 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
}
@Override
public Pair<Boolean, String> innerSignFlowCreateByFile(String mchMobile) {
//String userId = "0";
if (StrUtil.isBlank(mchMobile)) {
public Pair<Boolean, String> innerSignFlowCreateByFile(Integer storeId) {
if (CheckUtil.isEmpty(storeId)) {
return Pair.of(false, "缺少必要参数!");
}
EsignContract esignContract = getEsignContractByMchMobile(mchMobile);
// 组织和填充商家店铺的模版数据
Boolean isFill = esignContractFillingFileService.fillDocTemplate(storeId);
if (!isFill) {
return Pair.of(false, "合同信息未准备好,请检查商家入驻手续是否已完成!");
}
EsignContract esignContract = getEsignContractByStoreId(storeId);
if (esignContract == null) {
return Pair.of(false, "未找到商家合同信息");
}
// 检查商户入驻信息是否被审核通过
// 检查店铺是否已经申请过入驻
Integer apprStatus = shopMchEntryService.getApprovalStatus(mchMobile);
Integer apprStatus = shopMchEntryService.getApprovalStatus(esignContract.getMch_mobile());
if (!CommonConstant.MCH_APPR_STA_PASS.equals(apprStatus)) {
return Pair.of(false, "请先审核商家入驻信息");
}
@ -254,108 +245,168 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
log.debug("签署流程结束通知:body >>> {}", requestBody);
log.debug("签署流程结束通知:header >>> {}", request.getParameterMap());
//异步通知获取到的header头中的签名值X-Tsign-Open-App-Id
// 1. 验证请求头参数完整性
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 signature = request.getHeader("X-Tsign-Open-SIGNATURE");
String timestamp = request.getHeader("X-Tsign-Open-TIMESTAMP");
if (StrUtil.isBlank(reqAppId) || StrUtil.isBlank(signture) || StrUtil.isBlank(timestamp)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new JSONObject().put("code", 400).put("msg", "缺少必要参数").toString());
if (StrUtil.isBlank(reqAppId) || StrUtil.isBlank(signature) || StrUtil.isBlank(timestamp)) {
log.warn("e签宝异步通知缺少必要参数: reqAppId={}, signature={}, timestamp={}", reqAppId, signature, timestamp);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "缺少必要参数").toString());
}
// 2. 验证AppId是否匹配
if (!reqAppId.equals(appId)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new JSONObject().put("code", 400).put("msg", "appId 有误").toString());
log.warn("e签宝异步通知AppId不匹配: 请求AppId={}, 配置AppId={}", reqAppId, appId);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "appId 有误").toString());
}
//按照规则进行加密
// 3. 验证签名
String signData = timestamp + requestBody;
String mySignature = getSignature(signData, appSecret, "HmacSHA256", "UTF-8");
log.debug("加密出来的签名值:----------->>>>>>" + mySignature);
log.debug("header里面的签名值---------->>>>>>" + signture);
if (!mySignature.equals(signture)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new JSONObject().put("code", 400).put("msg", "签名校验失败").toString());
// 签名生成失败处理
if (mySignature == null) {
log.error("生成签名失败signData: {}", signData);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "签名生成失败").toString());
}
log.debug("加密出来的签名值:----------->>>>>> {}", mySignature);
log.debug("header里面的签名值---------->>>>>> {}", signature);
if (!mySignature.equals(signature)) {
log.warn("e签宝异步通知签名校验失败: 计算签名={}, 请求签名={}", mySignature, signature);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "签名校验失败").toString());
}
// 4. 解析请求体数据
JSONObject reqBodyJSON;
try {
reqBodyJSON = JSONUtil.parseObj(requestBody);
} catch (Exception e) {
log.error("解析e签宝异步通知请求体失败: requestBody={}", requestBody, e);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "请求体格式错误").toString());
}
// 处理业务逻辑
JSONObject reqBodyJSON = JSONUtil.parseObj(requestBody);
String action = reqBodyJSON.getStr("action");
String signFlowId = reqBodyJSON.getStr("signFlowId");
Integer signResult = reqBodyJSON.getInt("signResult");
if (StrUtil.isBlank(action) || StrUtil.isBlank(signFlowId)) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new JSONObject().put("code", 400).put("msg", "返回数据有误").toString());
log.warn("e签宝异步通知缺少必要业务参数: action={}, signFlowId={}", action, signFlowId);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "返回数据有误").toString());
}
// 获取合同签署记录
EsignContract esignContract = baseMapper.selectOne(new QueryWrapper<EsignContract>().eq("sign_flow_id", signFlowId));
if (esignContract == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new JSONObject().put("code", 400).put("msg", "获取不到合同记录").toString());
// 5. 获取合同签署记录
EsignContract esignContract;
try {
esignContract = baseMapper.selectOne(new QueryWrapper<EsignContract>().eq("sign_flow_id", signFlowId));
if (esignContract == null) {
log.warn("未找到对应的合同记录: signFlowId={}", signFlowId);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "获取不到合同记录").toString());
}
} catch (Exception e) {
log.error("查询合同记录异常: signFlowId={}", signFlowId, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new JSONObject().put("code", 500).put("msg", "查询合同记录异常").toString());
}
log.debug("签署流程结束通知:action >>> {}", action);
if (CommonConstant.CONTRACT_SIGN_STA_FINISH.equals(esignContract.getSign_flow_status()) && StrUtil.isNotEmpty(esignContract.getLocal_contract_url())) {
// 已经签署完毕不用在更改状态
// 6. 如果合同已经完成且已有本地文件URL则直接返回成功
if (CommonConstant.CONTRACT_SIGN_STA_FINISH.equals(esignContract.getSign_flow_status())
&& StrUtil.isNotEmpty(esignContract.getLocal_contract_url())) {
log.debug("合同已处理完成,无需重复处理: signFlowId={}", signFlowId);
return ResponseEntity.ok(new JSONObject().put("code", 200).put("msg", "success").toString());
}
// 获取正式盖章合同文件上传到 oss 服务器更状态,保存数据
if (action.equals("SIGN_FLOW_COMPLETE")) {// 签署流程完毕
log.debug("签署流程完毕,开始处理业务逻辑");
// 获取正式盖章合同文件地址
String downloadUrl = getSignedContractFileUrl(signFlowId);
// 7. 根据不同动作类型处理业务逻辑
try {
// 签署流程完毕
if ("SIGN_FLOW_COMPLETE".equals(action)) {
log.debug("签署流程完毕,开始处理业务逻辑: signFlowId={}", signFlowId);
// 更新合同流程状态和文件地址
boolean success = updateContractFlowStatusAndFileUrlBySignFlowId(signFlowId, CommonConstant.CONTRACT_SIGN_STA_FINISH, downloadUrl);
if (success && StrUtil.isNotBlank(downloadUrl)) {
// 1电子合同给商家申请分账功能使用务必检查是否申请过申请过忽略
Pair<Boolean, String> retPair = lakalaApiService.innerApplyLedgerMer("", false);
if (!retPair.getFirst()) {
log.error("商家申请分账业务异常:{}", retPair.getSecond());
// 获取正式盖章合同文件地址
String downloadUrl = getSignedContractFileUrl(signFlowId);
if (StrUtil.isBlank(downloadUrl)) {
log.warn("获取签署完成的合同文件URL失败: signFlowId={}", signFlowId);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new JSONObject().put("code", 500).put("msg", "获取合同文件失败").toString());
}
// TODO mchId 必填字段更新商家的hasEsigned状态=1
shopMchEntryService.updateMulStatus(0L, "", 1, 0, 0, 0, 0, 0, CommonConstant.MCH_APPR_STA_LKL_PADDING);
// 更新合同流程状态和文件地址
boolean success = updateContractFlowStatusAndFileUrlBySignFlowId(
signFlowId,
CommonConstant.CONTRACT_SIGN_STA_FINISH,
downloadUrl);
if (success) {
log.info("合同签署完成处理成功: signFlowId={}", signFlowId);
return ResponseEntity.ok(new JSONObject().put("code", 200).put("msg", "success").toString());
} else {
log.error("更新合同流程状态失败: signFlowId={}", signFlowId);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new JSONObject().put("code", 500).put("msg", "更新合同状态失败").toString());
}
}
// 签署方签署结果通知含拒签
else if ("SIGN_MISSON_COMPLETE".equals(action) && ObjectUtil.isNotEmpty(signResult)) {
Integer signFlowStatus = null;
// 根据签署结果确定合同状态
if (Integer.valueOf(2).equals(signResult)) {
signFlowStatus = CommonConstant.CONTRACT_SIGN_STA_PARTIALLY;
} else if (Integer.valueOf(4).equals(signResult)) {
signFlowStatus = CommonConstant.CONTRACT_SIGN_STA_REJECT;
}
if (signFlowStatus == null) {
log.warn("未知的签署结果类型: signResult={}", signResult);
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new JSONObject().put("code", 400).put("msg", "未知的签署结果").toString());
}
// 更新合同流程状态
boolean success = updateContractFlowStatusAndFileUrlBySignFlowId(signFlowId, signFlowStatus, "");
if (success) {
log.info("签署任务完成处理成功: signFlowId={}, signResult={}, status={}",
signFlowId, signResult, signFlowStatus);
return ResponseEntity.ok(new JSONObject().put("code", 200).put("msg", "success").toString());
} else {
log.error("更新合同流程状态失败: signFlowId={}, signResult={}", signFlowId, signResult);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new JSONObject().put("code", 500).put("msg", "更新合同状态失败").toString());
}
}
// 其他情况记录日志但不处理
else {
log.debug("签署流程未完成或未知动作类型,不做处理: action={}, signFlowId={}", action, signFlowId);
return ResponseEntity.ok(new JSONObject().put("code", 200).put("msg", "success").toString());
}
} else if (action.equals("SIGN_MISSON_COMPLETE") && ObjectUtil.isNotEmpty(signResult)) {// 签署方-签署结果含拒签通知
Integer signFlowStatus = null;
if (signResult.equals(2)) {
signFlowStatus = CommonConstant.CONTRACT_SIGN_STA_PARTIALLY;
} else if (signResult.equals(4)) {
signFlowStatus = CommonConstant.CONTRACT_SIGN_STA_REJECT;
}
// 更新合同流程状态和文件地址
boolean success = updateContractFlowStatusAndFileUrlBySignFlowId(signFlowId, signFlowStatus, "");
if (success) {
return ResponseEntity.ok(new JSONObject().put("code", 200).put("msg", "success").toString());
}
} else {
log.debug("签署流程未完成,不做处理");
} catch (Exception e) {
log.error("处理e签宝异步通知异常: action={}, signFlowId={}", action, signFlowId, e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new JSONObject().put("code", 500).put("msg", "处理通知异常").toString());
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new JSONObject().put("code", 400).put("msg", "未更新数据!").toString());
}
/**
* 管理员查看已签署的电子合同文件
*
* @param mchMobile
* @param storeId
* @return
*/
@Override
public CommonResult getSignedContactFile(String mchMobile) {
String userId = "0";
// UserDto user = getCurrentUser();
// if (!user.isAdmin()) {
// return CommonResult.failed("权限不足!");
// }
// userId = user.getId().toString();
EsignContract esignContract = getEsignContractByMchMobile(mchMobile);
public CommonResult getSignedContactFile(Integer storeId) {
EsignContract esignContract = getEsignContractByStoreId(storeId);
if (esignContract == null) {
return CommonResult.success(null, "未找到商家合同信息");
}
@ -583,22 +634,86 @@ public class EsignContractServiceImpl extends BaseServiceImpl<EsignContractMappe
/**
* 根据商家注册手机号获取一条合同信息
*
* @param mchMobile
* @return
* @param mchMobile 商家注册手机号
* @return EsignContract 合同信息对象若未找到则返回null
*/
@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)) {
// 参数校验
if (StrUtil.isBlank(mchMobile)) {
log.warn("查询合同信息失败:商家手机号为空");
return null;
}
return esignContractList.get(0);
try {
QueryWrapper<EsignContract> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("mch_mobile", mchMobile);
queryWrapper.eq("status", CommonConstant.Enable);
return findOne(queryWrapper);
} catch (Exception e) {
log.error("根据商家手机号查询合同信息异常,手机号: {}", mchMobile, e);
return null;
}
}
/**
* 根据店铺Id获取一条合同信息
*
* @param storeId 店铺ID
* @return EsignContract 合同信息对象若未找到则返回null
*/
@Override
public EsignContract getEsignContractByStoreId(Integer storeId) {
// 参数校验
if (storeId == null) {
log.warn("查询合同信息失败店铺ID为空");
return null;
}
try {
QueryWrapper<EsignContract> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("store_id", storeId);
queryWrapper.eq("status", CommonConstant.Enable);
return findOne(queryWrapper);
} catch (Exception e) {
log.error("根据店铺ID查询合同信息异常店铺ID: {}", storeId, e);
return null;
}
}
/**
* 根据店铺Id获取合同状态和下载地址
*
* @param storeId
* @return
*/
@Override
public EsignContract getEsignContractStatusUrl(Integer storeId) {
// 参数校验
if (storeId == null) {
log.warn("查询合同状态和URL失败店铺ID为空");
return null;
}
try {
LambdaQueryWrapper<EsignContract> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(EsignContract::getStore_id, storeId)
.eq(EsignContract::getStatus, CommonConstant.Enable)
.eq(EsignContract::getSign_flow_status, CommonConstant.CONTRACT_SIGN_STA_FINISH)
.isNotNull(EsignContract::getLocal_contract_url)
.ne(EsignContract::getLocal_contract_url, "")
.select(EsignContract::getSign_flow_status, EsignContract::getLocal_contract_url);
return findOne(queryWrapper);
} catch (Exception e) {
log.error("根据店铺ID查询合同状态和URL异常店铺ID: {}", storeId, e);
return null;
}
}
@Override
public EsignContract getEsignContractBySignFlowId(String signFlowId) {
QueryWrapper<EsignContract> queryWrapper = new QueryWrapper<>();

View File

@ -149,12 +149,7 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl<EsignPlatformI
queryWrapper.eq("license_number", licenseNumber);
}
List<EsignPlatformInfo> esignPlatformInfos = list(queryWrapper);
if (CollectionUtil.isEmpty(esignPlatformInfos)) {
return null;
}
return esignPlatformInfos.get(0);
return findOne(queryWrapper);
}
/**

View File

@ -5390,6 +5390,18 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl<ShopOrderBaseMappe
cancelActivity(order_id);
}
// 取消顺丰同城配送订单
// === 7. 特殊场景顺丰同城配送且全单退的时候才触发顺丰同城订单取消 ===
if (orderInfo.getDelivery_type_id() != null
&& StateCode.DELIVERY_TYPE_SAME_CITY == orderInfo.getDelivery_type_id().intValue()) {
try {
sfExpressApiService.cancelOrder(order_id, 313, "用户或商家取消订单。");
} catch (Exception e) {
log.error("顺丰同城取消订单失败", e);
}
}
return true;
}

View File

@ -2888,7 +2888,7 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
if (lklOrderSeparateService.isOrderSeparated(orderId)) {
// TODO 后期如果已经分账的订单一定强硬退款可能需要拉卡拉撤销分账再退款已提现的真的没有办法退款了
return CommonResult.failed("订单已三方结清,无法退款");
return CommonResult.failed("订单已三方结清,无法退款");
}
List<ShopOrderItem> orderItems = shopOrderItemService.find(new QueryWrapper<ShopOrderItem>().eq("order_id", orderId));
@ -2996,16 +2996,16 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl<ShopOrderReturnM
throw new ApiException("退款审核失败!");
}
// === 7. 特殊场景同城配送订单取消 ===
if (orderInfo.getDelivery_type_id() != null
&& StateCode.DELIVERY_TYPE_SAME_CITY == orderInfo.getDelivery_type_id().intValue()
&& !isPartialRefund) {
try {
sfExpressApiService.cancelOrder(orderId, 313, refundOrder.getReturn_store_message());
} catch (Exception e) {
log.error("顺丰同城取消订单失败", e);
}
}
// // === 7. 特殊场景顺丰同城配送且全单退的时候才触发顺丰同城订单取消 === RMK 在ShopOrderBaseServiceImpl.cancel取消订单方法里执行了
// if (orderInfo.getDelivery_type_id() != null
// && StateCode.DELIVERY_TYPE_SAME_CITY == orderInfo.getDelivery_type_id().intValue()
// && !isPartialRefund) {
// try {
// sfExpressApiService.cancelOrder(orderId, 313, refundOrder.getReturn_store_message());
// } catch (Exception e) {
// log.error("顺丰同城取消订单失败", e);
// }
// }
return CommonResult.success();
} catch (Exception e) {

View File

@ -185,42 +185,10 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
return Pair.of(false, "联系人手机号不能为空");
}
// AddressParseResultTO addressParseResultTO = AddressUtil.parseAddress(shopMchEntry.getStore_address());
// // 解析城市名称
// String cityName = "桂平市"; // 默认城市
//
// // 去掉省市区的详细地址
// String storeAddress = addressParseResultTO.getDetailAddress();
//
// if (StrUtil.isNotBlank(shopMchEntry.getStore_area())) {
// String[] areaNames = shopMchEntry.getStore_area().split("/");
// if (areaNames.length >= 3) {
// cityName = areaNames[areaNames.length - 1];
// } else {
// cityName = shopMchEntry.getStore_area().replace("/", "");
// }
// } else {
// cityName = addressParseResultTO.getCity();
// }
//
// // 如果解析后城市名为空使用默认值
// if (StrUtil.isBlank(cityName)) {
// cityName = "桂平市";
// logger.warn("[顺丰] 城市名为空,使用默认城市: {}", cityName);
// } else {
// logger.debug("[顺丰] 解析得到城市名: {}", cityName);
// }
//
// // 为了其他顺丰店同名店铺名称加上[门店ID]; xxxx[xxxx] 聚万家生鲜超市[69]
// String shopStoreName = String.format("%s[%s]", shopMchEntry.getStore_name(), shopMchEntry.getStore_id());
// 调用创建店铺方法
Pair<Boolean, String> result = createSfExpressShop(
mchId,
Convert.toInt(shopMchEntry.getStore_id()),
// shopStoreName,
// cityName,
// storeAddress,
shopMchEntry.getContact_name(),
contactMobile,
shopMchEntry.getStore_longitude(),
@ -718,77 +686,92 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
* 取消订单
*
* @param params 综合参数请参考https://openic.sf-express.com/open/api/docs/index/#/apidoc
* @return
* @return ThirdApiRes 取消订单结果
*/
@Override
@Transactional
public ThirdApiRes cancelOrder(Map<String, Object> params) {
// TODO 检验用户权限
logger.info("[顺丰] 开始取消订单流程");
// 1. 参数校验
if (params == null || ObjectUtil.isEmpty(params.get("order_id"))) {
logger.warn("[顺丰] 取消订单参数校验失败: 参数为空或缺少order_id");
return new ThirdApiRes().fail(1003, "请求参数有误!");
}
// 转换 json 字符串参数
String sfOrderId = params.get("order_id").toString(); // 这是顺丰的订单号不是商城的订单号
params.putAll(buildCommonParams());
try {
// 2. 获取顺丰订单号
String sfOrderId = params.get("order_id").toString();
logger.debug("[顺丰] 准备取消订单: sfOrderId={}", sfOrderId);
String paramJSON = JsonUtil.toJSONString(params);
// 3. 添加公共参数
params.putAll(buildCommonParams());
String paramJSON = JsonUtil.toJSONString(params);
// 根据参数生成请求签名
String send_url = buildUrl("cancelorder", paramJSON);
String retRespStr = HttpUtil.post(send_url, paramJSON);
if (StrUtil.isBlank(retRespStr)) {
logger.error("顺丰同城:取消订单异常,无返回值!");
return new ThirdApiRes().fail(2, "顺丰同城:无返回值!");
// 4. 调用顺丰取消订单接口
String sendUrl = buildUrl("cancelorder", paramJSON);
logger.debug("[顺丰] 调用取消订单接口: url={}, params={}", sendUrl, paramJSON);
String responseStr = HttpUtil.post(sendUrl, paramJSON);
if (StrUtil.isBlank(responseStr)) {
logger.error("[顺丰] 取消订单接口调用失败: 无返回值, sfOrderId={}", sfOrderId);
return new ThirdApiRes().fail(2, "顺丰同城:无返回值!");
}
// 5. 解析接口响应
ThirdApiRes sfExpressApiRes = JsonUtil.json2object(responseStr, ThirdApiRes.class);
if (sfExpressApiRes == null) {
logger.error("[顺丰] 取消订单接口响应解析失败: {}, sfOrderId={}", responseStr, sfOrderId);
return new ThirdApiRes().fail(2, "顺丰同城:响应解析失败!");
}
// 6. 检查接口调用结果
if (!sfExpressApiRes.getError_code().equals(0)) {
logger.error("[顺丰] 取消订单接口调用失败: errorCode={}, errorMsg={}, sfOrderId={}",
sfExpressApiRes.getError_code(), sfExpressApiRes.getError_msg(), sfOrderId);
return new ThirdApiRes().fail(2, sfExpressApiRes.getError_msg());
}
logger.info("[顺丰] 顺丰接口取消订单成功: sfOrderId={}", sfOrderId);
// 7. 检查本地订单状态
ShopStoreSfOrder existingOrder = shopStoreSfOrderService.getByShopOrderId(sfOrderId);
if (existingOrder == null) {
logger.error("[顺丰] 本地订单不存在: sfOrderId={}", sfOrderId);
return new ThirdApiRes().fail(2, "订单不存在!");
}
// 8. 检查订单是否已经取消
if (existingOrder.getOrder_status() != null &&
(existingOrder.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELED) ||
existingOrder.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELING))) {
logger.info("[顺丰] 订单已处于取消状态,无需重复操作: sfOrderId={}, status={}",
sfOrderId, existingOrder.getOrder_status());
return new ThirdApiRes().success("订单已取消过!");
}
// 9. 更新顺丰订单状态为已取消
ShopStoreSfOrder updateOrder = new ShopStoreSfOrder();
updateOrder.setSf_order_id(existingOrder.getSf_order_id());
updateOrder.setOrder_status(StateCode.SF_ORDER_STATUS_CANCELED);
updateOrder.setStatus_desc("线上商城发起取消订单");
Boolean updateSuccess = shopStoreSfOrderService.updateShopStoreSfOrderStatus(updateOrder);
if (!updateSuccess) {
logger.error("[顺丰] 更新本地订单状态失败: sfOrderId={}", sfOrderId);
throw new ApiException(_("取消顺丰订单失败!"));
}
logger.info("[顺丰] 本地订单状态更新成功: sfOrderId={}", sfOrderId);
return sfExpressApiRes;
} catch (Exception e) {
logger.error("[顺丰] 取消订单过程中发生异常: ", e);
return new ThirdApiRes().fail(-1, "系统异常: " + e.getMessage());
}
ThirdApiRes sfExpressApiRes = JsonUtil.json2object(retRespStr, ThirdApiRes.class);
if (sfExpressApiRes == null) {
logger.error("顺丰同城:取消订单,返回值异常!{}", retRespStr);
return new ThirdApiRes().fail(2, "顺丰同城:无返回值!");
}
if (!sfExpressApiRes.getError_code().equals(0)) {
logger.error("顺丰同城:取消订单失败!{}", retRespStr);
return new ThirdApiRes().fail(2, sfExpressApiRes.getError_msg());
}
// 判断订单的状态是否已经取消了已取消不再执行
ShopStoreSfOrder shopStoreSfOrderExist = shopStoreSfOrderService.getByShopOrderId(sfOrderId);
if (shopStoreSfOrderExist == null) {
return new ThirdApiRes().fail(2, "订单有误!");
}
if (shopStoreSfOrderExist.getOrder_status() != null
&& (shopStoreSfOrderExist.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELED) ||
(shopStoreSfOrderExist.getOrder_status().equals(StateCode.SF_ORDER_STATUS_CANCELING)))) {
return new ThirdApiRes().success("订单已取消过!");
}
// // 更改商城订单状态为已取消注意事务问题
// List<String> orderList = new ArrayList<>();
// orderList.add(shopStoreSfOrderExist.getShop_order_id());
// 取消订单, 流程订单状态积分众宝库存礼包优惠券 有就统统退还
// Boolean success = shopOrderReturnService.sfExpressExpiredForceRefund(shopStoreSfOrderExist.getShop_order_id()); // 不检查订单付款状态
// if (!success) {
// throw new ApiException(I18nUtil._("取消商家订单失败!"));
// }
// 更改顺丰的订单状态
ShopStoreSfOrder shopStoreSfOrder = new ShopStoreSfOrder();
shopStoreSfOrder.setSf_order_id(shopStoreSfOrderExist.getSf_order_id());
shopStoreSfOrder.setOrder_status(StateCode.SF_ORDER_STATUS_CANCELED);
shopStoreSfOrder.setStatus_desc("线上商城发起取消订单");
Boolean success = shopStoreSfOrderService.updateShopStoreSfOrderStatus(shopStoreSfOrder);
if (!success) {
throw new ApiException(_("取消顺丰订单失败!"));
}
return sfExpressApiRes;
}
/**
* 订单加小费订单创建后骑士未接单的情况下通过该接口对订单进行加小费促进订单接单截止订单完成前都可以对订单加小费
*
@ -1170,10 +1153,10 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
String order_id = shopStoreSfOrder.getShop_order_id();
itemQueryWrapper.eq("order_id", order_id);
List<ShopOrderItem> order_item_rows = shopOrderItemService.find(itemQueryWrapper);
ShopOrderBase shopOrderBase=shopOrderBaseService.get(order_id);
String saleTimeStr=null;
if(null!=shopOrderBase){
saleTimeStr= String.valueOf(shopOrderBase.getOrder_time().getTime());
ShopOrderBase shopOrderBase = shopOrderBaseService.get(order_id);
String saleTimeStr = null;
if (null != shopOrderBase) {
saleTimeStr = String.valueOf(shopOrderBase.getOrder_time().getTime());
}
if (picking(order_item_rows)) {
logger.info("顺丰发货商品扣减库存成功");
@ -1183,12 +1166,12 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
Map<String, Integer> stockDeltaMap = new HashMap<>();
String item_src_id = shopOrderItem.getItem_src_id();
Integer order_item_quantity = shopOrderItem.getOrder_item_quantity();
String mapKey=item_src_id + "-" + shopStoreSfOrder.getShop_order_id()+"-"+shopOrderItem.getOrder_item_unit_price();
if(StringUtils.isNotEmpty(saleTimeStr)){
mapKey=mapKey+"-"+saleTimeStr;
String mapKey = item_src_id + "-" + shopStoreSfOrder.getShop_order_id() + "-" + shopOrderItem.getOrder_item_unit_price();
if (StringUtils.isNotEmpty(saleTimeStr)) {
mapKey = mapKey + "-" + saleTimeStr;
}
stockDeltaMap.put(mapKey, -order_item_quantity);
syncThirdDataService.incrProductStockToRedis(stockDeltaMap,null);
syncThirdDataService.incrProductStockToRedis(stockDeltaMap, null);
}
}
//出库扣减思迅库存end
@ -1356,9 +1339,9 @@ public class SFExpressApiServiceImpl implements SFExpressApiService {
Map<String, Integer> stockDeltaMap = new HashMap<>();
String item_src_id = shopOrderItem.getItem_src_id();
Integer order_item_quantity = shopOrderItem.getOrder_item_quantity();
String mapKey=item_src_id + "-" + shopOrderItem.getOrder_id()+"-"+shopOrderItem.getOrder_item_unit_price()+"-"+shopOrderBase.getOrder_time().getTime();
String mapKey = item_src_id + "-" + shopOrderItem.getOrder_id() + "-" + shopOrderItem.getOrder_item_unit_price() + "-" + shopOrderBase.getOrder_time().getTime();
stockDeltaMap.put(mapKey, -order_item_quantity);
syncThirdDataService.incrProductStockToRedis(stockDeltaMap,null);
syncThirdDataService.incrProductStockToRedis(stockDeltaMap, null);
}
}
return CommonResult.success("操作成功");

View File

@ -44,7 +44,7 @@ public class ShopMchEntryController extends BaseControllerImpl {
@ApiOperation(value = "测试", notes = "测试")
@RequestMapping(value = "/gencon", method = RequestMethod.POST)
public Object fillDocTemplate() {
return esignContractFillingFileService.fillDocTemplate("13128997057", "91450881MADEQ92533");
return esignContractFillingFileService.fillDocTemplate(57);
}
@ApiOperation(value = "店铺主营分类(类目)", notes = "店铺主营分类(类目)")

View File

@ -367,4 +367,12 @@ public interface ShopMchEntryService {
* @return 包含ID路径和名称路径的字符串数组格式为 [ID路径, 名称路径]
*/
String[] handleStoreDistrictInfo(String storeDistrict, String storeArea, String refStoreAddress);
/**
* 根据店铺Id获取拉卡拉的审核状态和下载地址
*
* @param storeId
* @return
*/
ShopMchEntry getLklContractStatusUrl(Integer storeId);
}

View File

@ -17,6 +17,7 @@ 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.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -2511,6 +2512,36 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl<ShopMchEntryMapper,
}
}
/**
* 根据店铺Id获取拉卡拉的审核状态和下载地址
*
* @param storeId
* @return
*/
@Override
public ShopMchEntry getLklContractStatusUrl(Integer storeId) {
// 参数校验
if (storeId == null) {
log.warn("查询合同状态和URL失败店铺ID为空");
return null;
}
try {
LambdaQueryWrapper<ShopMchEntry> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(ShopMchEntry::getStore_id, storeId)
.eq(ShopMchEntry::getStatus, CommonConstant.Enable)
.eq(ShopMchEntry::getApproval_status, CommonConstant.MCH_APPR_STA_PASS)
.isNotNull(ShopMchEntry::getContract_download_url)
.ne(ShopMchEntry::getContract_download_url, "")
.select(ShopMchEntry::getApproval_status, ShopMchEntry::getContract_download_url);
return findOne(queryWrapper);
} catch (Exception e) {
log.error("根据店铺ID查询合同状态和URL异常店铺ID: {}", storeId, e);
return null;
}
}
}

View File

@ -33,6 +33,7 @@ import com.suisung.mall.common.modules.account.AccountUserInfo;
import com.suisung.mall.common.modules.account.AccountUserSns;
import com.suisung.mall.common.modules.base.*;
import com.suisung.mall.common.modules.distribution.ShopDistributionPlantformUser;
import com.suisung.mall.common.modules.esign.EsignContract;
import com.suisung.mall.common.modules.invoicing.InvoicingCustomerLevel;
import com.suisung.mall.common.modules.invoicing.InvoicingWarehouseBase;
import com.suisung.mall.common.modules.page.ShopPageBase;
@ -56,6 +57,7 @@ import com.suisung.mall.shop.base.service.ShopBaseStoreGradeService;
import com.suisung.mall.shop.config.BaiduUtil;
import com.suisung.mall.shop.distribution.service.ShopDistributionPlantformUserService;
import com.suisung.mall.shop.entity.LocationBean;
import com.suisung.mall.shop.esign.service.EsignContractService;
import com.suisung.mall.shop.invoicing.service.InvoicingCustomerLevelService;
import com.suisung.mall.shop.invoicing.service.InvoicingWarehouseBaseService;
import com.suisung.mall.shop.page.service.ShopPageBaseService;
@ -184,6 +186,11 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
@Lazy
@Autowired
private ShopMchEntryService shopMchEntryService;
@Lazy
@Autowired
private EsignContractService esignContractService;
@Autowired
private ThreadPoolExecutor executor;
@ -1474,6 +1481,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
List<Map> items = (List<Map>) data.get("items");
//经营期限
List<Integer> store_ids = items.stream().map(s -> Convert.toInt(s.get("store_id"))).collect(Collectors.toList());
List<ShopStoreInfo> store_info_rows = shopStoreInfoService.gets(store_ids);
List<Integer> subsite_ids = items.stream().map(s -> Convert.toInt(s.get("subsite_id"))).distinct().collect(Collectors.toList());
@ -1481,6 +1489,7 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
if (CollUtil.isNotEmpty(subsite_ids)) {
subsite_rows = shopPlantformSubsiteService.gets(subsite_ids);
}
//店铺统计
List<ShopStoreAnalytics> store_analytics_rows = shopStoreAnalyticsService.gets(store_ids);
List<ShopPlantformSubsite> finalSubsite_rows = subsite_rows;
@ -1525,6 +1534,22 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
} else {
s.put("subsite_name", I18nUtil._("全国站"));
}
// E签宝和拉卡拉的合同文件下载地址
String lkl_contract_file_url = "";
String esign_contract_file_url = "";
ShopMchEntry entry = shopMchEntryService.getLklContractStatusUrl(_store_id);
if (ObjectUtil.isNotEmpty(entry)) {
lkl_contract_file_url = entry.getContract_download_url();
}
EsignContract esignContract = esignContractService.getEsignContractStatusUrl(_store_id);
if (ObjectUtil.isNotEmpty(esignContract)) {
esign_contract_file_url = esignContract.getSigned_contract_url();
}
s.put("lkl_contract_file_url", lkl_contract_file_url);
s.put("esign_contract_file_url", esign_contract_file_url);
});
data.put("items", accountService.fixUserAvatar((List<Map>) data.get("items"), true));
@ -1558,6 +1583,21 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl<ShopStoreBaseMappe
}
}
// E签宝和拉卡拉的合同文件下载地址
String lkl_contract_file_url = "";
String esign_contract_file_url = "";
ShopMchEntry entry = shopMchEntryService.getLklContractStatusUrl(store_id);
if (ObjectUtil.isNotEmpty(entry)) {
lkl_contract_file_url = entry.getContract_download_url();
}
EsignContract esignContract = esignContractService.getEsignContractStatusUrl(store_id);
if (ObjectUtil.isNotEmpty(esignContract)) {
esign_contract_file_url = esignContract.getSigned_contract_url();
}
row.put("lkl_contract_file_url", lkl_contract_file_url);
row.put("esign_contract_file_url", esign_contract_file_url);
// 火星坐标系GCJ02经纬度 转出 百度坐标系BD09经纬度因为数据库保存的经纬度统一是GCJ02经纬度所以需要转换
gcj02ToBd09Gps(row);