diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java b/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java index 620147fd..93d1d7e9 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/esign/controller/admin/EsignController.java @@ -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")); } } 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 fafe710d..11fbcd4a 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 @@ -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位置数据 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 41b7afe1..afa26800 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 @@ -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 innerSignFlowCreateByFile(String mchMobile); + Pair 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); } 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 88ba9d90..de141c64 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 @@ -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 - * 后台管理员审核商家通过之后,触发调用这个方法,生成未签署合同文件,预备签署 + * 拉卡拉审核通过之后,触发调用这个方法,生成未签署合同文件,预备签署 * - * @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() {{ - put("componentKey", "plat_contracts"); - put("componentValue", "《平台商户入驻服务框架协议》和《小发同城服务费结算》"); - }}); - - // 签署时间 - for (int i = 1; i <= 3; i++) { - int finalI = i; + // 10. 填充合同组件数据 + // 平台合同名称 list.add(new HashMap() {{ - 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() {{ - 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() {{ - 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() {{ + 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() {{ put("componentKey", "mch_company" + finalI); @@ -199,233 +230,239 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl() {{ put("componentKey", "mch_company17"); put("componentValue", shopMchEntry.getContact_name()); }}); } - } - // 甲方法人姓名,甲方是个人的时候,没有法人,直接用个人实名 - for (int i = 1; i <= 4; i++) { - int finalI = i; - list.add(new HashMap() {{ - put("componentKey", "mch_legal_person_name" + finalI); - put("componentValue", legalPersonName); - }}); - } - - // 甲方法人手机号 - for (int i = 1; i <= 3; i++) { - int finalI = i; - list.add(new HashMap() {{ - put("componentKey", "mch_legal_person_mobile" + finalI); - put("componentValue", LegalPersonMobile); - }}); - } - - // 甲方身份证号码 - list.add(new HashMap() {{ - put("componentKey", "mch_legal_person_id_number1"); - put("componentValue", legalPersonIdNumber); - }}); - - list.add(new HashMap() {{ - put("componentKey", "mch_store_name1"); - put("componentValue", shopMchEntry.getStore_name()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "rule_no"); - put("componentValue", 3); - }}); - - list.add(new HashMap() {{ - put("componentKey", "mch_ratio"); - put("componentValue", shopMchEntry.getSplit_ratio()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "settlement_method"); - put("componentValue", shopMchEntry.getSettlement_method()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "mch_address1"); - put("componentValue", shopMchEntry.getStore_address()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "mch_bank1"); - put("componentValue", shopMchEntry.getBank_name()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "mch_account_number1"); - put("componentValue", shopMchEntry.getAccount_number()); - }}); - - // 乙方公司名称 - list.add(new HashMap() {{ - put("componentKey", "plat_company1"); - put("componentValue", platCompany + "和代理商"); - }}); - - for (int i = 2; i <= 5; i++) { - int finalI = i; - list.add(new HashMap() {{ - put("componentKey", "plat_company" + finalI); - put("componentValue", platCompany); - }}); - } - - for (int i = 1; i <= 2; i++) { - int finalI = i; - list.add(new HashMap() {{ - put("componentKey", "plat_mobile" + finalI); - put("componentValue", finalEsignPlatformInfo.getLegal_person_mobile()); - }}); - } - - list.add(new HashMap() {{ - put("componentKey", "plat_email1"); - put("componentValue", finalEsignPlatformInfo.getEmail()); - }}); - - - list.add(new HashMap() {{ - put("componentKey", "plat_email1"); - put("componentValue", finalEsignPlatformInfo.getEmail()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "plat_email1"); - put("componentValue", finalEsignPlatformInfo.getEmail()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "plat_email1"); - put("componentValue", finalEsignPlatformInfo.getEmail()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "plat_email1"); - put("componentValue", finalEsignPlatformInfo.getEmail()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "plat_email1"); - put("componentValue", finalEsignPlatformInfo.getEmail()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "plat_bank1"); - put("componentValue", finalEsignPlatformInfo.getRec_acc_bank_name()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "plat_account_number1"); - put("componentValue", finalEsignPlatformInfo.getRec_acc_card_no()); - }}); - - // 代理商相关 - if (distributor != null) { - // 有代理商的时候,才填充代理商的信息 - list.add(new HashMap() {{ - put("componentKey", "distr_company1"); - put("componentValue", distributor.getLicense_company()); - }}); - list.add(new HashMap() {{ - put("componentKey", "distr_mobile1"); - put("componentValue", distributor.getLegal_person_mobile()); - }}); - list.add(new HashMap() {{ - put("componentKey", "distr_company2"); - put("componentValue", distributor.getLicense_company()); - }}); - list.add(new HashMap() {{ - put("componentKey", "distr_bank1"); - put("componentValue", distributor.getRec_acc_bank_name()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "distr_account_number1"); - put("componentValue", distributor.getRec_acc_card_no()); - }}); - - list.add(new HashMap() {{ - put("componentKey", "distr_sign_date1"); - put("componentValue", today); - }}); - } else { - // 有代理商的时候,才填充代理商的信息 - list.add(new HashMap() {{ - put("componentKey", "distr_company1"); - put("componentValue", "无"); - }}); - list.add(new HashMap() {{ - put("componentKey", "distr_mobile1"); - put("componentValue", "无"); - }}); - list.add(new HashMap() {{ - put("componentKey", "distr_company2"); - put("componentValue", "无"); - }}); - list.add(new HashMap() {{ - put("componentKey", "distr_bank1"); - put("componentValue", "无"); - }}); - - list.add(new HashMap() {{ - put("componentKey", "distr_account_number1"); - put("componentValue", "无"); - }}); - - } - - fillJson.put("components", list); - - String jsonParma = fillJson.toString(); - - //生成签名鉴权方式的的header - Map 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() {{ + 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() {{ + put("componentKey", "mch_legal_person_mobile" + finalI); + put("componentValue", legalPersonMobile); + }}); + } + // 甲方身份证号码 + list.add(new HashMap() {{ + put("componentKey", "mch_legal_person_id_number1"); + put("componentValue", legalPersonIdNumber); + }}); + + // 甲方店铺名称 + list.add(new HashMap() {{ + put("componentKey", "mch_store_name1"); + put("componentValue", shopMchEntry.getStore_name()); + }}); + + // 规则编号 + list.add(new HashMap() {{ + put("componentKey", "rule_no"); + put("componentValue", 3); + }}); + + // 分账比例 + BigDecimal finalSplitRatio = splitRatio; + list.add(new HashMap() {{ + put("componentKey", "mch_ratio"); + put("componentValue", finalSplitRatio); + }}); + + // 结算方式 + list.add(new HashMap() {{ + put("componentKey", "settlement_method"); + put("componentValue", shopMchEntry.getSettlement_method()); + }}); + + // 甲方地址 + list.add(new HashMap() {{ + put("componentKey", "mch_address1"); + put("componentValue", shopMchEntry.getStore_address()); + }}); + + // 甲方银行 + list.add(new HashMap() {{ + put("componentKey", "mch_bank1"); + put("componentValue", shopMchEntry.getBank_name()); + }}); + + // 甲方账户号 + list.add(new HashMap() {{ + put("componentKey", "mch_account_number1"); + put("componentValue", shopMchEntry.getAccount_number()); + }}); + + // 乙方公司名称 + list.add(new HashMap() {{ + put("componentKey", "plat_company1"); + put("componentValue", platCompany + "和代理商"); + }}); + + // 其他乙方公司名称 + for (int i = 2; i <= 5; i++) { + int finalI = i; + list.add(new HashMap() {{ + put("componentKey", "plat_company" + finalI); + put("componentValue", platCompany); + }}); + } + + // 乙方手机号 + for (int i = 1; i <= 2; i++) { + int finalI = i; + list.add(new HashMap() {{ + put("componentKey", "plat_mobile" + finalI); + put("componentValue", esignPlatformInfo.getLegal_person_mobile()); + }}); + } + + // 乙方邮箱(重复填充,但保持原逻辑) + for (int i = 0; i < 6; i++) { + list.add(new HashMap() {{ + put("componentKey", "plat_email1"); + put("componentValue", esignPlatformInfo.getEmail()); + }}); + } + + // 乙方银行 + list.add(new HashMap() {{ + put("componentKey", "plat_bank1"); + put("componentValue", esignPlatformInfo.getRec_acc_bank_name()); + }}); + + // 乙方账户号 + list.add(new HashMap() {{ + put("componentKey", "plat_account_number1"); + put("componentValue", esignPlatformInfo.getRec_acc_card_no()); + }}); + + // 11. 处理代理商相关数据 + if (distributor != null) { + // 有代理商的时候,填充代理商的信息 + list.add(new HashMap() {{ + put("componentKey", "distr_company1"); + put("componentValue", distributor.getLicense_company()); + }}); + list.add(new HashMap() {{ + put("componentKey", "distr_mobile1"); + put("componentValue", distributor.getLegal_person_mobile()); + }}); + list.add(new HashMap() {{ + put("componentKey", "distr_company2"); + put("componentValue", distributor.getLicense_company()); + }}); + list.add(new HashMap() {{ + put("componentKey", "distr_bank1"); + put("componentValue", distributor.getRec_acc_bank_name()); + }}); + + list.add(new HashMap() {{ + put("componentKey", "distr_account_number1"); + put("componentValue", distributor.getRec_acc_card_no()); + }}); + + list.add(new HashMap() {{ + put("componentKey", "distr_sign_date1"); + put("componentValue", today); + }}); + + log.debug("已填充代理商信息: {}", distributor.getLicense_company()); + } else { + // 无代理商时填充默认值 + list.add(new HashMap() {{ + put("componentKey", "distr_company1"); + put("componentValue", "无"); + }}); + list.add(new HashMap() {{ + put("componentKey", "distr_mobile1"); + put("componentValue", "无"); + }}); + list.add(new HashMap() {{ + put("componentKey", "distr_company2"); + put("componentValue", "无"); + }}); + list.add(new HashMap() {{ + put("componentKey", "distr_bank1"); + put("componentValue", "无"); + }}); + + list.add(new HashMap() {{ + put("componentKey", "distr_account_number1"); + put("componentValue", "无"); + }}); + + log.debug("未配置代理商信息,使用默认值"); + } + + fillJson.put("components", list); + String jsonParam = fillJson.toString(); + + // 12. 调用e签宝API生成合同文件 + Map 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 signPositionMap = getSignPosition(templateId, fileId); if (signPositionMap != null) { if (signPositionMap.get("mch") != null) { @@ -441,22 +478,34 @@ public class EsignContractFillingFileServiceImpl extends BaseServiceImpl 0; + boolean result = successCnt > 0; + log.info("合同文件生成完成, storeId: {}, 总模版数: {}, 成功处理数: {}, 结果: {}", + storeId, templates.size(), successCnt, result); + + return result; } + /** * 获取模版的甲方与乙方印章XY位置数据 * 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 32e9a451..fbfa2ae5 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 @@ -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 ret = innerSignFlowCreateByFile(mchMobile); + public CommonResult signFlowCreateByFile(Integer storeId) { + Pair ret = innerSignFlowCreateByFile(storeId); if (!ret.getFirst()) { return CommonResult.failed(ret.getSecond()); } @@ -179,21 +166,25 @@ public class EsignContractServiceImpl extends BaseServiceImpl innerSignFlowCreateByFile(String mchMobile) { - //String userId = "0"; - - if (StrUtil.isBlank(mchMobile)) { + public Pair 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>> {}", 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().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().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 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 queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("mch_mobile", mchMobile); - queryWrapper.eq("status", CommonConstant.Enable); - List esignContractList = this.list(queryWrapper); - if (CollectionUtil.isEmpty(esignContractList)) { + // 参数校验 + if (StrUtil.isBlank(mchMobile)) { + log.warn("查询合同信息失败:商家手机号为空"); return null; } - return esignContractList.get(0); + try { + QueryWrapper 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 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 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 queryWrapper = new QueryWrapper<>(); 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 6aa55a76..6c3d3c7a 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 @@ -149,12 +149,7 @@ public class EsignPlatformInfoServiceImpl extends BaseServiceImpl esignPlatformInfos = list(queryWrapper); - if (CollectionUtil.isEmpty(esignPlatformInfos)) { - return null; - } - - return esignPlatformInfos.get(0); + return findOne(queryWrapper); } /** diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java index 6ba8d32b..a3ea4618 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java @@ -5390,6 +5390,18 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl orderItems = shopOrderItemService.find(new QueryWrapper().eq("order_id", orderId)); @@ -2996,16 +2996,16 @@ public class ShopOrderReturnServiceImpl extends BaseServiceImpl= 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 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 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 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 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 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 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("操作成功"); diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java index 2aa1bf4f..6ffbd5cb 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/controller/mobile/ShopMchEntryController.java @@ -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 = "店铺主营分类(类目)") diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java index f1859fa4..40ce92cc 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/ShopMchEntryService.java @@ -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); } \ No newline at end of file diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index 0f5a945f..498727e8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -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 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; + } + } + } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java index cedc24aa..a941e594 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopStoreBaseServiceImpl.java @@ -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 items = (List) data.get("items"); //经营期限 + List store_ids = items.stream().map(s -> Convert.toInt(s.get("store_id"))).collect(Collectors.toList()); List store_info_rows = shopStoreInfoService.gets(store_ids); List 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 store_analytics_rows = shopStoreAnalyticsService.gets(store_ids); List finalSubsite_rows = subsite_rows; @@ -1525,6 +1534,22 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl) data.get("items"), true)); @@ -1558,6 +1583,21 @@ public class ShopStoreBaseServiceImpl extends BaseServiceImpl