feat(crm): 添加线索跟进任务并优化客户导入功能
- 新增线索跟进任务定时 job,自动更新三天未跟进的线索状态- 优化客户导入功能,增加重复客户检测和提示 - 添加合同编号字段到发票响应 VO- 修改合同列表获取逻辑,支持下属和自己的合同查询 -优化发票列表查询,支持关系筛选 - 新增商机状态更新接口
This commit is contained in:
parent
32309d2842
commit
92850e2d12
@ -37,7 +37,6 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
|
||||
* OA 合同审批 Controller
|
||||
*
|
||||
* @author 符溶馨
|
||||
|
||||
*/
|
||||
@Tag(name = "管理后台 - OA 合同审批")
|
||||
@RestController
|
||||
@ -68,7 +67,6 @@ public class BpmOAContractController {
|
||||
@Operation(summary = "获得合同审批")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public CommonResult<BpmOAContractRespVO> getContract(@RequestParam("id") Long id) {
|
||||
|
||||
BpmOAContractDO contract = contractService.getContract(id);
|
||||
BpmOAContractRespVO respVO = BpmOAContractConvert.INSTANCE.convert(contract);
|
||||
if (respVO != null) {
|
||||
@ -137,15 +135,12 @@ public class BpmOAContractController {
|
||||
return success(contractService.getContractPage(pageReqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/getListByDeptId")
|
||||
@Operation(summary = "获得同部门的销售合同")
|
||||
public CommonResult<List<BpmOAContractRespVO>> getListByDeptId() {
|
||||
|
||||
// 获取同部门所有用户id
|
||||
List<Long> userIds = userApi.getUserIdsByUserIdGroupByDept(getLoginUserId()).getCheckedData();
|
||||
|
||||
List<BpmOAContractDO> contracts = contractService.getListByDeptId(userIds);
|
||||
|
||||
@GetMapping("/getList")
|
||||
@Operation(summary = "获取下属和自己的合同列表")
|
||||
public CommonResult<List<BpmOAContractRespVO>> getList(@RequestParam(required = false) String relation,
|
||||
@RequestParam(required = false) Integer contractType,
|
||||
@RequestParam(required = false) String contractName) {
|
||||
List<BpmOAContractDO> contracts = contractService.getList(relation, contractType, contractName);
|
||||
return success(BeanUtils.toBean(contracts, BpmOAContractRespVO.class));
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,9 @@ public class BpmOAInvoiceRespVO extends BpmOABaseRespVO {
|
||||
@Schema(description = "合同名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractName;
|
||||
|
||||
@Schema(description = "合同编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractNo;
|
||||
|
||||
@Schema(description = "关联合同流程实例编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
|
||||
private String contractInstanceId;
|
||||
|
||||
|
@ -16,32 +16,17 @@ import java.util.Objects;
|
||||
public interface BpmOAInvoiceMapper extends BaseMapperX<BpmOAInvoiceDO> {
|
||||
|
||||
default PageResult<BpmOAInvoiceRespVO> selectPage(BpmOAInvoicePageReqVO pageReqVO,
|
||||
Long userId) {
|
||||
List<Long> userIds) {
|
||||
|
||||
MPJLambdaWrapperX<BpmOAInvoiceDO> query = new MPJLambdaWrapperX<>();
|
||||
query.selectAll(BpmOAInvoiceDO.class);
|
||||
query.selectAs(BpmOAContractDO::getContractName, BpmOAInvoiceRespVO::getContractName);
|
||||
query.selectAs(BpmOAContractDO::getCustomerName, BpmOAInvoiceRespVO::getCustomerName);
|
||||
query.selectAs(BpmOAContractDO::getContractNo, BpmOAInvoiceRespVO::getContractNo);
|
||||
query.leftJoin(BpmOAContractDO.class, "c", BpmOAContractDO::getId, BpmOAInvoiceDO::getContractId);
|
||||
query.apply(Objects.nonNull(pageReqVO.getContractName()), "c.contract_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getContractName());
|
||||
query.apply(Objects.nonNull(pageReqVO.getCustomerName()), "c.customer_name LIKE CONCAT('%', {0}, '%')", pageReqVO.getCustomerName());
|
||||
if ("my".equals(pageReqVO.getRelation())) {
|
||||
query.eq(BpmOAContractDO::getUserId, userId);
|
||||
}else if ("sub".equals(pageReqVO.getRelation())){
|
||||
query.innerJoin("(" +
|
||||
"\tSELECT DISTINCT\n" +
|
||||
"\t\tu.id \n" +
|
||||
"\tFROM\n" +
|
||||
"\t\tsystem_users u\n" +
|
||||
"\t\tINNER JOIN system_dept d ON d.leader_user_id = "+ userId +"\n" +
|
||||
"\t\tINNER JOIN system_dept d1 ON d1.flag LIKE CONCAT( '%', d.id, '-' ) \n" +
|
||||
"\t\tOR d1.flag LIKE CONCAT( '%-', d.id, '-%' ) \n" +
|
||||
"\t\tOR d1.flag LIKE CONCAT( '-', d.id, '%' ) \n" +
|
||||
"\tWHERE\n" +
|
||||
"\t\tu.dept_id = d1.id \n" +
|
||||
"\t\tAND u.STATUS = 0 \n" +
|
||||
"\t) subordinate ON subordinate.id = t.user_id");
|
||||
}
|
||||
query.in(BpmOAInvoiceDO::getUserId, userIds);
|
||||
query.orderByDesc(BpmOAInvoiceDO::getCreateTime);
|
||||
|
||||
return selectJoinPage(pageReqVO, BpmOAInvoiceRespVO.class, query);
|
||||
|
@ -127,4 +127,11 @@ public interface BpmOAContractService {
|
||||
* @param contractIds
|
||||
*/
|
||||
void updateSettlementFlagByIds(List<Long> contractIds);
|
||||
|
||||
/**
|
||||
* 获取下属和自己的合同列表
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<BpmOAContractDO> getList(String relation, Integer contractType, String contractName);
|
||||
}
|
||||
|
@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.oa;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
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.UploadUserFile;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
@ -18,6 +16,7 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAContractMapper;
|
||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.ContractApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcontract.dto.CrmContractProductDTO;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmcustomer.CrmCustomerApi;
|
||||
@ -25,8 +24,6 @@ import cn.iocoder.yudao.module.hrm.api.crmcustomer.dto.CrmCustomerDTO;
|
||||
import cn.iocoder.yudao.module.hrm.api.userlivetree.UserLiveTreeApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
|
||||
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.vo.StoreProductAttrValueApiVO;
|
||||
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
|
||||
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
@ -107,7 +104,8 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
|
||||
@Resource
|
||||
private CrmCustomerApi customerApi;
|
||||
|
||||
@Resource
|
||||
private BusinessApi businessApi;
|
||||
@Resource
|
||||
private UserLiveTreeApi userLiveTreeApi;
|
||||
|
||||
@ -206,13 +204,15 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
ProcessInstance instance = processInstanceService.getProcessInstance(processInstanceId);
|
||||
|
||||
if (instance.isEnded()) {
|
||||
|
||||
// 审批通过后,更新客户成交信息
|
||||
customerApi.updateCustomerPurchaseTotal(new CrmCustomerDTO()
|
||||
.setId(contract.getCustomerId())
|
||||
.setDealStatus(ShopCommonEnum.IS_STATUS_1.getValue())
|
||||
.setDealTime(LocalDateTime.now())
|
||||
.setPurchaseTotal(contract.getContractMoney()));
|
||||
|
||||
// 审批通过后,更新商机状态
|
||||
businessApi.updateIsEnd(contract.getBusinessId(), ShopCommonEnum.IS_STATUS_1.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@ -354,6 +354,27 @@ public class BpmOAContractServiceImpl extends BpmOABaseService implements BpmOAC
|
||||
.in(BpmOAContractDO::getId, contractIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BpmOAContractDO> getList(String relation, Integer contractType, String contractName) {
|
||||
List<Long> userIds = new ArrayList<>();
|
||||
Long id = getLoginUserId();
|
||||
if ("my".equals(relation)) {
|
||||
userIds.add(id);
|
||||
} else if ("sub".equals(relation)) {
|
||||
// 查询当前用户 所有下级用户编号
|
||||
userIds.addAll(userLiveTreeApi.getItemIdsByUserId(id).getCheckedData());
|
||||
}
|
||||
userIds.add(id);
|
||||
if (CollUtil.isNotEmpty(userIds)) {
|
||||
return contractMapper.selectList(new LambdaQueryWrapperX<BpmOAContractDO>()
|
||||
.in(BpmOAContractDO::getUserId, userIds)
|
||||
.eqIfPresent(BpmOAContractDO::getContractType, contractType)
|
||||
.likeIfPresent(BpmOAContractDO::getContractName, contractName)
|
||||
.eq(BpmOAContractDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()));
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public static BigDecimal calculatePercentageChange(Object today, Object yesterday) {
|
||||
|
||||
// 转换为 BigDecimal 进行高精度计算
|
||||
|
@ -14,6 +14,7 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAInvoiceDO;
|
||||
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAInvoiceMapper;
|
||||
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
|
||||
import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService;
|
||||
import cn.iocoder.yudao.module.hrm.api.userlivetree.UserLiveTreeApi;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -22,6 +23,7 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -36,11 +38,10 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
|
||||
* OA 开票申请 Service 实现类
|
||||
*
|
||||
* @author 符溶馨
|
||||
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAInvoiceService{
|
||||
public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAInvoiceService {
|
||||
|
||||
/**
|
||||
* OA 开票申请对应的流程定义 KEY
|
||||
@ -61,6 +62,8 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
|
||||
@Resource
|
||||
private RedissonClient redissonClient;
|
||||
@Resource
|
||||
private UserLiveTreeApi userLiveTreeApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -74,7 +77,7 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
.setUserId(userId)
|
||||
.setStatus(0)
|
||||
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
|
||||
invoiceMapper.insert(invoice) ;
|
||||
invoiceMapper.insert(invoice);
|
||||
|
||||
// 发起 BPM 流程
|
||||
Map<String, Object> processInstanceVariables = new HashMap<>();
|
||||
@ -90,10 +93,10 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId());
|
||||
}
|
||||
|
||||
List<UploadUserFile> fileItems = createReqVO.getFileItems() ;
|
||||
List<UploadUserFile> fileItems = createReqVO.getFileItems();
|
||||
//这里的逻辑,如果fileItems不为空,且有数据,那么说明是上传了附件的,则需要更工作流文件表对应的实例Id
|
||||
if (fileItems != null && !fileItems.isEmpty()) {
|
||||
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
|
||||
uploadBpmFileProcessInstanceId(processInstanceId, fileItems);
|
||||
}
|
||||
|
||||
return invoice.getId();
|
||||
@ -184,8 +187,14 @@ public class BpmOAInvoiceServiceImpl extends BpmOABaseService implements BpmOAIn
|
||||
|
||||
@Override
|
||||
public PageResult<BpmOAInvoiceRespVO> getInvoicePage(BpmOAInvoicePageReqVO pageReqVO) {
|
||||
|
||||
return invoiceMapper.selectPage(pageReqVO, getLoginUserId());
|
||||
Long loginUserId = getLoginUserId();
|
||||
List<Long> userIds = new ArrayList<>();
|
||||
if ("my".equals(pageReqVO.getRelation())) {
|
||||
userIds.add(loginUserId);
|
||||
} else {
|
||||
userIds = userLiveTreeApi.getItemIdsByUserId(loginUserId).getCheckedData();
|
||||
}
|
||||
return invoiceMapper.selectPage(pageReqVO, userIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,4 +28,9 @@ public interface BusinessApi {
|
||||
@Operation(summary = "获得商机所绑定产品信息")
|
||||
@Parameter(name = "businessId", description = "商机编号", required = true)
|
||||
CommonResult<List<CrmBusinessProductDTO>> getBusinessProduct(@RequestParam("businessId") Long businessId);
|
||||
|
||||
@GetMapping(PREFIX + "/updateIsEnd")
|
||||
@Operation(summary = "更新商机状态")
|
||||
@Parameter(name = "id", description = "ID", required = true)
|
||||
CommonResult<Boolean> updateIsEnd(@RequestParam("id") Long id, @RequestParam("isEnd") Integer isEnd);
|
||||
}
|
||||
|
@ -16,5 +16,6 @@ public interface ErrorCodeConstants {
|
||||
ErrorCode ACHIEVEMENT_NOT_EXISTS = new ErrorCode(200009, "业绩目标不存在");
|
||||
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, "系统已存在该客户,不可重复录入");
|
||||
ErrorCode THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_DO_YOU_WANT_TO_CONTINUE_ADDING = new ErrorCode(200012, "系统已存在该客户,是否继续添加");
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
@ -38,4 +37,10 @@ public class BusinessApiImpl implements BusinessApi {
|
||||
List<CrmBusinessProductDO> businessProductList = businessService.getBusinessProductListByBusinessId(businessId);
|
||||
return success(BeanUtils.toBean(businessProductList, CrmBusinessProductDTO.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> updateIsEnd(Long id, Integer isEnd) {
|
||||
businessService.updateIsEnd(id, isEnd);
|
||||
return success(true);
|
||||
}
|
||||
}
|
||||
|
@ -12,15 +12,13 @@ import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -105,12 +103,12 @@ public class CrmCustomerController {
|
||||
@Operation(summary = "导出客户 Excel")
|
||||
// @PreAuthorize("@ss.hasPermission('crm:customer:export')")
|
||||
public void exportCustomerExcel(@Valid CrmCustomerPageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
HttpServletResponse response) throws IOException {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<CrmCustomerDO> list = customerService.getCustomerPage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "客户.xls", "数据", CrmCustomerRespVO.class,
|
||||
BeanUtils.toBean(list, CrmCustomerRespVO.class));
|
||||
BeanUtils.toBean(list, CrmCustomerRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-import-template")
|
||||
@ -136,11 +134,11 @@ public class CrmCustomerController {
|
||||
@Parameter(name = "averageType", description = "分配方式")
|
||||
})
|
||||
public CommonResult<CustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("deptId") String deptId,
|
||||
@RequestParam("adminIds") String adminIds,
|
||||
@RequestParam("averageType") Integer averageType) throws Exception {
|
||||
@RequestParam("averageType") Integer averageType,
|
||||
@RequestParam(value = "repeatConfirmationFlag", defaultValue = "0") Integer repeatConfirmationFlag) throws Exception {
|
||||
List<CrmCustomerImportVO> list = ExcelUtils.read(file, CrmCustomerImportVO.class);
|
||||
return success(customerService.importList(list, deptId,adminIds,averageType));
|
||||
return success(customerService.importList(list, adminIds, averageType, repeatConfirmationFlag));
|
||||
}
|
||||
|
||||
@PostMapping("/recover")
|
||||
@ -172,6 +170,4 @@ public class CrmCustomerController {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class CrmCustomerPageReqVO extends PageParam {
|
||||
@Schema(description = "是否去重 0否 1是 默认否", example = "0")
|
||||
private Integer distinctFlag = 0;
|
||||
|
||||
@Schema(description = "客户名称", example = "李四")
|
||||
private String name;
|
||||
|
@ -133,4 +133,6 @@ public class CrmCustomerRespVO {
|
||||
@Schema(description = "负责人")
|
||||
private String createName;
|
||||
|
||||
@Schema(description = "相同客户自增排序")
|
||||
private Integer sortNum;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@ -108,6 +108,7 @@ public class CrmCustomerSaveReqVO {
|
||||
@Schema(description = "跟进状态", example = "1")
|
||||
private Integer followStatus;
|
||||
|
||||
|
||||
@Schema(description = "重复客户依旧添加 0否 1是 默认否", example = "1")
|
||||
private Integer repeatConfirmationFlag;
|
||||
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ public class CrmCluesDO extends BaseDO {
|
||||
*/
|
||||
private Integer industry;
|
||||
/**
|
||||
* 客户标签
|
||||
* 客户标签
|
||||
*/
|
||||
private String tags;
|
||||
/**
|
||||
@ -107,11 +107,11 @@ public class CrmCluesDO extends BaseDO {
|
||||
private LocalDateTime collectTime;
|
||||
/**
|
||||
* 跟进状态1|新客
|
||||
2|待再次沟通
|
||||
3|有意向
|
||||
4|已加微信
|
||||
5|转商机
|
||||
0|无效
|
||||
* 2|待再次沟通
|
||||
* 3|有意向
|
||||
* 4|已加微信
|
||||
* 5|转商机
|
||||
* 0|无效
|
||||
*/
|
||||
private Integer followStatus;
|
||||
|
||||
|
@ -78,7 +78,10 @@ public class CrmCustomerDO extends BaseDO {
|
||||
* 负责人ID
|
||||
*/
|
||||
private Long ownerUserId;
|
||||
|
||||
/**
|
||||
* 相同客户自增排序
|
||||
*/
|
||||
private Integer sortNum;
|
||||
/**
|
||||
* 省份id
|
||||
*/
|
||||
|
@ -27,7 +27,7 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
||||
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<CrmCustomerDO>()
|
||||
//.eq(CustomerTypesEnum.OPEN.getValue().equals(reqVO.getType()),)
|
||||
.inIfPresent(CrmCustomerDO::getOwnerUserId,ids)
|
||||
.inIfPresent(CrmCustomerDO::getOwnerUserId, ids)
|
||||
.likeIfPresent(CrmCustomerDO::getName, reqVO.getName())
|
||||
.eqIfPresent(CrmCustomerDO::getMobile, reqVO.getMobile())
|
||||
.eqIfPresent(CrmCustomerDO::getTelephone, reqVO.getTelephone())
|
||||
@ -41,7 +41,17 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
||||
.orderByDesc(CrmCustomerDO::getId));
|
||||
}
|
||||
|
||||
IPage<CrmCustomerRespVO> selectPageList(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
|
||||
IPage<CrmCustomerRespVO> selectPageList2(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
|
||||
|
||||
List<CustomerStatisticRespVO> selectStatistic(@Param("userIds") List<Long> userIds, @Param("createTime") LocalDateTime[] createTime);
|
||||
|
||||
IPage<CrmCustomerDO> selectPageList(@Param("page") IPage page, @Param("dto") CrmCustomerPageReqVO pageReqVO, @Param("ids") List<Long> ids);
|
||||
|
||||
/**
|
||||
* 获取重复客户的所有负责人名称
|
||||
*
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
List<String> getRepeatOwnerUserName(@Param("name") String name);
|
||||
}
|
||||
|
@ -10,8 +10,11 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontract.CrmContractDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcontractreceivables.CrmContractReceivablesDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO;
|
||||
import cn.iocoder.yudao.module.crm.dal.dataobject.crminvoice.CrmInvoiceDO;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -26,6 +29,7 @@ public interface CrmInvoiceMapper extends BaseMapperX<CrmInvoiceDO> {
|
||||
|
||||
default PageResult<CrmInvoiceRespVO> selectPage2(CrmInvoicePageReqVO reqVO, List<Long> ids) {
|
||||
Long loginAdminId = SecurityFrameworkUtils.getLoginUserId();
|
||||
|
||||
return selectJoinPage(reqVO, CrmInvoiceRespVO.class, new MPJLambdaWrapper<CrmInvoiceDO>()
|
||||
.selectAll(CrmInvoiceDO.class)
|
||||
.selectAs(CrmCustomerDO::getName,CrmInvoiceRespVO::getCustomerName)
|
||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.crm.framework.rpc.config;
|
||||
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.BpmOASalesPerformanceApi;
|
||||
import cn.iocoder.yudao.module.hrm.api.crmbusiness.BusinessApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproduct.StoreProductApi;
|
||||
import cn.iocoder.yudao.module.product.api.storeproductattrvalue.StoreProductAttrValueApi;
|
||||
import cn.iocoder.yudao.module.system.api.auth.AdminOauthUserOtherInfoApi;
|
||||
@ -19,6 +20,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@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, RoleApi.class})
|
||||
BpmOAContractApi.class, BpmOAReceiptApi.class, BpmOASalesPerformanceApi.class, AdminOauthUserOtherInfoApi.class, SubscribeMessageSendApi.class, RoleApi.class, BusinessApi.class})
|
||||
public class RpcConfiguration {
|
||||
}
|
||||
|
@ -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.crmclues.CrmCluesService;
|
||||
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 FollowUpCluesJob {
|
||||
|
||||
// TODO: 2024/11/04 - 每天晚上2点 执行一次 判断三天内是否有跟进
|
||||
@Resource
|
||||
private CrmCluesService cluesService;
|
||||
|
||||
@XxlJob("followUpClues")
|
||||
@TenantJob // --- ⚠️ 这个注解 会将租户列表拉出来 完了后逐个租户执行 定时任务需要注意
|
||||
public ReturnT<String> execute() {
|
||||
log.info("开始 线索跟进任务");
|
||||
cluesService.autoConfirmJob();
|
||||
log.info("结束 线索跟进任务");
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
}
|
@ -137,7 +137,7 @@ public class CustomerServiceImpl implements CustomerService {
|
||||
|
||||
pageResult1.getList().forEach(v -> {
|
||||
|
||||
String per = "0";
|
||||
String per = "0.00";
|
||||
if (customerMap.get(v.getId()) == null) {
|
||||
v.setCustomerCount(0L);
|
||||
v.setSuccessCount(0L);
|
||||
|
@ -72,4 +72,12 @@ public interface CrmBusinessService {
|
||||
* @param transferVO
|
||||
*/
|
||||
void transfer(@Valid CrmBusinessTransferVO transferVO);
|
||||
|
||||
/**
|
||||
* 更新商机状态
|
||||
*
|
||||
* @param id
|
||||
* @param isEnd
|
||||
*/
|
||||
void updateIsEnd(Long id, Integer isEnd);
|
||||
}
|
||||
|
@ -205,6 +205,14 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIsEnd(Long id, Integer isEnd) {
|
||||
CrmBusinessDO businessDO = new CrmBusinessDO();
|
||||
businessDO.setId(id);
|
||||
businessDO.setIsEnd(isEnd);
|
||||
businessMapper.updateById(businessDO);
|
||||
}
|
||||
|
||||
private void createBusinessProductList(Long businessId, List<CrmBusinessProductDO> list) {
|
||||
list.forEach(o -> o.setBusinessId(businessId));
|
||||
businessProductMapper.insertBatch(list);
|
||||
|
@ -57,27 +57,31 @@ public interface CrmCluesService {
|
||||
|
||||
/**
|
||||
* 放入线索池
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void openClues(Long id);
|
||||
|
||||
/**
|
||||
* 领取线索
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void receiveClues(Long id);
|
||||
|
||||
/**
|
||||
* 线索转换成客户
|
||||
*
|
||||
* @param createReqVO
|
||||
*/
|
||||
void createCustomer(CrmCustomerSaveReqVO createReqVO);
|
||||
|
||||
/**
|
||||
* 线索导入
|
||||
*
|
||||
* @param importUsers 导入文件
|
||||
* @param deptId 部门ID
|
||||
* @param adminIds 用户ID
|
||||
* @param deptId 部门ID
|
||||
* @param adminIds 用户ID
|
||||
* @param averageType 导入类型
|
||||
* @return
|
||||
*/
|
||||
@ -85,14 +89,21 @@ public interface CrmCluesService {
|
||||
|
||||
/**
|
||||
* 转移线索
|
||||
*
|
||||
* @param transferVO
|
||||
*/
|
||||
void transfer(CrmCluesTransferVO transferVO);
|
||||
|
||||
/**
|
||||
* 获取指定用户的线索统计信息
|
||||
*
|
||||
* @param ownerUserIds 用户ID
|
||||
* @return 线索统计信息列表
|
||||
*/
|
||||
List<CrmCluesStatisticsRespVO> getCluesStatisticsByUserIds(List<Long> ownerUserIds, LocalDateTime[] createTime);
|
||||
|
||||
/**
|
||||
* 线索跟进任务
|
||||
*/
|
||||
void autoConfirmJob();
|
||||
}
|
||||
|
@ -33,15 +33,11 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY;
|
||||
|
||||
/**
|
||||
* 线索 Service 实现类
|
||||
@ -120,7 +116,7 @@ public class CrmCluesServiceImpl implements CrmCluesService {
|
||||
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
|
||||
ids = userLiveTreeService.getItemIdsByUserId(adminId);
|
||||
}
|
||||
if (CollUtil.isEmpty(ids)){
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
|
||||
@ -158,15 +154,14 @@ public class CrmCluesServiceImpl implements CrmCluesService {
|
||||
if (crmCluesDO == null) {
|
||||
throw exception(CLUES_NOT_EXISTS);
|
||||
}
|
||||
if(CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())){
|
||||
throw exception(new ErrorCode(202411160,"已经转化成客户!"));
|
||||
if (CluesStatusEnum.STATUS_1.getValue().equals(crmCluesDO.getStatus())) {
|
||||
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);
|
||||
}
|
||||
List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(createReqVO.getName());
|
||||
if (CollUtil.isNotEmpty(repeatOwnerUserNameList) && createReqVO.getRepeatConfirmationFlag() == 0) {
|
||||
List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
|
||||
throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?")); }
|
||||
createReqVO.setId(null);
|
||||
CrmCustomerDO customerDO = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
|
||||
customerDO.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||
@ -286,4 +281,19 @@ public class CrmCluesServiceImpl implements CrmCluesService {
|
||||
return cluesMapper.selectStatisticsByUserIds(ownerUserIds, createTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autoConfirmJob() {
|
||||
// 获取负责人不为0 并且跟进记录为3天以外的数据
|
||||
List<CrmCluesDO> crmCluesDOS = cluesMapper.selectList(new LambdaQueryWrapper<CrmCluesDO>()
|
||||
.ne(CrmCluesDO::getOwnerUserId, 0)
|
||||
.in(CrmCluesDO::getStatus, Arrays.asList(CluesStatusEnum.STATUS_0.getValue(), CluesStatusEnum.STATUS_NEG_1.getValue()))
|
||||
.le(CrmCluesDO::getFollowTime, LocalDateTime.now().minusDays(3)));
|
||||
for (CrmCluesDO crmCluesDO : crmCluesDOS) {
|
||||
crmCluesDO.setOwnerUserId(0L);
|
||||
}
|
||||
if (CollUtil.isNotEmpty(crmCluesDOS)) {
|
||||
cluesMapper.updateBatch(crmCluesDOS);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -82,12 +82,11 @@ public interface CrmCustomerService {
|
||||
/**
|
||||
* 客户导入
|
||||
* @param importUsers 导入文件
|
||||
* @param deptId 部门ID
|
||||
* @param adminIds 用户ID
|
||||
* @param averageType 导入类型
|
||||
* @return
|
||||
*/
|
||||
CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String deptId, String adminIds, Integer averageType);
|
||||
CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String adminIds, Integer averageType,Integer repeatConfirmationFlag);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,8 +32,6 @@ import cn.iocoder.yudao.module.system.api.mail.dto.MailSendSingleReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.SmsSendApi;
|
||||
import cn.iocoder.yudao.module.system.api.sms.dto.send.SmsSendSingleReqDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiDTO;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserApiVO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -42,15 +40,11 @@ import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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.THIS_CUSTOMER_ALREADY_EXISTS_IN_THE_SYSTEM_AND_CANNOT_BE_ENTERED_REPEATEDLY;
|
||||
|
||||
/**
|
||||
* 客户 Service 实现类
|
||||
@ -88,17 +82,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
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);
|
||||
List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(createReqVO.getName());
|
||||
if (CollUtil.isNotEmpty(repeatOwnerUserNameList) && createReqVO.getRepeatConfirmationFlag() == 0) {
|
||||
List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
|
||||
throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?"));
|
||||
}
|
||||
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class);
|
||||
customer.setCollectTime(LocalDateTime.now());
|
||||
customer.setFollowTime(LocalDateTime.now());
|
||||
// 由于这里是 size 而排序是从0开始的 所以这里递增一个直接用size即可
|
||||
customer.setSortNum(repeatOwnerUserNameList.size());
|
||||
customer.setOwnerUserId(SecurityFrameworkUtils.getLoginUserId());
|
||||
customerMapper.insert(customer);
|
||||
|
||||
@ -126,8 +121,17 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
public void updateCustomer(CrmCustomerSaveReqVO updateReqVO) {
|
||||
// 校验存在
|
||||
CrmCustomerDO customerDO = validateCustomerExists(updateReqVO.getId());
|
||||
List<String> repeatOwnerUserNameList = customerMapper.getRepeatOwnerUserName(updateReqVO.getName());
|
||||
if (!customerDO.getName().equals(updateReqVO.getName())
|
||||
&& CollUtil.isNotEmpty(repeatOwnerUserNameList)
|
||||
&& updateReqVO.getRepeatConfirmationFlag() == 0) {
|
||||
List<String> items = repeatOwnerUserNameList.stream().distinct().collect(Collectors.toList());
|
||||
throw exception(new ErrorCode(200012, "该客户已被:" + String.join(",", items) + "添加过,是否继续添加?")); }
|
||||
|
||||
// 更新
|
||||
CrmCustomerDO updateObj = BeanUtils.toBean(updateReqVO, CrmCustomerDO.class);
|
||||
// 由于这里是 size 而排序是从0开始的 所以这里递增一个直接用size即可
|
||||
updateObj.setSortNum(repeatOwnerUserNameList.size());
|
||||
customerMapper.updateById(updateObj);
|
||||
|
||||
//插入日志
|
||||
@ -255,7 +259,14 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
if (CollUtil.isEmpty(ids)) {
|
||||
return PageResult.empty();
|
||||
}
|
||||
return customerMapper.selectPage(pageReqVO, ids);
|
||||
IPage<CrmCustomerDO> pageResult;
|
||||
if (pageReqVO.getDistinctFlag() == 0) {
|
||||
return customerMapper.selectPage(pageReqVO, ids);
|
||||
} else {
|
||||
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
|
||||
pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids);
|
||||
}
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
}
|
||||
|
||||
|
||||
@ -276,42 +287,46 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
return PageResult.empty();
|
||||
}
|
||||
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
|
||||
IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList(mpPage, pageReqVO, ids);
|
||||
IPage<CrmCustomerRespVO> pageResult = customerMapper.selectPageList2(mpPage, pageReqVO, ids);
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String deptId, String adminIds,
|
||||
Integer averageType) {
|
||||
public CustomerImportRespVO importList(List<CrmCustomerImportVO> importUsers, String adminIds,
|
||||
Integer averageType, Integer repeatConfirmationFlag) {
|
||||
CustomerImportRespVO respVO = CustomerImportRespVO.builder().createNames(new ArrayList<>())
|
||||
.failureNames(new LinkedHashMap<>()).build();
|
||||
//处理客户归属方案
|
||||
//如果只选择了机构没有选择用户直接获取当前部门下的用户
|
||||
List<Long> userList = new ArrayList<>();
|
||||
if (StrUtil.isNotEmpty(deptId) && StrUtil.isEmpty(adminIds)) {
|
||||
List<AdminUserApiVO> adminUserDOS = adminUserApi.getUserList(new AdminUserApiDTO().setDeptId(Long.valueOf(deptId)).setNextDept(1)).getCheckedData();
|
||||
userList = adminUserDOS.stream().map(AdminUserApiVO::getId).collect(Collectors.toList());
|
||||
if (userList.isEmpty()) {
|
||||
throw exception(new ErrorCode(202409080, "当前部门下没有用户,清重新选择"));
|
||||
}
|
||||
} else {
|
||||
if (StrUtil.isNotEmpty(adminIds)) {
|
||||
userList = StrUtil.split(adminIds, ",").stream().map(Long::parseLong).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
int i = 1;
|
||||
int j = 0;
|
||||
int adminCount = userList.size();
|
||||
List<CrmCustomerDO> customerList = new ArrayList<>();
|
||||
// -- 查询重复
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
if (repeatConfirmationFlag == 0) {
|
||||
List<String> nameList = importUsers.stream().map(CrmCustomerImportVO::getName).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
|
||||
if (CollUtil.isNotEmpty(nameList)) {
|
||||
List<CrmCustomerDO> crmCustomerDOS = customerMapper.selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
||||
.in(CrmCustomerDO::getName, nameList));
|
||||
map = crmCustomerDOS.stream().collect(Collectors.groupingBy(CrmCustomerDO::getName, Collectors.summingInt(e -> 1)));
|
||||
}
|
||||
}
|
||||
for (CrmCustomerImportVO importVO : importUsers) {
|
||||
if (StrUtil.isEmpty(importVO.getName())) {
|
||||
respVO.getFailureNames().put("第" + i + "行:", "客户名称为空,已经被过滤掉");
|
||||
continue;
|
||||
}
|
||||
Long count = customerMapper.selectCount(new LambdaQueryWrapper<CrmCustomerDO>()
|
||||
.eq(CrmCustomerDO::getName, importVO.getName()));
|
||||
if (count > 0) {
|
||||
respVO.getFailureNames().put("第" + i + "行:", "客户名称已经存在,已经被过滤掉");
|
||||
continue;
|
||||
if (repeatConfirmationFlag == 0) {
|
||||
Integer num = map.get(importVO.getName());
|
||||
if (num != null && num > 1) {
|
||||
respVO.getFailureNames().put("第" + i + "行:", "客户名称重复,已经被过滤掉");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CrmCustomerDO customer = BeanUtils.toBean(importVO, CrmCustomerDO.class);
|
||||
Long adminId = 0L;
|
||||
@ -329,11 +344,22 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||
int num = random.nextInt(adminCount);
|
||||
adminId = userList.get(num);
|
||||
}
|
||||
Integer num = map.get(importVO.getName());
|
||||
if (num != null && num > 1) {
|
||||
map.put(importVO.getName(), num + 1);
|
||||
} else if (num == null) {
|
||||
num = 0;
|
||||
map.put(importVO.getName(), num);
|
||||
}
|
||||
customer.setSortNum(num);
|
||||
customer.setOwnerUserId(adminId);
|
||||
customerMapper.insert(customer);
|
||||
customerList.add(customer);
|
||||
respVO.getCreateNames().add("第" + i + "行:导入成功用户名->" + importVO.getName());
|
||||
i++;
|
||||
}
|
||||
if (!customerList.isEmpty()) {
|
||||
customerMapper.insertBatch(customerList);
|
||||
}
|
||||
return respVO;
|
||||
}
|
||||
|
||||
|
@ -92,9 +92,6 @@ public class CrmCustomerContactsServiceImpl implements CrmCustomerContactsServic
|
||||
} else if (RelationEnum.SUB.getValue().equals(pageReqVO.getRelation())) {
|
||||
ids = userLiveTreeService.getItemIdsByUserId(adminId);
|
||||
}
|
||||
if (CollUtil.isEmpty(ids)){
|
||||
return PageResult.empty();
|
||||
}
|
||||
IPage mpPage = MyBatisUtils.buildPage(pageReqVO);
|
||||
IPage<CrmCustomerContactsRespVO> pageResult = customerContactsMapper.selectPageList(mpPage, pageReqVO, ids);
|
||||
return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
|
||||
|
@ -6,6 +6,7 @@ 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.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crmcontract.vo.CheckInfoVO;
|
||||
import cn.iocoder.yudao.module.crm.controller.admin.crminvoice.vo.CrmInvoicePageReqVO;
|
||||
@ -28,6 +29,7 @@ import cn.iocoder.yudao.module.hrm.enums.*;
|
||||
import cn.iocoder.yudao.module.system.api.mail.MailSendApi;
|
||||
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
|
@ -18,6 +18,7 @@
|
||||
left join system_users b ON b.id = a.owner_user_id
|
||||
<where>
|
||||
a.deleted = 0
|
||||
and a.status != 1
|
||||
<if test="dto.name != null and dto.name != ''">
|
||||
and a.name like concat('%', #{dto.name}, '%')
|
||||
</if>
|
||||
|
@ -9,7 +9,7 @@
|
||||
文档可见:https://www.yixiang.co/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
<select id="selectPageList"
|
||||
<select id="selectPageList2"
|
||||
resultType="cn.iocoder.yudao.module.crm.controller.admin.crmcustomer.vo.CrmCustomerRespVO">
|
||||
select
|
||||
a.*,
|
||||
@ -74,4 +74,65 @@
|
||||
</if>
|
||||
GROUP BY owner_user_id
|
||||
</select>
|
||||
<select id="selectPageList"
|
||||
resultType="cn.iocoder.yudao.module.crm.dal.dataobject.crmcustomer.CrmCustomerDO">
|
||||
SELECT * from (
|
||||
select
|
||||
a.*,
|
||||
ROW_NUMBER() OVER (PARTITION BY name ORDER BY sort_num DESC, id DESC) AS rn
|
||||
from crm_customer as a
|
||||
<where>
|
||||
a.deleted = 0
|
||||
<if test="ids != null and ids.size() > 0">
|
||||
and a.owner_user_id in
|
||||
<foreach item="ownerUserId" collection="ids" separator="," open="(" close=")" index="">
|
||||
#{ownerUserId}
|
||||
</foreach>
|
||||
</if>
|
||||
<if test="dto.name != null and dto.name != ''">
|
||||
and a.name like concat('%', #{dto.name}, '%')
|
||||
</if>
|
||||
<if test="dto.mobile != null and dto.mobile != ''">
|
||||
and a.mobile = #{dto.mobile}
|
||||
</if>
|
||||
<if test="dto.telephone != null and dto.telephone != ''">
|
||||
and a.telephone = #{dto.telephone}
|
||||
</if>
|
||||
<if test="dto.dealStatus != null">
|
||||
and a.deal_status = #{dto.dealStatus}
|
||||
</if>
|
||||
<if test="dto.level != null">
|
||||
and a.level = #{dto.level}
|
||||
</if>
|
||||
<if test="dto.industry != null">
|
||||
and a.industry = #{dto.industry}
|
||||
</if>
|
||||
<if test="dto.source != null">
|
||||
and a.source = #{dto.source}
|
||||
</if>
|
||||
<if test="dto.weixin != null and dto.weixin != ''">
|
||||
and a.weixin = #{dto.weixin}
|
||||
</if>
|
||||
<if test="dto.qq != null and dto.qq != ''">
|
||||
and a.qq = #{dto.qq}
|
||||
</if>
|
||||
<if test="dto.qq != null and dto.qq != ''">
|
||||
and a.qq = #{dto.qq}
|
||||
</if>
|
||||
<if test="dto.followStatus != null">
|
||||
and a.follow_status = #{dto.followStatus}
|
||||
</if>
|
||||
</where>
|
||||
order by a.id desc
|
||||
) AS ranked
|
||||
where rn = 1;
|
||||
</select>
|
||||
<select id="getRepeatOwnerUserName" resultType="java.lang.String">
|
||||
select t1.nickname
|
||||
from crm_customer as a
|
||||
left join system_users as t1 on a.owner_user_id = t1.id
|
||||
where a.deleted = 0
|
||||
and t1.deleted = 0
|
||||
and a.name = #{name}
|
||||
</select>
|
||||
</mapper>
|
||||
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cn.iocoder.yudao.module.crm.dal.mysql.crminvoice.CrmInvoiceMapper">
|
||||
|
||||
<!--
|
||||
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
|
||||
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
|
||||
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
|
||||
文档可见:https://www.yixiang.co/MyBatis/x-plugins/
|
||||
-->
|
||||
|
||||
</mapper>
|
@ -667,9 +667,9 @@ public class StoreProductServiceImpl extends ServiceImpl<StoreProductMapper, Sto
|
||||
.reduce(Integer::sum)
|
||||
.orElse(0);
|
||||
|
||||
if (stock <= 0) {
|
||||
throw exception(STORE_PRODUCT_STOCK_ERROR);
|
||||
}
|
||||
// if (stock <= 0) {
|
||||
// throw exception(STORE_PRODUCT_STOCK_ERROR);
|
||||
// }
|
||||
|
||||
return ProductResultDto.builder()
|
||||
.minPrice(minPrice)
|
||||
|
Loading…
Reference in New Issue
Block a user