Merge #8 into master from cc_20250922_closeStore_w

闭店

* cc_20250922_closeStore_w: (44 commits squashed)

  - feat:闭店流程init

  - feat:闭店流程接口

  - feat:闭店

  - Merge branch 'refs/heads/master' into cc_20250922_closeStore_w

  - fix:闭店材料模块

  - fix:账号关闭流程

  - feat:闭店审批流程(未测);字典表

  - fix:闭店审批流程完善

  - Merge branch 'master' into cc_20250922_closeStore_w

  - fix:闭店流程流转补充

  - feat:闭店退款

  - fix:字典表接口

  - Merge branch 'master' into cc_20250922_closeStore_w

  - fix:闭店原因接口新增闭店发起方式字段

  - fix:修改审批记录返回数据类型
    feat:新增退款流程跳过

  - fix

  - fix:新增字段

  - feat:新增闭店退款提交人列表接口

  - fix:闭店初始化数据来源修改;小程序闭店材料详情新增模板url字段

  - fix:新增接口返回字段

  - fix:闭店管理、审批待办类别所属品牌筛选改为多选

  - fix:闭店管理列表新增完成阶段数量字段

  - feat:新增第三方闭店申请接口

  - Merge branch 'refs/heads/master' into cc_20250922_closeStore_w
    
    # Conflicts:
    #	coolstore-partner-common/src/main/java/com/cool/store/constants/CommonConstants.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
    #	coolstore-partner-common/src/main/java/com/cool/store/utils/BeanUtil.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/dao/StoreDao.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/mapper/StoreMapper.java
    #	coolstore-partner-dao/src/main/resources/mapper/StoreMapper.xml

  - fix:自动发起闭店申请定时任务

  - feat:火码账号关闭

  - fix:闭店流程修改

  - Merge branch 'master' into cc_20250922_closeStore_w
    
    # Conflicts:
    #	coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
    #	coolstore-partner-web/src/main/java/com/cool/store/controller/webb/OpenApiController.java

  - fix:删除云流水发起闭店接口

  - fix:取消闭店申请入参修改

  - fix:闭店申请列表赋值异常问题

  - fix:闭店审批通过异常

  - fix:普通方法参数校验

  - fix:账号关闭时校验阶段状态

  - fix:初始化

  - fix:字段新增

  - fix:接口补充

  - fix

  - Merge branch 'refs/heads/master' into cc_20250922_closeStore_w
    
    # Conflicts:
    #	coolstore-partner-common/src/main/java/com/cool/store/constants/RedisConstant.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqGroupEnum.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/RocketMqTagEnum.java
    #	coolstore-partner-web/src/main/java/com/cool/store/controller/webb/OpenApiController.java
    #	coolstore-partner-web/src/main/java/com/cool/store/controller/webc/TestController.java

  - Merge branch 'refs/heads/master' into cc_20250922_closeStore_w
    
    # Conflicts:
    #	coolstore-partner-common/src/main/java/com/cool/store/common/InsertGroup.java
    #	coolstore-partner-common/src/main/java/com/cool/store/common/UpdateGroup.java
    #	coolstore-partner-common/src/main/java/com/cool/store/enums/ErrorCodeEnum.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/dao/StoreDao.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/dao/dict/SysDictColumnDAO.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/mapper/StoreMapper.java
    #	coolstore-partner-dao/src/main/java/com/cool/store/mapper/dict/SysDictColumnMapper.java
    #	coolstore-partner-dao/src/main/resources/mapper/StoreMapper.xml
    #	coolstore-partner-dao/src/main/resources/mapper/dict/SysDictColumnMapper.xml
    #	coolstore-partner-web/src/main/java/com/cool/store/controller/webb/DictManagerController.java
    #	coolstore-partner-web/src/main/java/com/cool/store/job/XxlJobHandler.java

  - fix:闭店流程修改

  - fix:闭店流程修改

  - fix:修改三方付款状态接口

  - fix:闭店申请测试接口

Signed-off-by: 王非凡 <accounts_67eba0c5fee9c49c80c8e2b4@mail.teambition.com>
Reviewed-by: 苏竹红 <accounts_68551bf01395375227aee211@mail.teambition.com>
Merged-by: 苏竹红 <accounts_68551bf01395375227aee211@mail.teambition.com>

CR-link: https://codeup.aliyun.com/692ea314dec569489f6f167c/hangzhou/java/custom_zxjp/change/8
This commit is contained in:
王非凡
2025-12-09 08:55:47 +00:00
committed by 苏竹红
parent 1b0fb1b034
commit 4be2276287
142 changed files with 8144 additions and 20 deletions

View File

@@ -1,6 +1,7 @@
package com.cool.store.service;
import com.cool.store.request.OrderSummaryRequest;
import com.cool.store.request.huoma.AccountCloseRequest;
import com.cool.store.request.huoma.ShopBasicInfoRequest;
import com.cool.store.response.IncomeBaseResponse;
import com.cool.store.response.IncomeSummaryResponse;
@@ -53,4 +54,11 @@ public interface HuoMaService {
* @description:获取店铺交易分析
*/
IncomeSummaryResponse getIncomeSummary (OrderSummaryRequest requestBody);
/**
* 账号关闭
* @param requestBody 火码账号关闭Request
* @return 火码账号关闭Response
*/
Boolean accountClose(AccountCloseRequest requestBody);
}

View File

@@ -0,0 +1,60 @@
package com.cool.store.service;
import com.cool.store.dto.xgj.XgjBranchBankDTO;
import com.cool.store.dto.xgj.XgjPartnerPageDTO;
import com.cool.store.dto.xgj.XgjPayResultDTO;
import com.cool.store.request.xgj.*;
import java.util.List;
/**
* <p>
* 新管家三方接口服务类
* </p>
*
* @author wangff
* @since 2025/11/28
*/
public interface ThirdXgjService {
/**
* 新管家账号关闭
* @param request 新管家账号关闭Request
* @return 是否成功
*/
String accountClose(XgjAccountCloseRequest request);
/**
* 新管家报销单
* @param request 新管家报销单Request
* @return 每刻单号
*/
String reimburse(XgjReimburseRequest request);
/**
* 新管家供应商同步
* @param request 新管家同步供应商Request
* @return java.lang.String
*/
String savePartner(XgjSavePartnerRequest request);
/**
* 获取单据支付结果
* @param request 新管家获取单据支付结果Request
* @return 新管家单据支付结果DTO
*/
XgjPayResultDTO queryOrderStatus(XgjPaymentRequest request);
/**
* 查询往来单位列表
* @param request 新管家往来单位查询Request
* @return 新管家分页DTO
*/
XgjPartnerPageDTO queryPartnerPage(XgjPartnerQueryRequest request);
/**
* 查询支行列表
* @return 新管家支行列表
*/
List<XgjBranchBankDTO> queryBranchBankList(XgjBankQueryRequest request);
}

View File

@@ -0,0 +1,34 @@
package com.cool.store.service.close;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* 账号关闭工厂
* </p>
*
* @author wangff
* @since 2025/10/8
*/
@Service
@RequiredArgsConstructor
public class AccountCloseFactory {
private final Map<String, AccountCloseStrategy> map = new HashMap<>();
@Autowired
public AccountCloseFactory(AccountCloseStrategy[] accountCloseStrategies) {
for (AccountCloseStrategy accountCloseStrategy : accountCloseStrategies) {
map.put(accountCloseStrategy.getSystemCode(), accountCloseStrategy);
}
}
public AccountCloseStrategy getByCode(String systemCode) {
return map.get(systemCode);
}
}

View File

@@ -0,0 +1,23 @@
package com.cool.store.service.close;
/**
* <p>
* 账号关闭
* </p>
*
* @author wangff
* @since 2025/10/8
*/
public interface AccountCloseStrategy {
/**
* 申请账号关闭
* @return 是否成功
*/
Boolean accountClose(String storeId);
/**
* 获取系统code
*/
String getSystemCode();
}

View File

@@ -0,0 +1,36 @@
package com.cool.store.service.close;
import com.cool.store.vo.close.account.CloseStoreAccountVO;
import java.util.List;
/**
* <p>
* 闭店账号关闭 服务类
* </p>
*
* @author wangff
* @since 2025/10/8
*/
public interface CloseStoreAccountService {
/**
* 查询账号列表
* @param closeStoreId 闭店申请id
* @return 闭店账号VO列表
*/
List<CloseStoreAccountVO> getAccountList(Long closeStoreId);
/**
* 账号关闭
* @param id 主键id
* @return 是否成功
*/
Boolean closeAccount(Long id);
/**
* 校验所有账号关闭状态并更新阶段
* @param closeStoreId 闭店申请id
*/
void verifyAndUpdateStage(Long closeStoreId);
}

View File

@@ -0,0 +1,72 @@
package com.cool.store.service.close;
import com.cool.store.request.close.file.*;
import com.cool.store.vo.close.file.CloseStoreFileDetailMiniVO;
import com.cool.store.vo.close.file.CloseStoreFileDetailVO;
/**
* <p>
* 闭店资料 服务类
* </p>
*
* @author wangff
* @since 2025/10/7
*/
public interface CloseStoreFileService {
/**
* 更新材料邮寄地址
* @param request 闭店资料邮寄地址信息Request
* @return 是否成功
*/
Boolean updateMailAddress(CloseStoreMailAddressRequest request);
/**
* 提交材料审批
* @param request 闭店材料审批Request
* @return 是否成功
*/
Boolean submitFileApprove(CloseStoreFileApproveRequest request);
/**
* 单个材料提交审批
* @param request 闭店材料信息Request
* @return 是否成功
*/
Boolean submitFileApproveSingle(CloseStoreFileInfoRequest request);
/**
* 查询闭店资料详情
* @param closeStoreId 闭店申请id
* @return 闭店资料详情VO
*/
CloseStoreFileDetailVO getFileDetail(Long closeStoreId);
/**
* 查询小程序闭店资料详情
* @param closeStoreId 闭店申请id
* @return 小程序闭店资料详情VO
*/
CloseStoreFileDetailMiniVO getMiniFileDetail(Long closeStoreId);
/**
* 提交材料
* @param request 闭店资料邮寄信息Request
* @return 是否成功
*/
Boolean submitFile(CloseStoreMailInfoRequest request);
/**
* 修改材料
* @param request 闭店材料提交Request
* @return 是否成功
*/
Boolean updateFile(CloseStoreFileSubmitRequest request);
/**
* 督导审批
* @param request 审批Request
* @return 是否成功
*/
Boolean supervisionAudit(CloseStoreFileAuditRequest request);
}

View File

@@ -0,0 +1,82 @@
package com.cool.store.service.close;
import com.cool.store.dto.close.CloseStoreMkUserDTO;
import com.cool.store.request.close.refund.CloseStoreRefundAddRequest;
import com.cool.store.request.close.refund.CloseStoreRefundQueryRequest;
import com.cool.store.request.close.refund.CloseStoreRefundSkipRequest;
import com.cool.store.request.close.refund.CloseStoreRefundUpdateRequest;
import com.cool.store.vo.close.refund.CloseStoreRefundDetailVO;
import com.cool.store.vo.close.refund.CloseStoreRefundListVO;
import com.cool.store.vo.close.refund.CloseStoreRefundSimpleVO;
import com.github.pagehelper.PageInfo;
import java.util.Date;
import java.util.List;
/**
* <p>
* 闭店退款 服务类
* </p>
*
* @author wangff
* @since 2025/10/13
*/
public interface CloseStoreRefundService {
/**
* 新增退款记录
* @param request 闭店退款新增Request
*/
Boolean addRefund(CloseStoreRefundAddRequest request);
/**
* 编辑退款记录
* @param request 闭店退款更新Request
*/
Boolean updateRefund(CloseStoreRefundUpdateRequest request);
/**
* 获取当前用户的每刻用户信息
* @return 每刻用户信息DTO
*/
CloseStoreMkUserDTO getCurrentMkUser();
/**
* 查询退款详情
* @param id 退款信息id
* @return 闭店退款详情VO
*/
CloseStoreRefundDetailVO getRefundDetail(Long id);
/**
* 完成退款
*/
void completeRefund(Long refundId, Date refundTime);
/**
* 查询退款简单信息列表
* @param closeStoreId 闭店申请id
* @return 闭店退款简单信息VO列表
*/
List<CloseStoreRefundSimpleVO> getRefundSimpleList(Long closeStoreId);
/**
* 跳过流程
* @param request 退款流程跳过Request
*/
void skip(CloseStoreRefundSkipRequest request);
/**
* 退款分页查询
* @param request 闭店退款查询Request
* @return 闭店退款列表VO列表
*/
PageInfo<CloseStoreRefundListVO> refundPage(CloseStoreRefundQueryRequest request);
/**
* 刷新退款订单状态
* @param request 闭店退款查询Request
* @return 是否成功
*/
Boolean refreshRefundOrderStatus(CloseStoreRefundQueryRequest request);
}

View File

@@ -0,0 +1,130 @@
package com.cool.store.service.close;
import com.cool.store.enums.close.CloseStoreSubStageEnum;
import com.cool.store.request.close.store.*;
import com.cool.store.response.AuditInfoResponse;
import com.cool.store.vo.close.store.*;
import com.github.pagehelper.PageInfo;
import java.util.List;
/**
* @Author suzhuhong
* @Date 2025/9/23 15:48
* @Version 1.0
*/
public interface CloseStoreService {
/**
* 申请闭店
* @param request 闭店申请Request
* @return 是否成功
*/
Boolean applyCloseStore(CloseStoreApplyRequest request);
/**
* 拒绝之后 重新提交申请
* @param request 闭店申请Request
* @return 是否成功
*/
Boolean reApplyCloseStore(ReCloseStoreApplyRequest request);
/**
* 第三方申请闭店
* @param request 三方闭店申请Request
* @return 是否成功
*/
Boolean thirdApplyCloseStore(ThirdCloseStoreApplyRequest request);
/**
* 审批通过
* @param request 闭店申请审批Request
* @return 是否成功
*/
Boolean auditPass(CloseStoreAuditRequest request);
/**
* 审批拒绝
* @param request 闭店申请审批Request
* @return 是否成功
*/
Boolean auditReject(CloseStoreAuditRequest request);
/**
* 取消闭店申请
* @param closeStoreId 闭店申请id
* @return 是否成功
*/
Boolean cancelApply(Long closeStoreId);
/**
* 查询权限下的闭店申请审批记录
* @param request 闭店申请查询Request
* @return 闭店申请记录列表VO列表
*/
PageInfo<CloseStoreInfoListVO> closeStoreAuditList(CloseStoreQueryRequest request);
/**
* 查询闭店申请列表
* @param request 闭店申请查询Request
* @return 闭店申请记录列表VO列表
*/
PageInfo<CloseStoreInfoListVO> closeStoreInfoList(CloseStoreQueryRequest request);
/**
* 查询闭店审批记录
* @param closeStoreId 闭店申请id
* @return 审批记录VO列表
*/
List<AuditInfoResponse> getAuditRecordList(Long closeStoreId);
/**
* 获取闭店申请详情
* @param closeStoreId 闭店申请id
* @return 闭店申请详情VO
*/
CloseStoreInfoDetailVO getCloseStoreInfoDetail(Long closeStoreId, Boolean queryAuditId);
/**
* 根据审批id获取闭店申请详情
* @param closeStoreAuditId 审批id
* @return 闭店申请详情VO
*/
CloseStoreInfoDetailVO getCloseStoreInfoDetailByAuditId(Long closeStoreAuditId);
/**
* 闭店原因列表
* @param closeType 闭店发起方式
* @return 门店闭店原因VO
*/
List<StoreCloseReasonVO> getStoreCloseReasonList(Integer closeType);
/**
* 获取闭店申请简单信息
* @param closeStoreId 闭店申请id
* 闭店申请简单信息VO
*/
CloseStoreSimpleVO getCloseStoreSimpleInfo(Long closeStoreId);
/**
* mini分页查询
* @param request 查询参数
* @return mini闭店申请简单信息VO
*/
PageInfo<MiniCloseStoreSimpleVO> getMiniCloseStoreSimpleInfoList(MiniCloseStoreQueryRequest request);
/**
* 获取闭店状态列表
* @return 闭店状态列表
*/
List<CloseStoreStatusVO> getCloseStoreStatusList();
/**
* 闭店流程流转
* @param closeStoreId 闭店申请id
* @param currentStage 当前阶段
*/
void closeStoreProcessFlow(Long closeStoreId, CloseStoreSubStageEnum currentStage);
}

View File

@@ -0,0 +1,37 @@
package com.cool.store.service.close.impl;
import com.cool.store.dao.StoreDao;
import com.cool.store.entity.StoreDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.service.close.AccountCloseStrategy;
import javax.annotation.Resource;
import java.util.Objects;
/**
* <p>
* 账号关闭
* </p>
*
* @author wangff
* @since 2025/10/8
*/
public abstract class AbstractAccountClose implements AccountCloseStrategy {
@Resource
private StoreDao storeDao;
@Override
public Boolean accountClose(String storeId) {
// 各平台待对接
return true;
}
protected StoreDO getStore(String storeId) {
StoreDO storeDO = storeDao.getByStoreId(storeId);
if (Objects.isNull(storeDO)) {
throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND);
}
return storeDO;
}
}

View File

@@ -0,0 +1,80 @@
package com.cool.store.service.close.impl;
import com.cool.store.dao.CloseStoreAccountInfoDAO;
import com.cool.store.dao.CloseStoreInfoDAO;
import com.cool.store.dao.CloseStoreStageInfoDAO;
import com.cool.store.entity.CloseStoreAccountInfoDO;
import com.cool.store.entity.CloseStoreInfoDO;
import com.cool.store.enums.close.*;
import com.cool.store.service.close.AccountCloseFactory;
import com.cool.store.service.close.AccountCloseStrategy;
import com.cool.store.service.close.CloseStoreAccountService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.vo.close.account.CloseStoreAccountVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 闭店账号关闭 服务实现类
* </p>
*
* @author wangff
* @since 2025/10/8
*/
@Service
@RequiredArgsConstructor
public class CloseStoreAccountServiceImpl implements CloseStoreAccountService {
private final CloseStoreAccountInfoDAO closeStoreAccountInfoDAO;
private final AccountCloseFactory accountCloseFactory;
private final CloseStoreStageInfoDAO closeStoreStageInfoDAO;
private final CloseStoreService closeStoreService;
private final CloseStoreInfoDAO closeStoreInfoDAO;
@Override
public List<CloseStoreAccountVO> getAccountList(Long closeStoreId) {
List<CloseStoreAccountInfoDO> list = closeStoreAccountInfoDAO.getByCloseStoreId(closeStoreId);
return BeanUtil.toList(list, CloseStoreAccountVO.class);
}
@Override
public Boolean closeAccount(Long id) {
CloseStoreAccountInfoDO accountInfo = closeStoreAccountInfoDAO.getById(id);
if (Objects.nonNull(accountInfo)) {
closeStoreStageInfoDAO.verifyStage(accountInfo.getCloseStoreId(), CloseStoreStageEnum.CLOSE_STORE_STAGE_2, CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_20, CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_25);
if (AccountCloseTypeEnum.APPLY_CLOSE.getType().equals(accountInfo.getCloseType())) {
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(accountInfo.getCloseStoreId());
// 申请关闭
AccountCloseStrategy accountClose = accountCloseFactory.getByCode(accountInfo.getSystemCode());
if (Objects.nonNull(accountClose) && accountClose.accountClose(closeStoreInfoDO.getStoreId())) {
closeStoreAccountInfoDAO.updateStatus(id, CloseStoreAccountStatusEnum.CLOSED.getStatus());
verifyAndUpdateStage(accountInfo.getCloseStoreId());
return true;
}
} else {
// 直接关闭
closeStoreAccountInfoDAO.updateStatus(id, CloseStoreAccountStatusEnum.CLOSED.getStatus());
verifyAndUpdateStage(accountInfo.getCloseStoreId());
return true;
}
}
return false;
}
@Override
public void verifyAndUpdateStage(Long closeStoreId) {
if (!closeStoreAccountInfoDAO.existNotCloseAccount(closeStoreId)) {
// 所有账号已关闭,校验当前阶段
CloseStoreStageEnum currentStage = CloseStoreStageEnum.CLOSE_STORE_STAGE_2;
CloseStoreSubStageEnum currentSubStage = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_20;
CloseStoreSubStageStatusEnum currentExpectedSubStageStatus = CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_25;
closeStoreStageInfoDAO.verifyStage(closeStoreId, currentStage, currentSubStage, currentExpectedSubStageStatus);
// 流程流转
closeStoreService.closeStoreProcessFlow(closeStoreId, currentSubStage);
}
}
}

View File

@@ -0,0 +1,211 @@
package com.cool.store.service.close.impl;
import com.cool.store.constants.CommonConstants;
import com.cool.store.constants.RedisConstant;
import com.cool.store.dao.CloseStoreFileDetailDAO;
import com.cool.store.dao.CloseStoreFileInfoDAO;
import com.cool.store.dao.CloseStoreStageInfoDAO;
import com.cool.store.entity.CloseStoreFileInfoDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.close.*;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.close.file.*;
import com.cool.store.entity.CloseStoreFileDetailDO;
import com.cool.store.service.close.CloseStoreFileService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.vo.close.file.CloseStoreFileDetailMiniVO;
import com.cool.store.vo.close.file.CloseStoreFileDetailVO;
import com.cool.store.vo.close.file.CloseStoreFileInfoVO;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;
import static com.cool.store.enums.close.CloseStoreSubStageStatusEnum.*;
/**
* <p>
* 闭店资料 服务实现类
* </p>
*
* @author wangff
* @since 2025/10/7
*/
@Service
@RequiredArgsConstructor
public class CloseStoreFileServiceImpl implements CloseStoreFileService {
private final CloseStoreFileDetailDAO closeStoreFileDetailDAO;
private final CloseStoreFileInfoDAO closeStoreFileInfoDAO;
private final CloseStoreStageInfoDAO closeStoreStageInfoDAO;
private final CloseStoreService closeStoreService;
private final RedisUtilPool redisUtilPool;
private static final CloseStoreStageEnum STAGE = CloseStoreStageEnum.CLOSE_STORE_STAGE_1;
private static final CloseStoreSubStageEnum SUB_STAGE = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_10;
@Override
@Transactional
public Boolean updateMailAddress(CloseStoreMailAddressRequest request) {
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), STAGE, SUB_STAGE, CLOSE_STORE_SUB_STAGE_STATUS_10);
closeStoreFileDetailDAO.insertOrUpdateMailAddress(request);
closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), SUB_STAGE);
return true;
}
@Override
@Transactional
public Boolean submitFileApprove(CloseStoreFileApproveRequest request) {
// 校验流程是否在材料待审批阶段
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), STAGE, SUB_STAGE, CLOSE_STORE_SUB_STAGE_STATUS_18);
// 修改材料详情
boolean approveCompleted = ListUtils.emptyIfNull(request.getFileList()).stream().allMatch(v -> CommonConstants.INDEX_ONE.equals(v.getApproveStatus()));
closeStoreFileDetailDAO.insertOrUpdateFileInfoSelective(request, approveCompleted);
// 修改所有材料的审批状态
if (CollectionUtils.isNotEmpty(request.getFileList())) {
List<CloseStoreFileInfoDO> fileList = BeanUtil.toList(request.getFileList(), CloseStoreFileInfoDO.class);
closeStoreFileInfoDAO.updateBatch(fileList);
}
// 全部材料合格,流程流转
if (approveCompleted) {
closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), SUB_STAGE);
}
return true;
}
@Override
@Transactional
public Boolean submitFileApproveSingle(CloseStoreFileInfoRequest request) {
// 校验流程是否在材料待审批阶段
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), STAGE, SUB_STAGE, CLOSE_STORE_SUB_STAGE_STATUS_18);
// 更新其他字段
updateFileField(request);
// 更新材料审批信息
CloseStoreFileInfoDO updateFileInfoDO = CloseStoreFileInfoDO.builder()
.id(request.getId())
.approveStatus(request.getApproveStatus())
.mailStatus(request.getMailStatus())
.approveOpinion(request.getApproveOpinion())
.urls(request.getUrls())
.build();
closeStoreFileInfoDAO.updateSelective(updateFileInfoDO);
// 校验所有材料是否审批完成,完成后流程流转
verifyComplete(request);
return true;
}
/**
* 校验所有材料是否全部完成邮寄和审批完成
*/
private void verifyComplete(CloseStoreFileInfoRequest request) {
List<CloseStoreFileInfoDO> fileList = closeStoreFileInfoDAO.getByCloseStoreId(request.getCloseStoreId());
boolean completeApprove = fileList.stream().allMatch(v -> Objects.nonNull(v.getApproveStatus()) && CommonConstants.INDEX_ONE.equals(v.getMailStatus()));
if (completeApprove) {
closeStoreFileDetailDAO.insertOrUpdateFileInfoSelective(CloseStoreFileApproveRequest.builder().closeStoreId(request.getCloseStoreId()).build(), true);
boolean pass = fileList.stream().allMatch(v -> CommonConstants.INDEX_ONE.equals(v.getApproveStatus()));
// 更新材料状态为审批状态
closeStoreFileInfoDAO.updateFileStatusToApproveStatus(request.getCloseStoreId());
if (pass) {
closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), SUB_STAGE);
} else {
closeStoreStageInfoDAO.updateSubStageStatus(request.getCloseStoreId(), CLOSE_STORE_SUB_STAGE_STATUS_19);
}
}
}
/**
* 更新其他字段
*/
private void updateFileField(CloseStoreFileInfoRequest request) {
CloseStoreFileInfoDO fileInfoDO = closeStoreFileInfoDAO.getById(request.getId());
if (Objects.isNull(fileInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_FILE_NOT_EXIST);
}
if (CloseStoreFileEnum.TKD.getCode().equals(fileInfoDO.getFileCode())) {
boolean f = Stream.of(request.getBankAccount(), request.getBankOpening(), request.getRefundAccount()).anyMatch(StringUtils::isNotBlank);
if (f) {
CloseStoreFileApproveRequest approveRequest = CloseStoreFileApproveRequest.builder()
.closeStoreId(request.getCloseStoreId())
.bankAccount(request.getBankAccount())
.bankOpening(request.getBankOpening())
.refundAccount(request.getRefundAccount())
.build();
closeStoreFileDetailDAO.insertOrUpdateFileInfoSelective(approveRequest, false);
}
}
}
@Override
public CloseStoreFileDetailVO getFileDetail(Long closeStoreId) {
CloseStoreFileDetailDO fileDetailDO = closeStoreFileDetailDAO.getByCloseStoreId(closeStoreId);
CloseStoreFileDetailVO detailVO = BeanUtil.toBean(fileDetailDO, CloseStoreFileDetailVO.class);
List<CloseStoreFileInfoDO> fileList = closeStoreFileInfoDAO.getByCloseStoreId(closeStoreId);
List<CloseStoreFileInfoVO> fileVOList = BeanUtil.toList(fileList, CloseStoreFileInfoVO.class);
detailVO.setFileList(fileVOList);
return detailVO;
}
@Override
public CloseStoreFileDetailMiniVO getMiniFileDetail(Long closeStoreId) {
CloseStoreFileDetailVO fileDetail = getFileDetail(closeStoreId);
CloseStoreFileDetailMiniVO result = BeanUtil.toBean(fileDetail, CloseStoreFileDetailMiniVO.class);
if (CollectionUtils.isNotEmpty(result.getFileList())) {
result.getFileList().forEach(v -> v.setTemplateUrl(redisUtilPool.hashGet(RedisConstant.CLOSE_STORE_FILE_TEMPLATE, v.getFileCode())));
}
return result;
}
@Override
@Transactional
public Boolean submitFile(CloseStoreMailInfoRequest request) {
// 校验流程是否在材料待上传阶段
CloseStoreSubStageStatusEnum[] conditions = {CLOSE_STORE_SUB_STAGE_STATUS_15, CLOSE_STORE_SUB_STAGE_STATUS_17, CLOSE_STORE_SUB_STAGE_STATUS_19};
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), STAGE, SUB_STAGE, conditions);
// 修改邮寄信息
closeStoreFileDetailDAO.insertOrUpdateMailInfo(request, true);
// 校验所有材料是否上传完成,完成后流程流转
List<CloseStoreFileInfoDO> files = closeStoreFileInfoDAO.getByCloseStoreId(request.getCloseStoreId());
List<Integer> verifyList = Arrays.asList(FileStatusEnum.UPLOADED.getStatus(), FileStatusEnum.MODIFIED.getStatus(), FileStatusEnum.QUALIFIED.getStatus());
boolean verify = files.stream().allMatch(v -> verifyList.contains(v.getFileStatus()));
if (verify) {
closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), SUB_STAGE);
}
return true;
}
@Override
public Boolean updateFile(CloseStoreFileSubmitRequest request) {
CloseStoreSubStageStatusEnum[] conditions = {CLOSE_STORE_SUB_STAGE_STATUS_15, CLOSE_STORE_SUB_STAGE_STATUS_17, CLOSE_STORE_SUB_STAGE_STATUS_19};
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), STAGE, SUB_STAGE, conditions);
return closeStoreFileInfoDAO.updateFile(request.getId(), request.getUrls());
}
@Override
@Transactional
public Boolean supervisionAudit(CloseStoreFileAuditRequest request) {
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), STAGE, SUB_STAGE, CLOSE_STORE_SUB_STAGE_STATUS_16);
if (CommonConstants.INDEX_ONE.equals(request.getStatus())) {
// 所有资料状态改为审批中
closeStoreFileInfoDAO.updateAllFileStatus(request.getCloseStoreId());
// 流程流转
closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), SUB_STAGE);
} else {
// 修改督导审批意见
closeStoreFileDetailDAO.updateByCloseStoreIdSelective(CloseStoreFileDetailDO.builder().closeStoreId(request.getCloseStoreId()).remark(request.getRemark()).build());
// 修改阶段状态
closeStoreStageInfoDAO.updateSubStageStatus(request.getCloseStoreId(), CLOSE_STORE_SUB_STAGE_STATUS_17);
}
return true;
}
}

View File

@@ -0,0 +1,225 @@
package com.cool.store.service.close.impl;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.RedisConstant;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dao.*;
import com.cool.store.dto.close.CloseStoreMkUserDTO;
import com.cool.store.dto.xgj.XgjPayResultDTO;
import com.cool.store.entity.CloseStoreInfoDO;
import com.cool.store.entity.CloseStoreRefundInfoDO;
import com.cool.store.entity.EnterpriseUserDO;
import com.cool.store.entity.StoreDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.close.CloseStoreSubStageEnum;
import com.cool.store.enums.close.CloseStoreSubStageStatusEnum;
import com.cool.store.enums.close.RefundPayStatusEnum;
import com.cool.store.enums.close.XgjRefundPayStatusEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.close.refund.CloseStoreRefundAddRequest;
import com.cool.store.request.close.refund.CloseStoreRefundQueryRequest;
import com.cool.store.request.close.refund.CloseStoreRefundSkipRequest;
import com.cool.store.request.close.refund.CloseStoreRefundUpdateRequest;
import com.cool.store.request.xgj.XgjPaymentRequest;
import com.cool.store.request.xgj.XgjReimburseRequest;
import com.cool.store.service.ThirdXgjService;
import com.cool.store.service.close.CloseStoreRefundService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.service.dict.impl.DictService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.RedisUtilPool;
import com.cool.store.vo.close.refund.CloseStoreRefundDetailVO;
import com.cool.store.vo.close.refund.CloseStoreRefundListVO;
import com.cool.store.vo.close.refund.CloseStoreRefundSimpleVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* <p>
* 闭店退款 服务实现类
* </p>
*
* @author wangff
* @since 2025/10/13
*/
@Service
@RequiredArgsConstructor
public class CloseStoreRefundServiceImpl implements CloseStoreRefundService {
private final CloseStoreRefundInfoDAO closeStoreRefundInfoDAO;
private final CloseStoreInfoDAO closeStoreInfoDAO;
private final CloseStoreStageInfoDAO closeStoreStageInfoDAO;
private final CloseStoreService closeStoreService;
private final StoreDao storeDao;
private final RedisUtilPool redisUtilPool;
private final ThirdXgjService thirdXgjService;
private final EnterpriseUserDAO enterpriseUserDAO;
private final DictService dictService;
@Override
public Boolean addRefund(CloseStoreRefundAddRequest request) {
if (!CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.getCloseStoreSubStage().equals(request.getType())
&& !CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_40.getCloseStoreSubStage().equals(request.getType())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_TYPE_ERROR);
}
CloseStoreMkUserDTO mkUser = getCurrentMkUser();
// 校验是否有每刻权限
if (Objects.isNull(mkUser)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_MK_USER_NOT_EXIST);
}
// 是否存在非作废状态的记录,则不能新增
if (closeStoreRefundInfoDAO.existEffectiveRecord(request.getCloseStoreId(), request.getType())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_EXIST_EFFECTIVE_RECORD);
}
CloseStoreInfoDO closeStoreInfo = closeStoreInfoDAO.getById(request.getCloseStoreId());
if (Objects.isNull(closeStoreInfo)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
StoreDO storeDO = storeDao.getByStoreId(closeStoreInfo.getStoreId());
if (Objects.isNull(storeDO)) {
throw new ServiceException(ErrorCodeEnum.STORE_NOT_FIND);
}
CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(request.getType());
CloseStoreSubStageStatusEnum expectedStageStatus = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.equals(subStage) ? CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_35 : CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_45;
assert subStage != null;
// 校验阶段状态
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), subStage.getCloseStoreStageEnum(), subStage, expectedStageStatus);
CloseStoreRefundInfoDO refundInfoDO = BeanUtil.toBean(request, CloseStoreRefundInfoDO.class);
refundInfoDO.setRefundNo(generateCloseStoreNo());
// 提交新管家
XgjReimburseRequest xgjReimburseRequest = request.convertToXgjRequest(mkUser, closeStoreInfo.getCloseReason(), storeDO);
String orderNo = thirdXgjService.reimburse(xgjReimburseRequest);
refundInfoDO.setRefundOrderNo(orderNo);
refundInfoDO.setRefundStatus(RefundPayStatusEnum.APPROVING.getStatus());
refundInfoDO.setSubmitterId(StringUtils.isNotBlank(refundInfoDO.getSubmitterId()) ? refundInfoDO.getSubmitterId() : mkUser.getJobnumber());
refundInfoDO.setSubmitterName(StringUtils.isNotBlank(refundInfoDO.getSubmitterName()) ? refundInfoDO.getSubmitterName() : mkUser.getName());
return closeStoreRefundInfoDAO.insertSelective(refundInfoDO);
}
@Override
public Boolean updateRefund(CloseStoreRefundUpdateRequest request) {
CloseStoreMkUserDTO mkUser = getCurrentMkUser();
// 校验是否有每刻权限
if (Objects.isNull(mkUser)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_MK_USER_NOT_EXIST);
}
CloseStoreRefundInfoDO old = closeStoreRefundInfoDAO.getById(request.getId());
if (Objects.isNull(old)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_REFUND_INFO_NOT_EXIST);
}
CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(old.getType());
CloseStoreSubStageStatusEnum expectedStageStatus = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.equals(subStage) ? CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_35 : CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_45;
assert subStage != null;
// 校验阶段状态
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), subStage.getCloseStoreStageEnum(), subStage, expectedStageStatus);
CloseStoreRefundInfoDO refundInfoDO = BeanUtil.toBean(request, CloseStoreRefundInfoDO.class);
refundInfoDO.setSubmitterId(StringUtils.isNotBlank(refundInfoDO.getSubmitterId()) ? refundInfoDO.getSubmitterId() : mkUser.getJobnumber());
refundInfoDO.setSubmitterName(StringUtils.isNotBlank(refundInfoDO.getSubmitterName()) ? refundInfoDO.getSubmitterName() : mkUser.getName());
return closeStoreRefundInfoDAO.updateSelective(refundInfoDO);
}
@Override
public CloseStoreMkUserDTO getCurrentMkUser() {
EnterpriseUserDO user = enterpriseUserDAO.getUserInfoById(CurrentUserHolder.getUserId());
String mkUserStr = redisUtilPool.hashGet(RedisConstant.MK_USER_MAPPING, user.getJobnumber());
if (StringUtils.isNotBlank(mkUserStr)) {
return JSONObject.parseObject(mkUserStr, CloseStoreMkUserDTO.class);
}
return null;
}
@Override
public CloseStoreRefundDetailVO getRefundDetail(Long id) {
CloseStoreRefundInfoDO refundInfoDO = closeStoreRefundInfoDAO.getById(id);
if (Objects.nonNull(refundInfoDO)) {
CloseStoreRefundDetailVO vo = BeanUtil.toBean(refundInfoDO, CloseStoreRefundDetailVO.class);
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(refundInfoDO.getCloseStoreId());
if (Objects.nonNull(closeStoreInfoDO)) {
vo.setCloseReason(closeStoreInfoDO.getCloseReason());
}
dictService.fillDictField(vo);
return vo;
}
return null;
}
@Override
@Transactional
public void completeRefund(Long refundId, Date refundTime) {
CloseStoreRefundInfoDO refundInfoDO = closeStoreRefundInfoDAO.getById(refundId);
if (Objects.nonNull(refundInfoDO) && !RefundPayStatusEnum.PAY_SUCCESS.getStatus().equals(refundInfoDO.getRefundStatus())) {
CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(refundInfoDO.getType());
if (Objects.nonNull(subStage)) {
// 修改退款状态
closeStoreRefundInfoDAO.updateRefundStatus(refundId, RefundPayStatusEnum.PAY_SUCCESS.getStatus(), refundTime);
// 流程流转
closeStoreService.closeStoreProcessFlow(refundInfoDO.getCloseStoreId(), subStage);
}
}
}
@Override
public List<CloseStoreRefundSimpleVO> getRefundSimpleList(Long closeStoreId) {
List<CloseStoreRefundInfoDO> list = closeStoreRefundInfoDAO.getListByCloseStoreId(closeStoreId, null);
return BeanUtil.toList(list, CloseStoreRefundSimpleVO.class);
}
@Override
@Transactional
public void skip(CloseStoreRefundSkipRequest request) {
CloseStoreSubStageEnum subStage = CloseStoreSubStageEnum.getSubStageByStage(request.getType());
CloseStoreSubStageStatusEnum expectedStageStatus = CloseStoreSubStageEnum.CLOSE_STORE_SUB_STAGE_30.equals(subStage) ? CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_35 : CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_45;
assert subStage != null;
closeStoreStageInfoDAO.verifyStage(request.getCloseStoreId(), subStage.getCloseStoreStageEnum(), subStage, expectedStageStatus);
// 流程流转
closeStoreService.closeStoreProcessFlow(request.getCloseStoreId(), subStage);
}
@Override
public PageInfo<CloseStoreRefundListVO> refundPage(CloseStoreRefundQueryRequest request) {
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<CloseStoreRefundInfoDO> list = closeStoreRefundInfoDAO.getListByCloseStoreId(request.getCloseStoreId(), request.getType());
PageInfo<CloseStoreRefundInfoDO> page = new PageInfo<>(list);
return BeanUtil.toPage(page, CloseStoreRefundListVO.class);
}
@Override
public Boolean refreshRefundOrderStatus(CloseStoreRefundQueryRequest request) {
List<CloseStoreRefundInfoDO> list = closeStoreRefundInfoDAO.getListByCloseStoreId(request.getCloseStoreId(), request.getType());
List<CloseStoreRefundInfoDO> updateList = new ArrayList<>();
for (CloseStoreRefundInfoDO refundInfoDO : list) {
if (StringUtils.isNotBlank(refundInfoDO.getRefundOrderNo())) {
XgjPayResultDTO xgjPayResultDTO = thirdXgjService.queryOrderStatus(new XgjPaymentRequest(refundInfoDO.getRefundOrderNo()));
String xgjStatus = xgjPayResultDTO.getStatus();
String refundStatus = XgjRefundPayStatusEnum.REJECTED.getStatus().equals(xgjStatus) ? RefundPayStatusEnum.APPROVING.getStatus() : xgjStatus;
if (!refundInfoDO.getRefundStatus().equals(refundStatus)) {
updateList.add(CloseStoreRefundInfoDO.builder().id(refundInfoDO.getId()).refundStatus(refundStatus).build());
}
}
}
if (CollectionUtils.isNotEmpty(updateList)) {
closeStoreRefundInfoDAO.updateRefundStatusBatchById(list);
}
return true;
}
/**
* 生成退款申请单号
*/
private String generateCloseStoreNo(){
return "T" + CoolDateUtils.getTodayMillis();
}
}

View File

@@ -0,0 +1,621 @@
package com.cool.store.service.close.impl;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.constants.CommonConstants;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.context.LoginUserInfo;
import com.cool.store.context.PartnerUserHolder;
import com.cool.store.dao.*;
import com.cool.store.dao.store.StoreMasterSignerInfoDAO;
import com.cool.store.dto.store.StoreMasterIssueDTO;
import com.cool.store.entity.*;
import com.cool.store.entity.store.StoreMasterSignerInfoDO;
import com.cool.store.enums.*;
import com.cool.store.enums.close.*;
import com.cool.store.enums.master.StoreCloseReasonEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.mq.producer.SimpleMessageService;
import com.cool.store.request.close.store.*;
import com.cool.store.response.AuditInfoResponse;
import com.cool.store.service.UserAuthMappingService;
import com.cool.store.service.close.CloseStoreService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.poi.StringUtils;
import com.cool.store.vo.PartnerUserInfoVO;
import com.cool.store.vo.close.store.*;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
/**
* @Author suzhuhong
* @Date 2025/9/23 15:48
* @Version 1.0
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class CloseStoreServiceImpl implements CloseStoreService {
private final CloseStoreInfoDAO closeStoreInfoDAO;
private final CloseStoreAuditRecordDAO closeStoreAuditRecordDAO;
private final UserAuthMappingService userAuthMappingService;
private final CloseStoreFileInfoDAO closeStoreFileInfoDAO;
private final CloseStoreFileDetailDAO closeStoreFileDetailDAO;
private final CloseStoreAccountInfoDAO closeStoreAccountInfoDAO;
private final CloseStoreStageInfoDAO closeStoreStageInfoDAO;
private final StoreDao storeDao;
private final RegionDao regionDao;
private final EnterpriseUserRoleDao enterpriseUserRoleDao;
private final StoreMasterSignerInfoDAO storeMasterSignerInfoDAO;
private final SimpleMessageService simpleMessageService;
private final CloseStoreRefundInfoDAO closeStoreRefundInfoDAO;
private final EnterpriseUserDAO enterpriseUserDAO;
@Value("${mybatis.configuration.variables.enterpriseId}")
private String enterpriseId;
@Override
@Transactional
public Boolean applyCloseStore(CloseStoreApplyRequest request) {
// 查询当前当前门店 校验门店状态
StoreDO store = storeDao.getByStoreId(request.getStoreId());
if (store == null){
throw new ServiceException(ErrorCodeEnum.STORE_NOT_EXIST);
}
if (CommonConstants.CLOSED.equals(store.getStoreStatus())){
throw new ServiceException(ErrorCodeEnum.STORE_NOT_OPEN);
}
// 校验是否有正在进行的申请
if (closeStoreInfoDAO.existOngoingRecord(request.getStoreId())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_EXIST_ONGOING_RECORD);
}
RegionDO regionDO = regionDao.getRegionByStoreId(store.getStoreId());
if (Objects.isNull(regionDO)) {
throw new ServiceException(ErrorCodeEnum.REGION_NOT_EXIST);
}
String userId, userName;
if (CloseTypeEnum.INITIATE.getCloseType().equals(request.getCloseType())) {
// 主动发起的申请人为加盟商从C端登录用户信息中获取
PartnerUserInfoVO user = PartnerUserHolder.getUser();
userId = user.getPartnerId();
userName = user.getUsername();
if (StringUtils.isBlank(userName)) {
userName = user.getMobile();
}
} else {
userId = AIEnum.AI_ID.getCode();
userName = AIEnum.AI_NAME.getCode();
}
CloseStoreInfoDO closeStoreInfoDO = new CloseStoreInfoDO();
closeStoreInfoDO.setCloseStoreNo(generateCloseStoreNo());
closeStoreInfoDO.setStoreId(request.getStoreId());
closeStoreInfoDO.setRegionId(regionDO.getId());
closeStoreInfoDO.setPlanCloseData(request.getPlanCloseDate());
closeStoreInfoDO.setCloseType(request.getCloseType());
closeStoreInfoDO.setCloseReason(request.getCloseReason());
closeStoreInfoDO.setReasonDescription(request.getReasonDescription());
closeStoreInfoDO.setCloseStatus(CloseStoreStatusEnum.UNDER_APPROVAL.getCloseStoreStatus());
closeStoreInfoDO.setApplyUserId(userId);
closeStoreInfoDAO.insertSelective(closeStoreInfoDO);
// 查询督导
List<String> auditUserIds = getAuditUserIds(regionDO.getId(), UserRoleEnum.SUPERVISION);
closeStoreAuditRecordDAO.addRecord(closeStoreInfoDO.getId(), userId, userName, auditUserIds);
return Boolean.TRUE;
}
@Override
@Transactional
public Boolean reApplyCloseStore(ReCloseStoreApplyRequest request) {
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(request.getCloseStoreId());
if (Objects.isNull(closeStoreInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
CloseStoreApplyRequest applyRequest = CloseStoreApplyRequest.builder()
.planCloseDate(closeStoreInfoDO.getPlanCloseData())
.closeReason(closeStoreInfoDO.getCloseReason())
.reasonDescription(closeStoreInfoDO.getReasonDescription())
.closeType(closeStoreInfoDO.getCloseType())
.storeId(closeStoreInfoDO.getStoreId())
.build();
return applyCloseStore(applyRequest);
}
@Override
@Transactional
public Boolean thirdApplyCloseStore(ThirdCloseStoreApplyRequest request) {
StoreDO storeDO = storeDao.getByStoreNum(request.getStoreNum());
if (Objects.isNull(storeDO)) {
throw new ServiceException(ErrorCodeEnum.STORE_NOT_EXIST);
}
CloseStoreApplyRequest closeRequest = request.convert(storeDO.getStoreId());
return applyCloseStore(closeRequest);
}
@Override
@Transactional
public Boolean auditPass(CloseStoreAuditRequest request) {
CloseStoreAuditRecordDO auditRecordDO = closeStoreAuditRecordDAO.getById(request.getAuditRecordId());
// 校验审批权限
auditVerify(auditRecordDO);
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(auditRecordDO.getCloseStoreId());
if (Objects.isNull(closeStoreInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
// 修改闭店申请信息
Integer currentCloseStatus = closeStoreInfoDO.getCloseStatus();
Integer nextCloseStatus = CloseStoreStatusEnum.getNextPassStatus(currentCloseStatus);
if (Objects.nonNull(request.getCloseReason())) {
closeStoreInfoDO.setCloseReason(request.getCloseReason());
}
closeStoreInfoDO.setActualCloseData(request.getActualCloseData());
closeStoreInfoDO.setCloseStatus(nextCloseStatus);
closeStoreInfoDAO.updateSelective(closeStoreInfoDO);
// 修改闭店审批信息
auditRecordDO.setAuditStatus(CloseStoreAuditStatusEnum.PASS.getStatus());
auditRecordDO.setActionRemark(request.getRemark());
auditRecordDO.setHandlerUserId(CurrentUserHolder.getUserId());
auditRecordDO.setHandlerUserName(CurrentUserHolder.getUser().getName());
auditRecordDO.setFinishTaskTime(new Date());
closeStoreAuditRecordDAO.updateRecord(auditRecordDO);
// 督导审批结束后为大区经理审批
if (CloseStoreStatusEnum.MANAGER_UNDER_APPROVAL.getCloseStoreStatus().equals(nextCloseStatus)) {
// 新增大区老总审批
List<String> auditUserIds = getAuditUserIds(closeStoreInfoDO.getRegionId(), UserRoleEnum.REGION_MANAGER);
closeStoreAuditRecordDAO.addApproveRecord(closeStoreInfoDO.getId(), auditUserIds);
} else {
// 完成闭店,再进入闭店流程
closeStoreFlowInit(closeStoreInfoDO, closeStoreInfoDO.getStoreId(), closeStoreInfoDO.getCloseReason());
}
return true;
}
@Override
@Transactional
public Boolean auditReject(CloseStoreAuditRequest request) {
CloseStoreAuditRecordDO auditRecordDO = closeStoreAuditRecordDAO.getById(request.getAuditRecordId());
// 校验审批权限
auditVerify(auditRecordDO);
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(auditRecordDO.getCloseStoreId());
if (Objects.isNull(closeStoreInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
closeStoreInfoDO.setCloseStatus(CloseStoreStatusEnum.REVIEW_NOT_APPROVED.getCloseStoreStatus());
closeStoreInfoDAO.updateSelective(closeStoreInfoDO);
// 修改闭店审批信息
auditRecordDO.setAuditStatus(CloseStoreAuditStatusEnum.REJECTED.getStatus());
auditRecordDO.setActionRemark(request.getRemark());
auditRecordDO.setHandlerUserId(CurrentUserHolder.getUserId());
auditRecordDO.setHandlerUserName(CurrentUserHolder.getUser().getName());
auditRecordDO.setFinishTaskTime(new Date());
closeStoreAuditRecordDAO.updateRecord(auditRecordDO);
return true;
}
@Override
@Transactional
public Boolean cancelApply(Long closeStoreId) {
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(closeStoreId);
if (Objects.isNull(closeStoreInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
if (CloseStoreStatusEnum.CANCELED.getCloseStoreStatus().equals(closeStoreInfoDO.getCloseStatus())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_CANCELED);
}
// 未审批前能够取消
if (!CloseStoreStatusEnum.UNDER_APPROVAL.getCloseStoreStatus().equals(closeStoreInfoDO.getCloseStatus())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_CANCEL_ERROR);
}
// 非申请人无法取消
if (!closeStoreInfoDO.getApplyUserId().equals(PartnerUserHolder.getUser().getPartnerId())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_IS_NOT_APPLICANT);
}
// 修改闭店申请信息
closeStoreInfoDO.setCloseStatus(CloseStoreStatusEnum.CANCELED.getCloseStoreStatus());
closeStoreInfoDAO.updateSelective(closeStoreInfoDO);
// 删除待处理的审批记录
closeStoreAuditRecordDAO.deletePendingRecord(closeStoreId);
return true;
}
@Override
public PageInfo<CloseStoreInfoListVO> closeStoreAuditList(CloseStoreQueryRequest request) {
closeStoreRecordQueryBefore(request);
if (Objects.isNull(request.getAuditStatus())) {
request.setAuditStatus(CloseStoreAuditStatusEnum.PENDING.getStatus());
}
LoginUserInfo user = CurrentUserHolder.getUser();
Boolean isAdmin = enterpriseUserRoleDao.checkIsAdmin(user.getUserId());
PageInfo<CloseStoreInfoListVO> pageInfo = closeStoreAuditRecordDAO.getCloseStoreAuditList(request, user.getUserId(), isAdmin);
fillCloseStoreRecord(request, pageInfo.getList());
return pageInfo;
}
@Override
public PageInfo<CloseStoreInfoListVO> closeStoreInfoList(CloseStoreQueryRequest request) {
closeStoreRecordQueryBefore(request);
request.setQueryStore(true);
String userId = CurrentUserHolder.getUserId();
Boolean isAdmin = enterpriseUserRoleDao.checkIsAdmin(userId);
List<String> regionIds = new ArrayList<>();
if (!isAdmin) {
List<UserAuthMappingDO> userAuthMappingDOS = userAuthMappingService.listUserAuthMappingByUserId(userId);
if (CollectionUtils.isEmpty(userAuthMappingDOS)) {
return new PageInfo<>();
}
regionIds = CollStreamUtil.toList(userAuthMappingDOS, UserAuthMappingDO::getMappingId);
}
PageInfo<CloseStoreInfoListVO> pageInfo = closeStoreInfoDAO.getCloseStoreInfoList(request, regionIds);
fillCloseStoreRecord(request, pageInfo.getList());
List<Long> closeStoreIds = CollStreamUtil.toList(pageInfo.getList(), CloseStoreInfoListVO::getCloseStoreId);
Map<Long, Long> completeCountMap = closeStoreStageInfoDAO.getCompleteCountMap(closeStoreIds);
pageInfo.getList().forEach(v -> {
v.setCompleteProcessNum(completeCountMap.getOrDefault(v.getCloseStoreId(), 0L).intValue());
v.setTotalProcessNum(CloseStoreSubStageEnum.values().length);
});
return pageInfo;
}
@Override
public List<AuditInfoResponse> getAuditRecordList(Long closeStoreId) {
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(closeStoreId);
if (Objects.isNull(closeStoreInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
List<CloseStoreAuditRecordDO> list = closeStoreAuditRecordDAO.getListByCloseStoreId(closeStoreId);
Set<String> userIds = new HashSet<>();
list.forEach(v -> {
if (!CommonConstants.INDEX_ONE.equals(v.getRecordType()) || CloseTypeEnum.NO_ORDER_AUTO.getCloseType().equals(closeStoreInfoDO.getCloseType())) {
userIds.addAll(StringUtils.isNotBlank(v.getHandlerUserIds()) ? Arrays.asList(v.getHandlerUserIds().split(",")) : Collections.emptyList());
}
});
Map<String, EnterpriseUserDO> userMap = enterpriseUserDAO.getUserMap(new ArrayList<>(userIds));
List<AuditInfoResponse> result = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
CloseStoreAuditRecordDO auditRecordDO = list.get(i);
AuditInfoResponse auditInfo = AuditInfoResponse.builder()
.type(getAuditInfoType(auditRecordDO))
// 0加盟商发起 1云流水发起 2督导审批 3大区经理审批
.execute(i == 0 ? (CloseTypeEnum.INITIATE.getCloseType().equals(closeStoreInfoDO.getCloseType()) ? 0 : 1) : i + 1)
.status(CommonConstants.INDEX_ZERO.equals(auditRecordDO.getAuditStatus()) ? 0 : 1)
.createTime(auditRecordDO.getCreateTime())
.remark(auditRecordDO.getActionRemark())
.actualUserId(auditRecordDO.getHandlerUserId())
.build();
List<AuditInfoResponse.AuditUserInfoVO> auditUserList = Arrays.stream(auditRecordDO.getHandlerUserIds().split(","))
.filter(StringUtils::isNotBlank)
.map(v -> {
String userName = null, avatar = null;
if (CommonConstants.INDEX_ZERO.equals(auditInfo.getExecute())) {
userName = auditRecordDO.getHandlerUserName();
} else {
EnterpriseUserDO user = userMap.get(v);
if (Objects.nonNull(user)) {
userName = user.getName();
avatar = user.getAvatar();
}
}
return new AuditInfoResponse.AuditUserInfoVO(v, userName, avatar);
})
.collect(Collectors.toList());
auditInfo.setList(auditUserList);
result.add(auditInfo);
}
return result;
}
private Integer getAuditInfoType(CloseStoreAuditRecordDO auditRecordDO) {
if (CommonConstants.INDEX_ONE.equals(auditRecordDO.getRecordType())) {
return OperationLogAuditEnum.SUBMIT_AUDIT.getCode();
} else {
switch (auditRecordDO.getAuditStatus()) {
case 0:
return OperationLogAuditEnum.WAIT_AUDIT.getCode();
case 1:
return OperationLogAuditEnum.PASS.getCode();
case 2:
return OperationLogAuditEnum.REFUSE.getCode();
default:
return null;
}
}
}
@Override
public CloseStoreInfoDetailVO getCloseStoreInfoDetail(Long closeStoreId, Boolean queryAuditId) {
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(closeStoreId);
if (Objects.isNull(closeStoreInfoDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_INFO_NOT_EXIST);
}
CloseStoreInfoDetailVO vo = new CloseStoreInfoDetailVO();
BeanUtil.copyProperties(closeStoreInfoDO, vo);
StoreDO storeDO = storeDao.getByStoreId(closeStoreInfoDO.getStoreId());
if (Objects.nonNull(storeDO)) {
BeanUtil.copyPropertiesIgnoreId(storeDO, vo);
}
StoreMasterSignerInfoDO signerInfoDO = storeMasterSignerInfoDAO.getByStoreId(closeStoreInfoDO.getStoreId());
if (Objects.nonNull(signerInfoDO)) {
BeanUtil.copyPropertiesIgnoreId(signerInfoDO, vo);
}
if (Boolean.TRUE.equals(queryAuditId)) {
CloseStoreAuditRecordDO pendingAuditRecord = closeStoreAuditRecordDAO.getPendingAuditRecord(closeStoreId);
if (Objects.nonNull(pendingAuditRecord)) {
vo.setAuditId(pendingAuditRecord.getId());
}
}
return vo;
}
@Override
public CloseStoreInfoDetailVO getCloseStoreInfoDetailByAuditId(Long closeStoreAuditId) {
CloseStoreAuditRecordDO auditRecordDO = closeStoreAuditRecordDAO.getById(closeStoreAuditId);
if (Objects.isNull(auditRecordDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_AUDIT_RECORD_NOT_EXIST);
}
CloseStoreInfoDetailVO vo = getCloseStoreInfoDetail(auditRecordDO.getCloseStoreId(), null);
vo.setAuditId(auditRecordDO.getId());
return vo;
}
@Override
public List<StoreCloseReasonVO> getStoreCloseReasonList(Integer closeType) {
return Arrays.stream(StoreCloseReasonEnum.values())
.filter(v -> Objects.isNull(closeType) || v.getCloseNature().getCloseType().getCloseType().equals(closeType))
.map(v -> new StoreCloseReasonVO(v.getCode(), v.getDesc(), v.getCloseNature().getCloseType().getCloseType()))
.collect(Collectors.toList());
}
@Override
public CloseStoreSimpleVO getCloseStoreSimpleInfo(Long closeStoreId) {
CloseStoreInfoDetailVO detail = getCloseStoreInfoDetail(closeStoreId, null);
CloseStoreSimpleVO vo = BeanUtil.toBean(detail, CloseStoreSimpleVO.class);
vo.setCompleteProcessNum(closeStoreStageInfoDAO.getCompleteCount(closeStoreId));
vo.setTotalProcessNum(CloseStoreSubStageEnum.values().length);
List<CloseStoreStageInfoDO> stageInfoList = closeStoreStageInfoDAO.getList(closeStoreId);
List<CloseStoreSubStageStatusVO> subStageList = BeanUtil.toList(stageInfoList, CloseStoreSubStageStatusVO.class);
vo.setStageList(subStageList);
return vo;
}
@Override
public PageInfo<MiniCloseStoreSimpleVO> getMiniCloseStoreSimpleInfoList(MiniCloseStoreQueryRequest request) {
String userId = PartnerUserHolder.getUser().getPartnerId();
PageHelper.startPage(request.getPageNum(), request.getPageSize());
List<CloseStoreInfoDO> list = closeStoreInfoDAO.getListByApplyUserId(userId, CloseTypeEnum.INITIATE.getCloseType(), request.getStoreId());
PageInfo<CloseStoreInfoDO> pageInfo = new PageInfo<>(list);
PageInfo<MiniCloseStoreSimpleVO> voPage = BeanUtil.toPage(pageInfo, MiniCloseStoreSimpleVO.class);
Set<String> storeIds = CollStreamUtil.toSet(list, CloseStoreInfoDO::getStoreId);
List<StoreDO> storeList = storeDao.getEffectiveStoreByStoreIds(new ArrayList<>(storeIds));
Map<String, StoreDO> storeMap = CollStreamUtil.toMap(storeList, StoreDO::getStoreId, v -> v);
voPage.getList().forEach(v -> {
StoreDO storeDO = storeMap.get(v.getStoreId());
if (Objects.nonNull(storeDO)) {
BeanUtil.copyPropertiesIgnoreId(storeDO, v, "createTime");
}
});
return voPage;
}
@Override
public List<CloseStoreStatusVO> getCloseStoreStatusList() {
return Arrays.stream(CloseStoreStatusEnum.values())
.filter(v -> v != CloseStoreStatusEnum.MANAGER_UNDER_APPROVAL)
.map(v -> new CloseStoreStatusVO(v.getCloseStoreStatus(), v.getCloseStoreStatusName()))
.collect(Collectors.toList());
}
@Override
@Transactional
public void closeStoreProcessFlow(Long closeStoreId, CloseStoreSubStageEnum currentSubStage) {
CloseStoreStageInfoDO currentStage = closeStoreStageInfoDAO.getByStage(closeStoreId, currentSubStage.getCloseStoreStageEnum().getCloseStoreStage(), currentSubStage.getCloseStoreSubStage());
CloseStoreSubStageStatusEnum stageStatus = CloseStoreSubStageStatusEnum.getByStatus(currentStage.getShopSubStageStatus());
// 已结束或未开始的流程不流转
if (Objects.nonNull(stageStatus) && !CloseStoreSubStageStatusEnum.CLOSE_STORE_SUB_STAGE_STATUS_00.equals(stageStatus) && !stageStatus.isTerminated()) {
// 下个子阶段状态
CloseStoreSubStageStatusEnum nextStageStatus = CloseStoreSubStageStatusEnum.getNextStageStatus(stageStatus);
if (Objects.nonNull(nextStageStatus)) {
log.info("进入子阶段下一阶段:{}, status:{}[{}]", nextStageStatus.getShopSubStageName(), nextStageStatus.getShopSubStageStatusName(), nextStageStatus.getShopSubStageStatus());
currentStage.setShopSubStageStatus(nextStageStatus.getShopSubStageStatus());
currentStage.setIsTerminated(nextStageStatus.isTerminated() ? 1 : 0);
currentStage.setUpdateTime(new Date());
if (nextStageStatus.isTerminated()) {
currentStage.setActualCompleteTime(CoolDateUtils.getCurrentDateTime());
}
closeStoreStageInfoDAO.updateSelective(currentStage);
if (nextStageStatus.isTerminated()) {
// 当前子阶段结束,开始下一个子阶段
log.info("当前子阶段结束,进入下一个子阶段");
openNextSubStage(closeStoreId, currentSubStage);
}
}
}
}
/**
* 开启下一个子阶段
* @param closeStoreId 闭店申请ID
* @param currentSubStage 当前子阶段
*/
public void openNextSubStage(Long closeStoreId, CloseStoreSubStageEnum currentSubStage) {
// 根据当前子阶段获取下一个需要开启的子阶段列表
List<CloseStoreSubStageEnum> nextSubStages = CloseStoreSubStageEnum.getNextSubStage(currentSubStage);
if (CollectionUtils.isEmpty(nextSubStages)) {
// 不存在下一子阶段,校验当前所有子阶段状态,修改闭店申请状态
log.info("当前子阶段结束,不存在下一子阶段");
verifyAndUpdateCloseStoreStatus(closeStoreId);
return;
}
log.info("开启子阶段:{}", StringUtils.join(CollStreamUtil.toList(nextSubStages, CloseStoreSubStageEnum::getCloseStoreSubStageName), ","));
List<Integer> subStageList = CollStreamUtil.toList(nextSubStages, CloseStoreSubStageEnum::getCloseStoreSubStage);
List<CloseStoreStageInfoDO> stageInfoList = closeStoreStageInfoDAO.getBySubStage(closeStoreId, subStageList);
Map<Integer, Map<Integer, CloseStoreStageInfoDO>> stageMap = CollStreamUtil.group2Map(stageInfoList, CloseStoreStageInfoDO::getShopStage, CloseStoreStageInfoDO::getShopSubStage);
List<CloseStoreStageInfoDO> updateStageList = new ArrayList<>();
for (CloseStoreSubStageEnum nextSubStage : nextSubStages) {
CloseStoreStageInfoDO stageInfoDO = stageMap.getOrDefault(nextSubStage.getCloseStoreStageEnum().getCloseStoreStage(), Collections.emptyMap())
.get(nextSubStage.getCloseStoreSubStage());
if (Objects.nonNull(stageInfoDO)) {
// 获取子阶段开始的状态
CloseStoreSubStageStatusEnum openStageStatus = CloseStoreSubStageStatusEnum.getOpenStageStatus(nextSubStage);
if (Objects.nonNull(openStageStatus)) {
CloseStoreStageInfoDO updateStageInfo = CloseStoreStageInfoDO.builder()
.id(stageInfoDO.getId())
.shopSubStageStatus(openStageStatus.getShopSubStageStatus())
.build();
updateStageList.add(updateStageInfo);
}
}
}
if (CollectionUtils.isNotEmpty(updateStageList)) {
closeStoreStageInfoDAO.updateBatchSelective(updateStageList);
}
}
/**
* 校验当前所有子阶段状态,修改闭店申请状态
* @param closeStoreId 闭店申请ID
*/
public void verifyAndUpdateCloseStoreStatus(Long closeStoreId) {
if (!closeStoreStageInfoDAO.existUnfinishedStage(closeStoreId)) {
// 所有子阶段都完成,修改闭店申请状态为已完成
CloseStoreInfoDO closeStoreInfoDO = closeStoreInfoDAO.getById(closeStoreId);
if (Objects.nonNull(closeStoreInfoDO)) {
log.info("所有子阶段完成");
closeStoreInfoDAO.updateSelective(CloseStoreInfoDO.builder().id(closeStoreId).closeStatus(CloseStoreStatusEnum.COMPLETED.getCloseStoreStatus()).build());
}
}
}
/**
* 查询前置处理
*/
private void closeStoreRecordQueryBefore(CloseStoreQueryRequest request) {
request.setQueryStore(StringUtils.isNotBlank(request.getStoreNameOrNum()) || StringUtils.isNotBlank(request.getJoinBrandList()));
request.setQuerySigner(StringUtils.isNotBlank(request.getSignerName()) || StringUtils.isNotBlank(request.getSignerMobile()));
if (StringUtils.isNotBlank(request.getJoinBrandList())) {
request.setJoinBrands(Arrays.stream(request.getJoinBrandList().split(",")).map(Integer::parseInt).collect(Collectors.toList()));
}
}
/**
* 补充字段
*/
private void fillCloseStoreRecord(CloseStoreQueryRequest request, List<CloseStoreInfoListVO> list) {
Set<String> storeIds = new HashSet<>();
Set<String> signerStoreIds = new HashSet<>();
if (!request.getQueryStore() || !request.getQuerySigner()) {
for (CloseStoreInfoListVO v : list) {
if (!request.getQueryStore()) {
storeIds.add(v.getStoreId());
}
if (!request.getQuerySigner()) {
signerStoreIds.add(v.getStoreId());
}
}
}
Map<String, StoreDO> storeMap = Collections.emptyMap();
Map<String, StoreMasterSignerInfoDO> signerMap = Collections.emptyMap();
if (CollectionUtil.isNotEmpty(storeIds)) {
List<StoreDO> storeList = storeDao.getEffectiveStoreByStoreIds(new ArrayList<>(storeIds));
storeMap = CollStreamUtil.toMap(storeList, StoreDO::getStoreId, v -> v);
}
if (CollectionUtil.isNotEmpty(signerStoreIds)) {
signerMap = storeMasterSignerInfoDAO.getSignerMapByStoreIds(new ArrayList<>(signerStoreIds));
}
if (!request.getQueryStore() || !request.getQuerySigner()) {
for (CloseStoreInfoListVO v : list) {
StoreDO storeDO = storeMap.get(v.getStoreId());
if (Objects.nonNull(storeDO)) {
BeanUtil.copyPropertiesIgnoreId(storeDO, v);
}
StoreMasterSignerInfoDO signerInfoDO = signerMap.get(v.getStoreId());
if (Objects.nonNull(signerInfoDO)) {
BeanUtil.copyPropertiesIgnoreId(signerInfoDO, v);
}
}
}
}
/**
* 进入闭店流程初始化
*/
private void closeStoreFlowInit(CloseStoreInfoDO closeStoreInfoDO, String storeId, Integer closeReason) {
Long closeStoreId = closeStoreInfoDO.getId();
// 闭店资料初始化
closeStoreFileInfoDAO.init(closeStoreId);
closeStoreFileDetailDAO.init(closeStoreId);
// 闭店账号初始化
closeStoreAccountInfoDAO.init(closeStoreId);
// 闭店流程初始化
closeStoreStageInfoDAO.initStageInfo(closeStoreId);
// 门店改为闭店,闭店时间为当前时间
StoreCloseReasonEnum closeReasonEnum = StoreCloseReasonEnum.getByCode(closeReason);
assert closeReasonEnum != null;
storeDao.closeStore(storeId, closeReasonEnum.getCode(), closeReasonEnum.getCloseNature().getCode(), closeStoreInfoDO.getActualCloseData());
// 用mq通知主应用下发门店主数据
try {
StoreMasterIssueDTO storeMasterIssueDTO = new StoreMasterIssueDTO(enterpriseId, Collections.singletonList(storeId));
simpleMessageService.send(JSONObject.toJSONString(storeMasterIssueDTO), RocketMqTagEnum.STORE_MASTER_ISSUE);
} catch (Exception e) {
log.error("mq通知主应用下发门店主数据失败");
}
}
/**
* 审批校验
* @param auditRecordDO 审批记录
*/
private void auditVerify(CloseStoreAuditRecordDO auditRecordDO) {
if (Objects.isNull(auditRecordDO)) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_AUDIT_RECORD_NOT_EXIST);
}
if (!CloseStoreAuditStatusEnum.PENDING.getStatus().equals(auditRecordDO.getAuditStatus())) {
throw new ServiceException(ErrorCodeEnum.CLOSE_STORE_HAS_BEEN_COMPLETED);
}
// 是否有审批权限
String currentUserId = CurrentUserHolder.getUserId();
if (StringUtils.isBlank(auditRecordDO.getHandlerUserIds())) {
throw new ServiceException(ErrorCodeEnum.NO_APPROVAL_AUTHORITY);
}
List<String> userIds = Arrays.asList(auditRecordDO.getHandlerUserIds().split(","));
if (!userIds.contains(currentUserId)) {
throw new ServiceException(ErrorCodeEnum.NO_APPROVAL_AUTHORITY);
}
}
/**
* 获取拥有区域管辖权限的指定角色用户
* @param regionId 区域id
* @param userRoleEnum 角色枚举
* @return 用户id列表
*/
private List<String> getAuditUserIds(Long regionId, UserRoleEnum userRoleEnum) {
List<EnterpriseUserDO> allUserByRoleEnumAndRegionId = userAuthMappingService.getAllUserByRoleEnumAndRegionId(userRoleEnum, regionId);
return ListUtils.emptyIfNull(allUserByRoleEnumAndRegionId).stream().map(EnterpriseUserDO::getUserId).distinct().collect(Collectors.toList());
}
/**
* 生成闭店申请单号
*/
private String generateCloseStoreNo(){
return "C" + CoolDateUtils.getTodayMillis();
}
}

View File

@@ -0,0 +1,35 @@
package com.cool.store.service.close.impl;
import com.cool.store.entity.StoreDO;
import com.cool.store.request.huoma.AccountCloseRequest;
import com.cool.store.service.HuoMaService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* <p>
* 火码账号关闭
* </p>
*
* @author wangff
* @since 2025/10/8
*/
@Service
@RequiredArgsConstructor
public class HuomaAccountClose extends AbstractAccountClose {
private final HuoMaService huoMaService;
@Override
public String getSystemCode() {
return "huoma";
}
@Override
public Boolean accountClose(String storeId) {
StoreDO storeDO = getStore(storeId);
AccountCloseRequest request = new AccountCloseRequest();
request.setShop_sn(storeDO.getStoreNum());
request.setEnable(0);
return huoMaService.accountClose(request);
}
}

View File

@@ -0,0 +1,37 @@
package com.cool.store.service.close.impl;
import com.cool.store.entity.StoreDO;
import com.cool.store.request.xgj.XgjAccountCloseRequest;
import com.cool.store.service.ThirdXgjService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* <p>
* 新掌柜账号关闭
* </p>
*
* @author wangff
* @since 2025/10/8
*/
@Service
@RequiredArgsConstructor
public class XinguanjiaAccountClose extends AbstractAccountClose {
private final ThirdXgjService thirdXgjService;
@Override
public String getSystemCode() {
return "xinguanjia";
}
@Override
public Boolean accountClose(String storeId) {
StoreDO storeDO = getStore(storeId);
String closeTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
thirdXgjService.accountClose(new XgjAccountCloseRequest(storeDO.getStoreNum(), closeTime));
return true;
}
}

View File

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONObject;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.OrderSummaryRequest;
import com.cool.store.request.huoma.AccountCloseRequest;
import com.cool.store.request.huoma.ShopBasicInfoRequest;
import com.cool.store.response.IncomeBaseResponse;
import com.cool.store.response.IncomeSummaryResponse;
@@ -22,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
@@ -85,6 +87,13 @@ public class ThirdHuoMaServiceImpl implements HuoMaService {
return executeApiCall(apiUrl,requestBody,IncomeSummaryResponse.class);
}
@Override
public Boolean accountClose(AccountCloseRequest requestBody) {
String apiUrl = url + "/dzgV1/shop/setShopEnableSwitch";
executeApiCall(apiUrl, requestBody, List.class);
return true;
}
private <T> T executeApiCall(String url, Object requestBody, Class<T> responseType) {
// 1. 打印请求前日志

View File

@@ -0,0 +1,247 @@
package com.cool.store.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.cool.store.dto.xgj.XgjBranchBankDTO;
import com.cool.store.dto.xgj.XgjPartnerPageDTO;
import com.cool.store.dto.xgj.XgjPayResultDTO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.xgj.*;
import com.cool.store.response.XgjAccessTokenDTO;
import com.cool.store.response.oppty.OpportunityApiResponse;
import com.cool.store.service.ThirdXgjService;
import com.cool.store.utils.HmacSigner;
import com.cool.store.utils.poi.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
/**
* <p>
* 新管家三方接口 服务实现类
* </p>
*
* @author wangff
* @since 2025/11/28
*/
@Service
@RequiredArgsConstructor
@Slf4j
public class ThirdXgjServiceImpl implements ThirdXgjService {
@Value("${xgj.api.auth.url}")
private String xgjUrl;
@Value("${xgj.api.token.url}")
private String xgjTokenUrl;
@Value("${xgj.api.auth.username}")
private String xgjUsername;
@Value("${xgj.api.auth.secret}")
private String xgjSecret;
@Resource
OkHttpClient okHttpClient;
@Resource
ObjectMapper objectMapper;
@Override
public String accountClose(XgjAccountCloseRequest request) {
String apiUrl = xgjUrl + "/dmp/dmp-join/open/closeStore";
return executePostApiCall(apiUrl, request, String.class);
}
@Override
public String reimburse(XgjReimburseRequest request) {
String apiUrl = xgjUrl + "/dmp/dmp-join/open/dmpJoinCloseOpen";
return executePostApiCall(apiUrl, request, String.class);
}
@Override
public String savePartner(XgjSavePartnerRequest request) {
String apiUrl = xgjUrl + "/dmp/dmp-join/open/saveMKPartner";
return executePostApiCall(apiUrl, request, String.class);
}
@Override
public XgjPayResultDTO queryOrderStatus(XgjPaymentRequest request) {
String apiUrl = xgjUrl + "/dmp/dmp-join/open/quryOrderStatus";
return executePostApiCall(apiUrl, request, XgjPayResultDTO.class);
}
@Override
public XgjPartnerPageDTO queryPartnerPage(XgjPartnerQueryRequest request) {
String apiUrl = xgjUrl + "/dmp/dmp-join/open/partnerPage";
return executePostApiCall(apiUrl, request, XgjPartnerPageDTO.class);
}
@Override
public List<XgjBranchBankDTO> queryBranchBankList(XgjBankQueryRequest request) {
String apiUrl = xgjUrl = "/dmp-payment/open/queryOpenBankNoByBankName";
return executePostApiCall(apiUrl, request, List.class);
}
private <T> T executePostApiCall(String url, Object requestBody, Class<T> responseType) {
// 1. 打印请求前日志
logRequest(url, requestBody);
try {
String accessToken = getXgjAccessToken().getAccess_token();
Request request = buildRequest(requestBody, url,accessToken);
request.headers().names().forEach(x->{
log.info(x+": {}",request.header(x));
});
try (Response response = okHttpClient.newCall(request).execute()) {
// 2. 获取原始响应内容
String responseBody = response.body().string();
// 3. 打印响应日志
logResponse(url, response.code(), responseBody);
if (!response.isSuccessful()) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
"HTTP请求失败状态码: " + response.code());
}
// 4. 解析响应
JavaType javaType = objectMapper.getTypeFactory()
.constructParametricType(OpportunityApiResponse.class, responseType);
OpportunityApiResponse<T> apiResponse = objectMapper.readValue(responseBody, javaType);
if (apiResponse.getCode() != 200) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,apiResponse.getMsg());
}
return apiResponse.getData();
}
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("API调用异常 - URL: {}, 错误: {}", url, e.getMessage(), e);
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
}
}
private void logRequest(String url, Object requestBody) {
if (log.isInfoEnabled()) {
try {
log.info("\n======= 请求开始 =======\n" +
"API地址: {}\n" +
"请求参数: {}\n" +
"======= 请求结束 =======",
url,
objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(requestBody));
} catch (JsonProcessingException e) {
log.warn("日志JSON序列化失败", e);
}
}
}
public XgjAccessTokenDTO getXgjAccessToken() {
String apiUrl = xgjTokenUrl + "/oauth2/token?grant_type=client_credentials&scope=server";
String clientId = "dmp-join";
String clientSecret = "dmp20250528";
String auth = clientId + ":" + clientSecret;
String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
byte[] bytes = new byte[0];
Request request = new Request.Builder()
.url(apiUrl)
.post(RequestBody.create(MediaType.parse("application/json; charset=UTF-8"),bytes))
.header("Authorization", "Basic " + encodedAuth)
.build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR,
"HTTP请求失败状态码: " + response.code());
}
String responseBody = response.body().string();
XgjAccessTokenDTO xgjAccessTokenDTO = objectMapper.readValue(responseBody, XgjAccessTokenDTO.class);
return xgjAccessTokenDTO;
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
log.error("API调用异常 - URL: {}, 错误: {}", apiUrl, e.getMessage(), e);
throw new ServiceException(ErrorCodeEnum.THIRD_API_ERROR, "接口调用异常: " + e.getMessage());
}
}
private Request buildRequest(Object requestBody, String url,String accessToken) {
try {
Map<String, String> authHeaders = HmacSigner.generateHeaders(
xgjUsername, xgjSecret, JSONObject.toJSONString(requestBody));
log.debug("签名生成 - 签名结果: {}", JSONObject.toJSONString(authHeaders));
RequestBody body = RequestBody.create(MediaType.parse("application/json"),
JSONObject.toJSONString(requestBody)
);
log.info(JSONObject.toJSONString(requestBody));
Request.Builder builder = new Request.Builder()
.url(url)
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("x-Date", authHeaders.get("x-Date"))
.addHeader("Digest", authHeaders.get("Digest"));
if (!url.contains("get-token-byshopcode")&& StringUtils.isEmpty(accessToken)){
builder.addHeader("Authorization", authHeaders.get("Authorization"));
}
//新管家特定接口
if (StringUtils.isNotEmpty(accessToken)){
builder.addHeader("Authorization", "Bearer "+accessToken);
}
return builder.build();
} catch (Exception e) {
throw new ServiceException(ErrorCodeEnum.THIRD_API_SIGN_ERROR);
}
}
/**
* 记录响应日志
*/
private void logResponse(String url, int statusCode, String responseBody) {
if (log.isInfoEnabled()) {
try {
// 尝试美化JSON输出
Object json = objectMapper.readValue(responseBody, Object.class);
String prettyResponse = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(json);
log.info("\n======= 响应开始 =======\n" +
"API地址: {}\n" +
"HTTP状态码: {}\n" +
"响应内容: {}\n" +
"======= 响应结束 =======",
url,
statusCode,
prettyResponse);
} catch (Exception e) {
// 非JSON响应或解析失败时直接输出原始内容
log.info("\n======= 响应开始 =======\n" +
"API地址: {}\n" +
"HTTP状态码: {}\n" +
"原始响应: {}\n" +
"======= 响应结束 =======",
url,
statusCode,
responseBody);
}
}
}
}