refactor(bpm): 重构回款结算接口并添加客户转移功能

- 重构了 BpmOAReceiptService 接口,使用 ReceiptSettlementVO 替代 LocalDateTime[] 参数
- 添加了客户转移相关的 API 和服务实现
- 优化了销售业绩结算相关的数据结构和接口
- 调整了权限控制相关的配置
This commit is contained in:
aikai 2025-03-10 16:41:14 +08:00
parent f3f91f7350
commit 1f65ca883c
37 changed files with 426 additions and 129 deletions

View File

@ -145,7 +145,7 @@ public class WxMpMsgTemplateUtils {
message.setJumpWxMaFlag(true); message.setJumpWxMaFlag(true);
message.setMiniProgramState(dto.getMiniProgramState()); message.setMiniProgramState(dto.getMiniProgramState());
message.setPage(dto.getPage()); message.setPage(dto.getPage());
message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP.getType()); message.setSocialType(SocialTypeEnum.WECHAT_MINI_APP_CRM.getType());
return message; return message;
} }

View File

@ -1,10 +1,7 @@
package cn.iocoder.yudao.module.bpm.api.oa; package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.*;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.enums.ApiConstants; import cn.iocoder.yudao.module.bpm.enums.ApiConstants;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -36,7 +33,7 @@ public interface BpmOAReceiptApi {
CommonResult<List<ReceiptStatisticsDTO>> getContractStatistics(@RequestParam("userId") List<Long> userIds, CommonResult<List<ReceiptStatisticsDTO>> getContractStatistics(@RequestParam("userId") List<Long> userIds,
@RequestParam(name = "createTime", required = false) LocalDateTime[] createTime); @RequestParam(name = "createTime", required = false) LocalDateTime[] createTime);
@GetMapping(PREFIX + "/getReceiptSettlement") @PostMapping(PREFIX + "/getReceiptSettlement")
@Operation(summary = "获取用户回款结算信息") @Operation(summary = "获取用户回款结算信息")
CommonResult<List<ReceiptSettlementDTO>> getReceiptSettlement(@RequestParam(name = "times", required = false) LocalDateTime[] times); CommonResult<List<ReceiptSettlementDTO>> getReceiptSettlement(@RequestBody ReceiptSettlementVO vo);
} }

View File

@ -0,0 +1,20 @@
package cn.iocoder.yudao.module.bpm.api.oa.vo.receipt;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Data
@ToString(callSuper = true)
public class ReceiptSettlementVO {
@Schema(description = "时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -2,14 +2,12 @@ package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.*;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.ReceiptStatisticsVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReceiptDO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReceiptService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -48,7 +46,7 @@ public class BpmOAReceiptApiImpl implements BpmOAReceiptApi{
} }
@Override @Override
public CommonResult<List<ReceiptSettlementDTO>> getReceiptSettlement(LocalDateTime[] times) { public CommonResult<List<ReceiptSettlementDTO>> getReceiptSettlement(ReceiptSettlementVO vo) {
return success(receiptService.getReceiptSettlement(times)); return success(receiptService.getReceiptSettlement(vo));
} }
} }

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptRespVO;
@ -50,8 +51,7 @@ public interface BpmOAReceiptMapper extends BaseMapperX<BpmOAReceiptDO> {
/** /**
* 获取用户结算回款信息 * 获取用户结算回款信息
* *
* @param times
* @return * @return
*/ */
List<ReceiptSettlementDTO> getReceiptSettlement(@Param("times") LocalDateTime[] times); List<ReceiptSettlementDTO> getReceiptSettlement(@Param("vo") ReceiptSettlementVO vo);
} }

View File

@ -272,11 +272,13 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
List<Long> userIds = new ArrayList<>(); List<Long> userIds = new ArrayList<>();
if ("my".equals(pageReqVO.getRelation())) { if ("my".equals(pageReqVO.getRelation())) {
userIds.add(getLoginUserId()); userIds.add(getLoginUserId());
}else if ("sub".equals(pageReqVO.getRelation())){ } else if ("sub".equals(pageReqVO.getRelation())) {
// 查询当前用户 所有下级用户编号 // 查询当前用户 所有下级用户编号
userIds.addAll(userLiveTreeApi.getItemIdsByUserId(getLoginUserId()).getCheckedData()); userIds.addAll(userLiveTreeApi.getItemIdsByUserId(getLoginUserId()).getCheckedData());
} }
if (CollUtil.isEmpty(userIds)) {
return PageResult.empty();
}
return contractMapper.selectPage(pageReqVO, userIds); return contractMapper.selectPage(pageReqVO, userIds);
} }
@ -327,9 +329,10 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
@Override @Override
public List<BpmOAContractDO> getContractList(BpmOAContractVO respVO) { public List<BpmOAContractDO> getContractList(BpmOAContractVO respVO) {
Date[] dateArray = new Date[]{respVO.getStarTime(), respVO.getEndTime()}; Date[] dateArray = new Date[]{respVO.getStarTime(), respVO.getEndTime()};
if (CollUtil.isEmpty(respVO.getUserId())) {
return Collections.emptyList();
}
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>() return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
.inIfPresent(BpmOAContractDO::getUserId, respVO.getUserId()) .inIfPresent(BpmOAContractDO::getUserId, respVO.getUserId())
.eqIfPresent(BpmOAContractDO::getContractType, respVO.getContractType()) .eqIfPresent(BpmOAContractDO::getContractType, respVO.getContractType())
@ -370,30 +373,30 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
} }
private void createContractProductList(Long contractId, List<CrmContractProductVO> list) { private void createContractProductList(Long contractId, List<CrmContractProductVO> list) {
List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>(); // List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
if (CollUtil.isNotEmpty(list)) { // if (CollUtil.isNotEmpty(list)) {
List<Long> productIds = list.stream().map(CrmContractProductVO::getProductId).collect(Collectors.toList()); // List<Long> productIds = list.stream().map(CrmContractProductVO::getProductId).collect(Collectors.toList());
List<String> productAttrUnique = list.stream().map(CrmContractProductVO::getProductAttrUnique).collect(Collectors.toList()); // List<String> productAttrUnique = list.stream().map(CrmContractProductVO::getProductAttrUnique).collect(Collectors.toList());
storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO() // storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
.setProductIds(productIds) // .setProductIds(productIds)
.setUniques(productAttrUnique)).getCheckedData(); // .setUniques(productAttrUnique)).getCheckedData();
} // }
Map<String, List<StoreProductAttrValueApiVO>> map = storeProductAttrValueList.stream().collect(Collectors.groupingBy(a -> a.getProductId() + "_" + a.getUnique())); // Map<String, List<StoreProductAttrValueApiVO>> map = storeProductAttrValueList.stream().collect(Collectors.groupingBy(a -> a.getProductId() + "_" + a.getUnique()));
list.forEach(o -> { // list.forEach(o -> {
o.setContractId(contractId); // o.setContractId(contractId);
//库存处理 // //库存处理
List<StoreProductAttrValueApiVO> storeProductAttrValueApiVOS = map.get(o.getProductId() + "_" + o.getProductAttrUnique()); // List<StoreProductAttrValueApiVO> storeProductAttrValueApiVOS = map.get(o.getProductId() + "_" + o.getProductAttrUnique());
//
int count = 0; // int count = 0;
if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) { // if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
count = storeProductAttrValueApiVOS.stream().mapToInt(StoreProductAttrValueApiVO::getStock).sum(); // count = storeProductAttrValueApiVOS.stream().mapToInt(StoreProductAttrValueApiVO::getStock).sum();
} // }
if (NumberUtil.compare(count, o.getNums()) < 0) { // if (NumberUtil.compare(count, o.getNums()) < 0) {
throw exception(new ErrorCode(202408250, "该商品ID" + o.getProductId() + "库存不足")); // throw exception(new ErrorCode(202408250, "该商品ID" + o.getProductId() + "库存不足"));
} // }
// TODO: 2024/11/21 这里的库存扣件完后 - 如果审批不通过 库存退回 // // TODO: 2024/11/21 这里的库存扣件完后 - 如果审批不通过 库存退回
this.decProductStock(o.getNums(), o.getProductId(), o.getProductAttrUnique()); // this.decProductStock(o.getNums(), o.getProductId(), o.getProductAttrUnique());
}); // });
contractApi.createProduct(BeanUtils.toBean(list, CrmContractProductDTO.class)); contractApi.createProduct(BeanUtils.toBean(list, CrmContractProductDTO.class));
} }

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.receipt.BpmOAReceiptPageReqVO;
@ -86,8 +87,8 @@ public interface BpmOAReceiptService {
/** /**
* 获取用户结算回款信息 * 获取用户结算回款信息
* *
* @param times * @param vo
* @return * @return
*/ */
List<ReceiptSettlementDTO> getReceiptSettlement(LocalDateTime[] times); List<ReceiptSettlementDTO> getReceiptSettlement(ReceiptSettlementVO vo);
} }

View File

@ -1,11 +1,13 @@
package cn.iocoder.yudao.module.bpm.service.oa; package cn.iocoder.yudao.module.bpm.service.oa;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; import cn.iocoder.yudao.framework.common.pojo.UploadUserFile;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.BpmOAReceiptVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptStatisticsDTO;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
@ -30,11 +32,7 @@ import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@ -44,11 +42,10 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_RECEIPT_NO
* OA 回款申请 Service 实现类 * OA 回款申请 Service 实现类
* *
* @author 符溶馨 * @author 符溶馨
*/ */
@Service @Service
@Validated @Validated
public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOAReceiptService{ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOAReceiptService {
/** /**
* OA 退款对应的流程定义 KEY * OA 退款对应的流程定义 KEY
@ -80,7 +77,7 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
BpmOAReceiptDO receipt = BeanUtils.toBean(createReqVO, BpmOAReceiptDO.class) BpmOAReceiptDO receipt = BeanUtils.toBean(createReqVO, BpmOAReceiptDO.class)
.setUserId(userId) .setUserId(userId)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
receiptMapper.insert(receipt) ; receiptMapper.insert(receipt);
// 发起 BPM 流程 // 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>(); Map<String, Object> processInstanceVariables = new HashMap<>();
@ -97,10 +94,10 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId()); historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
} }
List<UploadUserFile> fileItems = createReqVO.getFileItems() ; List<UploadUserFile> fileItems = createReqVO.getFileItems();
//这里的逻辑如果fileItems不为空且有数据那么说明是上传了附件的则需要更工作流文件表对应的实例Id //这里的逻辑如果fileItems不为空且有数据那么说明是上传了附件的则需要更工作流文件表对应的实例Id
if (fileItems != null && !fileItems.isEmpty()) { if (fileItems != null && !fileItems.isEmpty()) {
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ; uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
} }
return receipt.getId(); return receipt.getId();
@ -152,11 +149,13 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
List<Long> userIds = new ArrayList<>(); List<Long> userIds = new ArrayList<>();
if ("my".equals(pageReqVO.getRelation())) { if ("my".equals(pageReqVO.getRelation())) {
userIds.add(getLoginUserId()); userIds.add(getLoginUserId());
}else if ("sub".equals(pageReqVO.getRelation())){ } else if ("sub".equals(pageReqVO.getRelation())) {
// 查询当前用户 所有下级用户编号 // 查询当前用户 所有下级用户编号
userIds.addAll(userLiveTreeApi.getItemIdsByUserId(getLoginUserId()).getCheckedData()); userIds.addAll(userLiveTreeApi.getItemIdsByUserId(getLoginUserId()).getCheckedData());
} }
if (CollUtil.isEmpty(userIds)) {
return PageResult.empty();
}
return receiptMapper.selectReceiptPage(pageReqVO, userIds); return receiptMapper.selectReceiptPage(pageReqVO, userIds);
} }
@ -171,7 +170,9 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
@Override @Override
public List<BpmOAReceiptDO> getReceiptList(BpmOAReceiptVO respVO) { public List<BpmOAReceiptDO> getReceiptList(BpmOAReceiptVO respVO) {
if (CollUtil.isEmpty(respVO.getUserId())) {
return Collections.emptyList();
}
return receiptMapper.selectList(new LambdaQueryWrapperX<BpmOAReceiptDO>() return receiptMapper.selectList(new LambdaQueryWrapperX<BpmOAReceiptDO>()
.inIfPresent(BpmOAReceiptDO::getUserId, respVO.getUserId()) .inIfPresent(BpmOAReceiptDO::getUserId, respVO.getUserId())
.eq(BpmOAReceiptDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()) .eq(BpmOAReceiptDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult())
@ -185,8 +186,8 @@ public class BpmOAReceiptServiceImpl extends BpmOABaseService implements BpmOARe
} }
@Override @Override
public List<ReceiptSettlementDTO> getReceiptSettlement(LocalDateTime[] times) { public List<ReceiptSettlementDTO> getReceiptSettlement(ReceiptSettlementVO vo) {
return receiptMapper.getReceiptSettlement(times); return receiptMapper.getReceiptSettlement(vo);
} }
public static BigDecimal calculatePercentageChange(Object today, Object yesterday) { public static BigDecimal calculatePercentageChange(Object today, Object yesterday) {

View File

@ -69,12 +69,12 @@
WHERE WHERE
deleted = 0 deleted = 0
AND result = 2 AND result = 2
<if test="times != null and times.length > 0"> <if test="vo.createTime != null and vo.createTime.length > 0">
<if test="times[0] != null"> <if test="vo.createTime[0] != null">
and create_time &gt;= #{times[0]} and create_time &gt;= #{vo.createTime[0]}
</if> </if>
<if test="times[1] != null"> <if test="vo.createTime[1] != null">
and create_time &lt;= #{times[1]} and create_time &lt;= #{vo.createTime[1]}
</if> </if>
</if> </if>
GROUP BY user_id GROUP BY user_id

View File

@ -15,4 +15,6 @@ public interface ErrorCodeConstants {
ErrorCode INVOICE_NOT_EXISTS = new ErrorCode(200008, "发票不存在"); ErrorCode INVOICE_NOT_EXISTS = new ErrorCode(200008, "发票不存在");
ErrorCode ACHIEVEMENT_NOT_EXISTS = new ErrorCode(200009, "业绩目标不存在"); ErrorCode ACHIEVEMENT_NOT_EXISTS = new ErrorCode(200009, "业绩目标不存在");
ErrorCode NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED = new ErrorCode(200010, "未申请销售目标前不可编辑"); ErrorCode NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED = new ErrorCode(200010, "未申请销售目标前不可编辑");
ErrorCode THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY = new ErrorCode(200011, "系统已存在该客户,不可重复录入");
} }

View File

@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessTransferVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerTransferVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO;
import cn.iocoder.yudao.module.crm.service.crmbusiness.CrmBusinessService; import cn.iocoder.yudao.module.crm.service.crmbusiness.CrmBusinessService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
@ -62,6 +64,13 @@ public class CrmBusinessController {
return success(businessService.getBusiness(id)); return success(businessService.getBusiness(id));
} }
@PostMapping("/transfer")
@Operation(summary = "转移商机")
public CommonResult<Boolean> transferBusiness(@Valid @RequestBody CrmBusinessTransferVO transferVO) {
businessService.transfer(transferVO);
return success(true);
}
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得商机分页") @Operation(summary = "获得商机分页")
// @PreAuthorize("@ss.hasPermission('crm:business:query')") // @PreAuthorize("@ss.hasPermission('crm:business:query')")

View File

@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - 客户转移 VO")
@Data
public class CrmBusinessTransferVO {
@Schema(description = "商机ID")
private List<Long> businessIds;
@Schema(description = "接受员工ID")
private List<Long> ownerAdminIds;
@Schema(description = "分配方式")
private Integer averageType;
}

View File

@ -41,7 +41,6 @@ public class SalesPerformanceSettlementController {
@PutMapping("/update") @PutMapping("/update")
@Operation(summary = "更新销售业绩结算记录") @Operation(summary = "更新销售业绩结算记录")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-settlement:update')")
public CommonResult<Boolean> updateSalesPerformanceSettlement(@Valid @RequestBody SalesPerformanceSettlementSaveReqVO updateReqVO) { public CommonResult<Boolean> updateSalesPerformanceSettlement(@Valid @RequestBody SalesPerformanceSettlementSaveReqVO updateReqVO) {
salesPerformanceSettlementService.updateSalesPerformanceSettlement(updateReqVO); salesPerformanceSettlementService.updateSalesPerformanceSettlement(updateReqVO);
return success(true); return success(true);
@ -67,7 +66,6 @@ public class SalesPerformanceSettlementController {
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "获得销售业绩结算记录分页") @Operation(summary = "获得销售业绩结算记录分页")
@PreAuthorize("@ss.hasPermission('crm:sales-performance-settlement:query')")
public CommonResult<PageResult<SalesPerformanceSettlementRespVO>> getSalesPerformanceSettlementPage(@Valid SalesPerformanceSettlementPageReqVO pageReqVO) { public CommonResult<PageResult<SalesPerformanceSettlementRespVO>> getSalesPerformanceSettlementPage(@Valid SalesPerformanceSettlementPageReqVO pageReqVO) {
PageResult<SalesPerformanceSettlementDO> pageResult = salesPerformanceSettlementService.getSalesPerformanceSettlementPage(pageReqVO); PageResult<SalesPerformanceSettlementDO> pageResult = salesPerformanceSettlementService.getSalesPerformanceSettlementPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, SalesPerformanceSettlementRespVO.class)); return success(BeanUtils.toBean(pageResult, SalesPerformanceSettlementRespVO.class));

View File

@ -1,13 +1,15 @@
package cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo; package cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageParam;
import java.math.BigDecimal; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ -59,6 +61,12 @@ public class SalesPerformanceSettlementPageReqVO extends PageParam {
@Schema(description = "是否可以确认 0否 1是") @Schema(description = "是否可以确认 0否 1是")
private Integer canConfirmFlag; private Integer canConfirmFlag;
@Schema(description = "评分状态 0待评分 1已评分")
private Integer scoreStatus;
@Schema(description = "结算状态 0待结算 1已结算待评分 2已结算")
private Integer settlementStatus;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime; private LocalDateTime[] createTime;
@ -66,4 +74,7 @@ public class SalesPerformanceSettlementPageReqVO extends PageParam {
@Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "27486") @Schema(description = "用户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "27486")
private String nickname; private String nickname;
@Schema(description = "用户ids", example = "27486")
private List<Long> userIds;
} }

View File

@ -44,6 +44,12 @@ public class SalesPerformanceSettlementRespVO {
@Schema(description = "实际销售额") @Schema(description = "实际销售额")
private Integer actualSale; private Integer actualSale;
@Schema(description = "回款目标")
private BigDecimal paymentTarget;
@Schema(description = "销售目标")
private Integer saleTarget;
@Schema(description = "评分") @Schema(description = "评分")
private BigDecimal score; private BigDecimal score;
@ -68,6 +74,12 @@ public class SalesPerformanceSettlementRespVO {
@Schema(description = "是否可以确认 0否 1是") @Schema(description = "是否可以确认 0否 1是")
private Integer canConfirmFlag; private Integer canConfirmFlag;
@Schema(description = "评分状态 0待评分 1已评分")
private Integer scoreStatus;
@Schema(description = "结算状态 0待结算 1已结算待评分 2已结算")
private Integer settlementStatus;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间") @ExcelProperty("创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;

View File

@ -59,4 +59,9 @@ public class SalesPerformanceSettlementSaveReqVO {
@Schema(description = "是否可以确认 0否 1是") @Schema(description = "是否可以确认 0否 1是")
private Integer canConfirmFlag; private Integer canConfirmFlag;
@Schema(description = "评分状态 0待评分 1已评分")
private Integer scoreStatus;
@Schema(description = "结算状态 0待结算 1已结算待评分 2已结算")
private Integer settlementStatus;
} }

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.*;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -86,9 +87,28 @@ public class SalesPerformanceSettlementDO extends BaseDO {
* 是否可以确认 0否 1是 * 是否可以确认 0否 1是
*/ */
private Integer canConfirmFlag; private Integer canConfirmFlag;
/**
* 评分状态 0待评分 1已评分
*/
private Integer scoreStatus;
/**
* 结算状态 0待结算 1已结算待评分 2已结算
*/
private Integer settlementStatus;
/** /**
* 昵称 * 昵称
*/ */
@TableField(exist = false) @TableField(exist = false)
private String nickname; private String nickname;
/**
* 回款目标
*/
@TableField(exist = false)
private BigDecimal paymentTarget;
/**
* 销售目标
*/
@TableField(exist = false)
private Integer saleTarget;
} }

View File

@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi; import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.mail.MailSendApi; import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
import cn.iocoder.yudao.module.system.api.notice.NoticeApi; import cn.iocoder.yudao.module.system.api.notice.NoticeApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi; import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -18,6 +19,6 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableFeignClients(clients = {DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class, @EnableFeignClients(clients = {DeptApi.class, DictDataApi.class, AdminUserApi.class, StoreProductApi.class, StoreProductAttrValueApi.class, SmsSendApi.class, MailSendApi.class, NoticeApi.class,
BpmOAContractApi.class, BpmOAReceiptApi.class, BpmOASalesPerformanceApi.class, AdminOauthUserOtherInfoApi.class, SubscribeMessageSendApi.class}) BpmOAContractApi.class, BpmOAReceiptApi.class, BpmOASalesPerformanceApi.class, AdminOauthUserOtherInfoApi.class, SubscribeMessageSendApi.class, RoleApi.class})
public class RpcConfiguration { public class RpcConfiguration {
} }

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.module.crm.job.salesperformance;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.crm.service.salesperformancesettlement.SalesPerformanceSettlementService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
@Slf4j
public class AutoConfirmJob {
// TODO: 2024/11/04 - 每个月月初03号 未确认的 自动确认上个月的结算记录
@Resource
private SalesPerformanceSettlementService salesPerformanceSettlementService;
@XxlJob("autoConfirmJob")
@TenantJob // --- 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
public ReturnT<String> execute() {
log.info("开始 自动确认");
salesPerformanceSettlementService.autoConfirmJob();
log.info("结束 自动确认");
return ReturnT.SUCCESS;
}
}

View File

@ -357,11 +357,6 @@ public class CrmAchievementServiceImpl implements CrmAchievementService {
.setStarTime(starTime) .setStarTime(starTime)
.setEndTime(endTime)).getCheckedData(); .setEndTime(endTime)).getCheckedData();
// List<CrmContractReceivablesDO> crmContractReceivablesDOS = contractReceivablesMapper
// .selectList(new LambdaQueryWrapper<CrmContractReceivablesDO>()
// .in(CrmContractReceivablesDO::getOwnerUserId, userIds)
// .eq(CrmContractReceivablesDO::getCheckStatus, ContractStatusEnum.STATUS_2.getValue())
// .between(CrmContractReceivablesDO::getReturnTime, starTime, endTime));
BigDecimal receivablesSuccessMoney = BigDecimal.ZERO; BigDecimal receivablesSuccessMoney = BigDecimal.ZERO;
if (CollectionUtil.isNotEmpty(receiptDTOS)) { if (CollectionUtil.isNotEmpty(receiptDTOS)) {
receivablesSuccessMoney = receiptDTOS receivablesSuccessMoney = receiptDTOS

View File

@ -198,6 +198,9 @@ public class AchievementServiceImpl implements AchievementService {
} else if (RelationEnum.SUB.getValue().equals(relation)) { } else if (RelationEnum.SUB.getValue().equals(relation)) {
userIds = userLiveTreeService.getItemIdsByUserId(userId); userIds = userLiveTreeService.getItemIdsByUserId(userId);
} }
if (CollUtil.isEmpty(userIds)){
return Collections.emptyList();
}
//合同目标 //合同目标
List<CrmAchievementDO> crmAchievementDO = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>() List<CrmAchievementDO> crmAchievementDO = achievementMapper.selectList(new LambdaQueryWrapperX<CrmAchievementDO>()
.eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue()) .eq(CrmAchievementDO::getType, FlowStepEnum.TYPE_2.getValue())
@ -364,6 +367,9 @@ public class AchievementServiceImpl implements AchievementService {
} else if (RelationEnum.SUB.getValue().equals(relation)) { } else if (RelationEnum.SUB.getValue().equals(relation)) {
userIds = userLiveTreeService.getItemIdsByUserId(userId); userIds = userLiveTreeService.getItemIdsByUserId(userId);
} }
if (CollUtil.isEmpty(userIds)){
return Collections.emptyList();
}
List<SalesVO> salesVOS = new ArrayList<>(); List<SalesVO> salesVOS = new ArrayList<>();
int i = 1; int i = 1;
while (i <= 12) { while (i <= 12) {

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessTransferVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO;
import javax.validation.Valid; import javax.validation.Valid;
@ -65,4 +66,10 @@ public interface CrmBusinessService {
*/ */
List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId); List<CrmBusinessProductDO> getBusinessProductListByBusinessId(Long businessId);
/**
* 转移商机
*
* @param transferVO
*/
void transfer(@Valid CrmBusinessTransferVO transferVO);
} }

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.crm.service.crmbusiness; package cn.iocoder.yudao.module.crm.service.crmbusiness;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
@ -8,7 +10,7 @@ import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessSaveReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.crmclues.vo.CrmCluesRespVO; import cn.iocoder.yudao.module.crm.controller.admin.crmbusiness.vo.CrmBusinessTransferVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO; import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO; import cn.iocoder.yudao.module.crm.dal.dataobject.crmbusiness.CrmBusinessProductDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO; import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
@ -17,13 +19,13 @@ import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessProductMapper; import cn.iocoder.yudao.module.crm.dal.mysql.crmbusiness.CrmBusinessProductMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper; import cn.iocoder.yudao.module.crm.dal.mysql.crmcustomer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper; import cn.iocoder.yudao.module.crm.dal.mysql.crmrecord.CrmRecordMapper;
import cn.iocoder.yudao.module.crm.service.crmoperatelog.CrmOperatelogService;
import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService; import cn.iocoder.yudao.module.crm.service.userlivetree.UserLiveTreeService;
import cn.iocoder.yudao.module.hrm.enums.RelationEnum; import cn.iocoder.yudao.module.hrm.enums.RelationEnum;
import cn.iocoder.yudao.module.hrm.enums.TypesEnum; import cn.iocoder.yudao.module.hrm.enums.TypesEnum;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi; import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO; import cn.iocoder.yudao.module.product.api.storeproductattrvalue.dto.StoreProductAttrValueApiDTO;
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO; import cn.iocoder.yudao.module.product.api.storeproductattrvalue.vo.StoreProductAttrValueApiVO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -34,6 +36,7 @@ import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -61,6 +64,8 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
private CrmRecordMapper crmRecordMapper; private CrmRecordMapper crmRecordMapper;
@Resource @Resource
private UserLiveTreeService userLiveTreeService; private UserLiveTreeService userLiveTreeService;
@Resource
private CrmOperatelogService crmOperatelogService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -130,7 +135,9 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) { } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(adminId); ids = userLiveTreeService.getItemIdsByUserId(adminId);
} }
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO); IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmBusinessRespVO> page = businessMapper.selectPageList(mpPage, pageReqVO, ids); IPage<CrmBusinessRespVO> page = businessMapper.selectPageList(mpPage, pageReqVO, ids);
return new PageResult<>(page.getRecords(), page.getTotal()); return new PageResult<>(page.getRecords(), page.getTotal());
@ -160,6 +167,44 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
return businessProductDOS; return businessProductDOS;
} }
@Override
@Transactional(rollbackFor = Exception.class)
public void transfer(CrmBusinessTransferVO transferVO) {
//客户
List<CrmBusinessDO> crmBusinessDOS = businessMapper.selectBatchIds(transferVO.getBusinessIds());
if (crmBusinessDOS == null || crmBusinessDOS.isEmpty()) {
throw exception(new ErrorCode(202409091, "商机信息不存在"));
}
int adminCount = transferVO.getOwnerAdminIds().size();
int i = 0;
List<CrmBusinessDO> businessUpdateList = new ArrayList<>();
for (CrmBusinessDO businessDO : crmBusinessDOS) {
Long adminId;
if (ShopCommonEnum.AVG_1.getValue().equals(transferVO.getAverageType())) {
//平均分配
adminId = transferVO.getOwnerAdminIds().get(i);
if (i == (adminCount - 1)) {
i = 0;
} else {
i++;
}
} else {
//随机分配
Random random = new Random();
int num = random.nextInt(adminCount);
adminId = transferVO.getOwnerAdminIds().get(num);
}
businessDO.setOwnerUserId(adminId);
businessUpdateList.add(businessDO);
//处理日志
crmOperatelogService.createLog("转移商机", businessDO.getCustomerId(), 0L, 0L);
}
if (CollUtil.isNotEmpty(businessUpdateList)) {
businessMapper.updateBatch(businessUpdateList);
}
}
private void createBusinessProductList(Long businessId, List<CrmBusinessProductDO> list) { private void createBusinessProductList(Long businessId, List<CrmBusinessProductDO> list) {
list.forEach(o -> o.setBusinessId(businessId)); list.forEach(o -> o.setBusinessId(businessId));
businessProductMapper.insertBatch(list); businessProductMapper.insertBatch(list);

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmclues; package cn.iocoder.yudao.module.crm.service.crmclues;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum; import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode; import cn.iocoder.yudao.framework.common.exception.ErrorCode;
@ -40,6 +41,7 @@ import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CLUES_NOT_EXISTS; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CLUES_NOT_EXISTS;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY;
/** /**
* 线索 Service 实现类 * 线索 Service 实现类
@ -118,7 +120,9 @@ public class CrmCluesServiceImpl implements CrmCluesService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) { } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(adminId); ids = userLiveTreeService.getItemIdsByUserId(adminId);
} }
if (CollUtil.isEmpty(ids)){
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO); IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmCluesRespVO> page = cluesMapper.selectPageList(mpPage, pageReqVO, ids); IPage<CrmCluesRespVO> page = cluesMapper.selectPageList(mpPage, pageReqVO, ids);
return new PageResult<>(page.getRecords(), page.getTotal()); return new PageResult<>(page.getRecords(), page.getTotal());
@ -157,13 +161,18 @@ public class CrmCluesServiceImpl implements CrmCluesService {
if(CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())){ if(CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())){
throw exception(new ErrorCode(202411160,"已经转化成客户!")); throw exception(new ErrorCode(202411160,"已经转化成客户!"));
} }
// 判断客户名称是否唯一
Long count = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.eq(CrmCustomerDO::getName, createReqVO.getName()));
if (count > 0) {
throw exception(THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY);
}
createReqVO.setId(null); createReqVO.setId(null);
CrmCustomerDO customerDO = BeanUtils.toBean(createReqVO, CrmCustomerDO.class); CrmCustomerDO customerDO = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId()); customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
customerDO.setNextTime(LocalDateTime.now()); customerDO.setNextTime(LocalDateTime.now());
customerDO.setCollectTime(LocalDateTime.now()); customerDO.setCollectTime(LocalDateTime.now());
customerMapper.insert(customerDO); customerMapper.insert(customerDO);
//更新线索 //更新线索
crmCluesDO.setStatus(CluesStatusEnum.STATUS_1.getValue()); crmCluesDO.setStatus(CluesStatusEnum.STATUS_1.getValue());
crmCluesDO.setCustomerId(customerDO.getId()); crmCluesDO.setCustomerId(customerDO.getId());

View File

@ -408,30 +408,30 @@ public class CrmContractServiceImpl implements CrmContractService {
} }
private void createContractProductList(Long contractId, List<CrmContractProductDO> list) { private void createContractProductList(Long contractId, List<CrmContractProductDO> list) {
List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>(); // List<StoreProductAttrValueApiVO> storeProductAttrValueList = new ArrayList<>();
if (CollUtil.isNotEmpty(list)) { // if (CollUtil.isNotEmpty(list)) {
List<Long> productIds = list.stream().map(CrmContractProductDO::getProductId).collect(Collectors.toList()); // List<Long> productIds = list.stream().map(CrmContractProductDO::getProductId).collect(Collectors.toList());
List<String> productAttrUnique = list.stream().map(CrmContractProductDO::getProductAttrUnique).collect(Collectors.toList()); // List<String> productAttrUnique = list.stream().map(CrmContractProductDO::getProductAttrUnique).collect(Collectors.toList());
storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO() // storeProductAttrValueList = storeProductAttrValueApi.getStoreProductAttrValueList(new StoreProductAttrValueApiDTO()
.setProductIds(productIds) // .setProductIds(productIds)
.setUniques(productAttrUnique)).getCheckedData(); // .setUniques(productAttrUnique)).getCheckedData();
} // }
Map<String, List<StoreProductAttrValueApiVO>> map = storeProductAttrValueList.stream().collect(Collectors.groupingBy(a -> a.getProductId() + "_" + a.getUnique())); // Map<String, List<StoreProductAttrValueApiVO>> map = storeProductAttrValueList.stream().collect(Collectors.groupingBy(a -> a.getProductId() + "_" + a.getUnique()));
list.forEach(o -> { // list.forEach(o -> {
o.setContractId(contractId); // o.setContractId(contractId);
//库存处理 // //库存处理
List<StoreProductAttrValueApiVO> storeProductAttrValueApiVOS = map.get(o.getProductId() + "_" + o.getProductAttrUnique()); // List<StoreProductAttrValueApiVO> storeProductAttrValueApiVOS = map.get(o.getProductId() + "_" + o.getProductAttrUnique());
//
int count = 0; // int count = 0;
if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) { // if (CollUtil.isNotEmpty(storeProductAttrValueApiVOS)) {
count = storeProductAttrValueApiVOS.stream().mapToInt(StoreProductAttrValueApiVO::getStock).sum(); // count = storeProductAttrValueApiVOS.stream().mapToInt(StoreProductAttrValueApiVO::getStock).sum();
} // }
if (NumberUtil.compare(count, o.getNums()) < 0) { // if (NumberUtil.compare(count, o.getNums()) < 0) {
throw exception(new ErrorCode(202408250, "该商品ID" + o.getProductId() + "库存不足")); // throw exception(new ErrorCode(202408250, "该商品ID" + o.getProductId() + "库存不足"));
} // }
// TODO: 2024/11/21 这里的库存扣件完后 - 如果审批不通过 库存退回 // // TODO: 2024/11/21 这里的库存扣件完后 - 如果审批不通过 库存退回
this.decProductStock(o.getNums(), o.getProductId(), o.getProductAttrUnique()); // this.decProductStock(o.getNums(), o.getProductId(), o.getProductAttrUnique());
}); // });
contractProductMapper.insertBatch(list); contractProductMapper.insertBatch(list);
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmcontractreceivables; package cn.iocoder.yudao.module.crm.service.crmcontractreceivables;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.PatternPool; import cn.hutool.core.lang.PatternPool;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
@ -186,6 +187,9 @@ public class CrmContractReceivablesServiceImpl implements CrmContractReceivables
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) { } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(loginAdminId); ids = userLiveTreeService.getItemIdsByUserId(loginAdminId);
} }
if (CollUtil.isEmpty(ids)){
return PageResult.empty();
}
pageReqVO.setLoginAdminId(loginAdminId); pageReqVO.setLoginAdminId(loginAdminId);
IPage mpPage = MyBatisUtils.buildPage(pageReqVO); IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmContractReceivablesRespVO> pageResult = contractReceivablesMapper.selectPageList(mpPage, pageReqVO, ids); IPage<CrmContractReceivablesRespVO> pageResult = contractReceivablesMapper.selectPageList(mpPage, pageReqVO, ids);

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmcustomer; package cn.iocoder.yudao.module.crm.service.crmcustomer;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum; import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
@ -49,6 +50,7 @@ import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.CUSTOMER_NOT_EXISTS;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY;
/** /**
* 客户 Service 实现类 * 客户 Service 实现类
@ -87,8 +89,13 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createCustomer(CrmCustomerSaveReqVO createReqVO) { public Long createCustomer(CrmCustomerSaveReqVO createReqVO) {
// 插入 // 插入
// 判断客户名称是否唯一
Long count = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
.eq(CrmCustomerDO::getName, createReqVO.getName()));
if (count > 0) {
throw exception(THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY);
}
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class); CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
customer.setCollectTime(LocalDateTime.now()); customer.setCollectTime(LocalDateTime.now());
customer.setFollowTime(LocalDateTime.now()); customer.setFollowTime(LocalDateTime.now());
@ -245,6 +252,9 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
ids = userLiveTreeService.getItemIdsByUserId(adminId); ids = userLiveTreeService.getItemIdsByUserId(adminId);
} }
} }
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
return customerMapper.selectPage(pageReqVO, ids); return customerMapper.selectPage(pageReqVO, ids);
} }
@ -262,6 +272,9 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
ids = userLiveTreeService.getItemIdsByUserId(adminId); ids = userLiveTreeService.getItemIdsByUserId(adminId);
} }
} }
if (CollUtil.isEmpty(ids)) {
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO); IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids); IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids);
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crmcustomercontacts; package cn.iocoder.yudao.module.crm.service.crmcustomercontacts;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
@ -91,6 +92,9 @@ public class CrmCustomerContactsServiceImpl implements CrmCustomerContactsServic
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) { } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(adminId); ids = userLiveTreeService.getItemIdsByUserId(adminId);
} }
if (CollUtil.isEmpty(ids)){
return PageResult.empty();
}
IPage mpPage = MyBatisUtils.buildPage(pageReqVO); IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
IPage<CrmCustomerContactsRespVO> pageResult = customerContactsMapper.selectPageList(mpPage, pageReqVO, ids); IPage<CrmCustomerContactsRespVO> pageResult = customerContactsMapper.selectPageList(mpPage, pageReqVO, ids);
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.crm.service.crmindex; package cn.iocoder.yudao.module.crm.service.crmindex;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum; import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi; import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi; import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
@ -101,7 +103,9 @@ public class CrmIndexServiceImpl implements CrmIndexService {
ids = userLiveTreeService.getItemIdsByUserId(adminId); ids = userLiveTreeService.getItemIdsByUserId(adminId);
} }
} }
if (CollUtil.isEmpty(ids)){
return BrieCountVO.builder().build();
}
Long count01 = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>() Long count01 = businessMapper.selectCount(new LambdaQueryWrapper<CrmBusinessDO>()
.in(!ids.isEmpty(), CrmBusinessDO::getOwnerUserId, ids) .in(!ids.isEmpty(), CrmBusinessDO::getOwnerUserId, ids)
.between(CrmBusinessDO::getCreateTime, todayStart, todayEnd)); .between(CrmBusinessDO::getCreateTime, todayStart, todayEnd));

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.crminvoice; package cn.iocoder.yudao.module.crm.service.crminvoice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum; import cn.iocoder.yudao.framework.common.enums.ShopCommonEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode; import cn.iocoder.yudao.framework.common.exception.ErrorCode;
@ -181,6 +182,9 @@ public class CrmInvoiceServiceImpl implements CrmInvoiceService {
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) { } else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
ids = userLiveTreeService.getItemIdsByUserId(loginAdminId); ids = userLiveTreeService.getItemIdsByUserId(loginAdminId);
} }
if (CollUtil.isEmpty(ids)){
return PageResult.empty();
}
PageResult<CrmInvoiceRespVO> pageResult = invoiceMapper.selectPage2(pageReqVO, ids); PageResult<CrmInvoiceRespVO> pageResult = invoiceMapper.selectPage2(pageReqVO, ids);
for (CrmInvoiceRespVO respVO : pageResult.getList()) { for (CrmInvoiceRespVO respVO : pageResult.getList()) {
List<String> adminIds = StrUtil.split(respVO.getFlowAdminId(), ","); List<String> adminIds = StrUtil.split(respVO.getFlowAdminId(), ",");

View File

@ -43,7 +43,6 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.RECORD_NOT_EXISTS; import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.RECORD_NOT_EXISTS;
/** /**
@ -71,6 +70,7 @@ public class CrmRecordServiceImpl implements CrmRecordService {
private DictDataApi dictDataApi; private DictDataApi dictDataApi;
@Resource @Resource
private UserLiveTreeService userLiveTreeService; private UserLiveTreeService userLiveTreeService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public Long createRecord(CrmRecordSaveReqVO createReqVO) { public Long createRecord(CrmRecordSaveReqVO createReqVO) {
@ -156,7 +156,7 @@ public class CrmRecordServiceImpl implements CrmRecordService {
List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id)); List<CrmRecordUserDO> crmRecordUserDOS = crmRecordUserMapper.selectList(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id));
crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id).eq(CrmRecordUserDO::getUserId, adminId)); crmRecordUserMapper.delete(new LambdaQueryWrapper<CrmRecordUserDO>().eq(CrmRecordUserDO::getRecordId, id).eq(CrmRecordUserDO::getUserId, adminId));
// 删除如果是最后一个的话删除一下 // 删除如果是最后一个的话删除一下
if (crmRecordUserDOS.size() == 1 && adminId.equals(crmRecordUserDOS.get(0).getUserId())){ if (crmRecordUserDOS.size() == 1 && adminId.equals(crmRecordUserDOS.get(0).getUserId())) {
recordMapper.deleteById(id); recordMapper.deleteById(id);
} }
} }

View File

@ -63,4 +63,9 @@ public interface SalesPerformanceSettlementService extends IService<SalesPerform
* 生成下一个月的业绩 * 生成下一个月的业绩
*/ */
void generateSalesPerformanceJob(); void generateSalesPerformanceJob();
/**
* 自动确认上个月的业绩
*/
void autoConfirmJob();
} }

View File

@ -11,10 +11,12 @@ import cn.iocoder.yudao.framework.common.util.number.BigDecimalUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi; import cn.iocoder.yudao.module.bpm.api.oa.BpmOAContractApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi; import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReceiptApi;
import cn.iocoder.yudao.module.bpm.api.oa.BpmOASalesPerformanceApi; import cn.iocoder.yudao.module.bpm.api.oa.BpmOASalesPerformanceApi;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementDTO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.receipt.ReceiptSettlementVO;
import cn.iocoder.yudao.module.bpm.api.oa.vo.salesperformance.SalesPerformanceDTO; import cn.iocoder.yudao.module.bpm.api.oa.vo.salesperformance.SalesPerformanceDTO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementPageReqVO; import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementSaveReqVO; import cn.iocoder.yudao.module.crm.controller.admin.salesperformancesettlement.vo.SalesPerformanceSettlementSaveReqVO;
@ -31,12 +33,14 @@ import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductSettlem
import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi; import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi;
import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO; import cn.iocoder.yudao.module.system.api.auth.dto.AdminOauthUserOtherInfoApiDTO;
import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO; import cn.iocoder.yudao.module.system.api.auth.vo.AdminOauthUserOtherInfoApiVO;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi; import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.ognl.Ognl; import org.apache.ibatis.ognl.Ognl;
import org.apache.ibatis.ognl.OgnlException; import org.apache.ibatis.ognl.OgnlException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -60,6 +64,7 @@ import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.NOT_EDITABLE_
*/ */
@Service @Service
@Validated @Validated
@Slf4j
public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerformanceSettlementMapper, SalesPerformanceSettlementDO> implements SalesPerformanceSettlementService { public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerformanceSettlementMapper, SalesPerformanceSettlementDO> implements SalesPerformanceSettlementService {
@Resource @Resource
@ -84,6 +89,8 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
private AdminUserApi adminUserApi; private AdminUserApi adminUserApi;
@Resource @Resource
private BpmOAContractApi bpmOAContractApi; private BpmOAContractApi bpmOAContractApi;
@Resource
private RoleApi roleApi;
//百分比 //百分比
private static final BigDecimal PERCENTAGE = new BigDecimal("0.01"); private static final BigDecimal PERCENTAGE = new BigDecimal("0.01");
@ -120,8 +127,8 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
// 未申请销售目标前不可编辑 // 未申请销售目标前不可编辑
throw exception(NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED); throw exception(NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED);
} }
BigDecimal saleScore = BigDecimal.valueOf(updateObj.getActualSale()) BigDecimal saleScore = (salesPerformanceDTO.getSaleTarget() == null || salesPerformanceDTO.getSaleTarget() == 0) ? BigDecimal.ZERO :
.divide(BigDecimal.valueOf(salesPerformanceDTO.getSaleTarget()), 2, RoundingMode.HALF_UP); (BigDecimal.valueOf(updateObj.getActualSale()).divide(BigDecimal.valueOf(salesPerformanceDTO.getSaleTarget()), 2, RoundingMode.HALF_UP));
saleScore = (saleScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getSaleWeight() : saleScore = (saleScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getSaleWeight() :
salesPerformanceWeight.getSaleWeight().multiply(saleScore); salesPerformanceWeight.getSaleWeight().multiply(saleScore);
// 销售任务最终得分 // 销售任务最终得分
@ -133,8 +140,8 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
// 未申请销售目标前不可编辑 // 未申请销售目标前不可编辑
throw exception(NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED); throw exception(NOT_EDITABLE_UNTIL_SALES_TARGET_HAS_BEEN_APPLIED);
} }
BigDecimal paymentScore = updateObj.getActualPayment() BigDecimal paymentScore = BigDecimalUtil.isEqZero(salesPerformanceDTO.getPaymentTarget()) ? BigDecimal.ZERO :
.divide(salesPerformanceDTO.getPaymentTarget(), 2, RoundingMode.HALF_UP); (updateObj.getActualPayment().divide(salesPerformanceDTO.getPaymentTarget(), 2, RoundingMode.HALF_UP));
paymentScore = (paymentScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getPaymentWeight() : paymentScore = (paymentScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getPaymentWeight() :
salesPerformanceWeight.getPaymentWeight().multiply(paymentScore); salesPerformanceWeight.getPaymentWeight().multiply(paymentScore);
// 回款任务最终得分 // 回款任务最终得分
@ -149,6 +156,11 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
// 回款任务最终得分 // 回款任务最终得分
updateObj.setScoreTask(score); updateObj.setScoreTask(score);
changeFlag = true; changeFlag = true;
// --
updateObj.setScoreStatus(1);
if (salesPerformanceSettlementDO.getSettlementStatus() == 1) {
updateObj.setSettlementStatus(2);
}
} }
if (changeFlag) { if (changeFlag) {
// 重新计算 - // 重新计算 -
@ -179,19 +191,26 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
@Override @Override
public PageResult<SalesPerformanceSettlementDO> getSalesPerformanceSettlementPage(SalesPerformanceSettlementPageReqVO pageReqVO) { public PageResult<SalesPerformanceSettlementDO> getSalesPerformanceSettlementPage(SalesPerformanceSettlementPageReqVO pageReqVO) {
Long userId = SecurityFrameworkUtils.getLoginUserId();
// -- 这里要做什么 要筛选出可见范围 - 但是crm用户不和system 用户 结构一体 - 所以 需要从代码中来区分 - 我们设定一个角色 可以看全部内容 - 完了后 其他的用户只能看自己以及下级的信息 通过pid id来判断
// 那么怎么获取到这个用户有没有包含这个角色呢
boolean calculator = roleApi.validCalculator(userId).getCheckedData();
if (!calculator) {
List<Long> userIds = userLiveTreeService.getItemIdsByUserId(userId);
userIds.add(userId);
pageReqVO.setUserIds(userIds);
}
IPage<SalesPerformanceSettlementDO> pageResult = salesPerformanceSettlementMapper.getSalesPerformanceSettlementPage(pageReqVO, MyBatisUtils.buildPage(pageReqVO)); IPage<SalesPerformanceSettlementDO> pageResult = salesPerformanceSettlementMapper.getSalesPerformanceSettlementPage(pageReqVO, MyBatisUtils.buildPage(pageReqVO));
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal()); return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
} }
@Override @Override
public void settlement() { public void settlement() {
// LocalDateTime now = LocalDateTime.now().minusMonths(1L); LocalDateTime now = LocalDateTime.now().minusMonths(1L);
LocalDateTime now = LocalDateTime.now();
String year = String.valueOf(now.getYear()); String year = String.valueOf(now.getYear());
String month = String.format("%02d", now.getMonthValue()); String month = String.format("%02d", now.getMonthValue());
// 获取CRM用户一下 // 获取CRM用户一下
// List<UserLiveTreeListVO> userLiveList = userLiveTreeService.getUserLiveList(); List<UserLiveTreeListVO> userLiveList = userLiveTreeService.getUserLiveList();
List<UserLiveTreeListVO> userLiveList = Arrays.asList(new UserLiveTreeListVO().setUserId(152L));
// 计算当前月所有销售的 销售额 - 销售台数 // 计算当前月所有销售的 销售额 - 销售台数
// -- 合同产品数量 后续可能需要根据不同的产品来定目标 - 所以这里 我们预判下 - 将合同对应的projectId也查询出来 好方便后续做产品区分 // -- 合同产品数量 后续可能需要根据不同的产品来定目标 - 所以这里 我们预判下 - 将合同对应的projectId也查询出来 好方便后续做产品区分
List<CrmContractProductSettlementDTO> contractProductSettlementDTOList = crmContractService.getContractProductSettlement(); List<CrmContractProductSettlementDTO> contractProductSettlementDTOList = crmContractService.getContractProductSettlement();
@ -204,7 +223,9 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
LocalDateTime beginTime = LocalDateTimeUtils.beginOfMonth(now); LocalDateTime beginTime = LocalDateTimeUtils.beginOfMonth(now);
LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(now); LocalDateTime endTime = LocalDateTimeUtils.endOfMonth(now);
LocalDateTime[] times = {beginTime, endTime}; LocalDateTime[] times = {beginTime, endTime};
List<ReceiptSettlementDTO> receiptSettlementList = receiptApi.getReceiptSettlement(times).getCheckedData(); ReceiptSettlementVO receiptSettlementVO = new ReceiptSettlementVO();
receiptSettlementVO.setCreateTime(times);
List<ReceiptSettlementDTO> receiptSettlementList = receiptApi.getReceiptSettlement(receiptSettlementVO).getCheckedData();
receiptSettlementList = CollUtil.isEmpty(receiptSettlementList) ? Collections.emptyList() : receiptSettlementList; receiptSettlementList = CollUtil.isEmpty(receiptSettlementList) ? Collections.emptyList() : receiptSettlementList;
Map<Long, BigDecimal> receiptSettlementMap = receiptSettlementList.stream() Map<Long, BigDecimal> receiptSettlementMap = receiptSettlementList.stream()
.collect(Collectors.toMap(ReceiptSettlementDTO::getUserId, ReceiptSettlementDTO::getMoney)); .collect(Collectors.toMap(ReceiptSettlementDTO::getUserId, ReceiptSettlementDTO::getMoney));
@ -232,20 +253,25 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
salesPerformanceSettlementDO.setActualSale(productMap.getOrDefault(vo.getUserId(), 0)); salesPerformanceSettlementDO.setActualSale(productMap.getOrDefault(vo.getUserId(), 0));
salesPerformanceSettlementDO.setActualPayment(receiptSettlementMap.getOrDefault(vo.getUserId(), BigDecimal.ZERO)); salesPerformanceSettlementDO.setActualPayment(receiptSettlementMap.getOrDefault(vo.getUserId(), BigDecimal.ZERO));
SalesPerformanceDTO salesPerformanceDTO = salesPerformanceMap.get(vo.getUserId()); SalesPerformanceDTO salesPerformanceDTO = salesPerformanceMap.get(vo.getUserId());
if (salesPerformanceDTO == null) {
continue;
}
// 计算得分 // 计算得分
if (salesPerformanceWeight != null) { if (salesPerformanceWeight != null) {
// -- 如果实际/目标>0则拿到全额的权重 // -- 如果实际/目标>0则拿到全额的权重
// ----------- 销售任务得分计算 ----------- // ----------- 销售任务得分计算 -----------
BigDecimal saleScore = BigDecimal.valueOf(salesPerformanceSettlementDO.getActualSale()) BigDecimal saleScore = (salesPerformanceDTO.getSaleTarget() == null || salesPerformanceDTO.getSaleTarget() == 0) ? BigDecimal.ZERO :
.divide(BigDecimal.valueOf(salesPerformanceDTO.getSaleTarget()), 2, RoundingMode.HALF_UP); (BigDecimal.valueOf(salesPerformanceSettlementDO.getActualSale())
.divide(BigDecimal.valueOf(salesPerformanceDTO.getSaleTarget()), 2, RoundingMode.HALF_UP));
saleScore = (saleScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getSaleWeight() : saleScore = (saleScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getSaleWeight() :
salesPerformanceWeight.getSaleWeight().multiply(saleScore); salesPerformanceWeight.getSaleWeight().multiply(saleScore);
// 销售任务最终得分 // 销售任务最终得分
salesPerformanceSettlementDO.setSaleTask(saleScore); salesPerformanceSettlementDO.setSaleTask(saleScore);
// ----------- 回款任务得分计算 ----------- // ----------- 回款任务得分计算 -----------
BigDecimal paymentScore = salesPerformanceSettlementDO.getActualPayment() BigDecimal paymentScore = BigDecimalUtil.isEqZero(salesPerformanceDTO.getPaymentTarget()) ? BigDecimal.ZERO :
.divide(salesPerformanceDTO.getPaymentTarget(), 2, RoundingMode.HALF_UP); (salesPerformanceSettlementDO.getActualPayment()
.divide(salesPerformanceDTO.getPaymentTarget(), 2, RoundingMode.HALF_UP));
paymentScore = (paymentScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getPaymentWeight() : paymentScore = (paymentScore.compareTo(BigDecimal.ONE) >= 0) ? salesPerformanceWeight.getPaymentWeight() :
salesPerformanceWeight.getPaymentWeight().multiply(paymentScore); salesPerformanceWeight.getPaymentWeight().multiply(paymentScore);
// 回款任务最终得分 // 回款任务最终得分
@ -272,6 +298,7 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
} }
} }
salesPerformanceSettlementDO.setCanConfirmFlag(1); salesPerformanceSettlementDO.setCanConfirmFlag(1);
salesPerformanceSettlementDO.setSettlementStatus(salesPerformanceSettlementDO.getScoreStatus() == 1 ? 2 : 1);
} }
list.add(salesPerformanceSettlementDO); list.add(salesPerformanceSettlementDO);
} }
@ -286,7 +313,8 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
List<AdminOauthUserOtherInfoApiVO> adminOauthUserOtherInfoApiVOS = adminOauthUserOtherInfoApi.getOpenIdByCondition( List<AdminOauthUserOtherInfoApiVO> adminOauthUserOtherInfoApiVOS = adminOauthUserOtherInfoApi.getOpenIdByCondition(
new AdminOauthUserOtherInfoApiDTO().setUserIds(userIds) new AdminOauthUserOtherInfoApiDTO().setUserIds(userIds)
.setSocialType(SocialTypeEnum.WECHAT_MP.getType())).getCheckedData(); .setSocialType(SocialTypeEnum.WECHAT_MP.getType())).getCheckedData();
log.info("用户列表:{}", userIds);
log.info("用户三方账号列表:{}", adminOauthUserOtherInfoApiVOS);
// - 结算完毕 - 通知所有填写申请到crm用户确认 // - 结算完毕 - 通知所有填写申请到crm用户确认
for (AdminOauthUserOtherInfoApiVO adminOauthUserOtherInfoApiVO : adminOauthUserOtherInfoApiVOS) { for (AdminOauthUserOtherInfoApiVO adminOauthUserOtherInfoApiVO : adminOauthUserOtherInfoApiVOS) {
SubscribeMessageReqDTO dto = new WxMpMsgTemplateUtils().convertPerformanceResultConfirmationReminder(new PerformanceResultConfirmationReminderDTO() SubscribeMessageReqDTO dto = new WxMpMsgTemplateUtils().convertPerformanceResultConfirmationReminder(new PerformanceResultConfirmationReminderDTO()
@ -321,6 +349,16 @@ public class SalesPerformanceSettlementServiceImpl extends ServiceImpl<SalesPerf
} }
} }
@Override
public void autoConfirmJob() {
LocalDateTime now = LocalDateTime.now().minusMonths(1L);
salesPerformanceSettlementMapper.update(new SalesPerformanceSettlementDO().setConfirmFlag(1),
new LambdaQueryWrapper<SalesPerformanceSettlementDO>()
.eq(SalesPerformanceSettlementDO::getYear, String.valueOf(now.getYear()))
.eq(SalesPerformanceSettlementDO::getMonth, String.format("%02d", now.getMonthValue()))
.eq(SalesPerformanceSettlementDO::getConfirmFlag, 0));
}
/** /**
* 表达式 10<=n && n<=20 * 表达式 10<=n && n<=20
* *

View File

@ -34,7 +34,7 @@
and a.is_end = #{dto.isEnd} and a.is_end = #{dto.isEnd}
</if> </if>
<if test="dto.customerName != null and dto.customerName != ''"> <if test="dto.customerName != null and dto.customerName != ''">
and b.name = #{dto.customerName} and b.name like concat('%', #{dto.customerName}, '%')=
</if> </if>
<if test="dto.customerId != null"> <if test="dto.customerId != null">
and a.customer_id = #{dto.customerId} and a.customer_id = #{dto.customerId}

View File

@ -13,15 +13,24 @@
resultType="cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO"> resultType="cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO">
select select
a.*, a.*,
b.nickname b.nickname,
c.payment_target as paymentTarget,
c.sale_target as saleTarget
from crm_sales_performance_settlement as a from crm_sales_performance_settlement as a
left join system_users as b on a.user_id = b.id left join system_users as b on a.user_id = b.id
left join bpm_oa_sales_performance as c on a.sales_performance_id = c.id
<where> <where>
a.deleted = 0 a.deleted = 0
and b.deleted = 0 and b.deleted = 0
<if test="vo.userId != null"> <if test="vo.userId != null">
and a.user_id = #{vo.userId} and a.user_id = #{vo.userId}
</if> </if>
<if test="vo.userIds != null and vo.userIds.size() > 0">
and a.user_id in
<foreach collection="vo.userIds" item="userId" open="(" separator="," close=")">
#{userId}
</foreach>
</if>
<if test="vo.year != null and vo.year != ''"> <if test="vo.year != null and vo.year != ''">
and a.year = #{vo.year} and a.year = #{vo.year}
</if> </if>
@ -31,15 +40,24 @@
<if test="vo.nickname != null and vo.nickname != ''"> <if test="vo.nickname != null and vo.nickname != ''">
and b.nickname like concat('%', #{vo.nickname}, '%') and b.nickname like concat('%', #{vo.nickname}, '%')
</if> </if>
<if test="vo.scoreStatus != null">
and a.score_status = #{vo.scoreStatus}
</if>
<if test="vo.settlementStatus != null">
and a.settlement_status = #{vo.settlementStatus}
</if>
</where> </where>
</select> </select>
<select id="getSalesPerformanceSettlement" <select id="getSalesPerformanceSettlement"
resultType="cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO"> resultType="cn.iocoder.yudao.module.crm.dal.dataobject.salesperformancesettlement.SalesPerformanceSettlementDO">
select select
a.*, a.*,
b.nickname b.nickname,
c.payment_target as paymentTarget,
c.sale_target as saleTarget
from crm_sales_performance_settlement as a from crm_sales_performance_settlement as a
left join system_users as b on a.user_id = b.id left join system_users as b on a.user_id = b.id
left join bpm_oa_sales_performance as c on a.sales_performance_id = c.id
<where> <where>
a.deleted = 0 a.deleted = 0
and b.deleted = 0 and b.deleted = 0

View File

@ -22,4 +22,10 @@ public interface RoleApi {
@Parameter(name = "ids", description = "角色编号数组", example = "1,2", required = true) @Parameter(name = "ids", description = "角色编号数组", example = "1,2", required = true)
CommonResult<Boolean> validRoleList(@RequestParam("ids") Collection<Long> ids); CommonResult<Boolean> validRoleList(@RequestParam("ids") Collection<Long> ids);
}
@GetMapping(PREFIX + "/validCalculator")
@Operation(summary = "校验角色是否包含销售业绩核算员")
@Parameter(name = "userId", description = "用户id", example = "2", required = true)
CommonResult<Boolean> validCalculator(@RequestParam("userId") Long userId);
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.api.permission; package cn.iocoder.yudao.module.system.api.permission;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
import cn.iocoder.yudao.module.system.service.permission.RoleService; import cn.iocoder.yudao.module.system.service.permission.RoleService;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -16,10 +17,19 @@ public class RoleApiImpl implements RoleApi {
@Resource @Resource
private RoleService roleService; private RoleService roleService;
@Resource
private PermissionService permissionService;
private static final String ROLE = "calculator";
@Override @Override
public CommonResult<Boolean> validRoleList(Collection<Long> ids) { public CommonResult<Boolean> validRoleList(Collection<Long> ids) {
roleService.validateRoleList(ids); roleService.validateRoleList(ids);
return success(true); return success(true);
} }
@Override
public CommonResult<Boolean> validCalculator(Long userId) {
boolean flag = permissionService.hasAnyRoles(userId, ROLE);
return success(flag);
}
} }