mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-02-07 21:10:05 +08:00
commit
acb8d3f23b
@ -6,16 +6,15 @@ import cn.iocoder.yudao.framework.common.util.io.IoUtils;
|
|||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
|
||||||
import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
|
import cn.iocoder.yudao.module.bpm.convert.definition.BpmModelConvert;
|
||||||
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
|
import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
@ -44,6 +43,15 @@ public class BpmModelController {
|
|||||||
return success(model);
|
return success(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-by-key")
|
||||||
|
@Operation(summary = "获得模型")
|
||||||
|
@Parameter(name = "key", description = "流程标识", required = true, example = "oa_leave")
|
||||||
|
@PreAuthorize("@ss.hasPermission('bpm:model:query')")
|
||||||
|
public CommonResult<BpmModelRespVO> getModelByKey(@RequestParam("key") String key) {
|
||||||
|
BpmModelRespVO model = modelService.getBpmnModelByKey(key);
|
||||||
|
return success(model);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "新建模型")
|
@Operation(summary = "新建模型")
|
||||||
@PreAuthorize("@ss.hasPermission('bpm:model:create')")
|
@PreAuthorize("@ss.hasPermission('bpm:model:create')")
|
||||||
|
@ -2,9 +2,8 @@ package cn.iocoder.yudao.module.bpm.service.definition;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
|
import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.*;
|
||||||
import org.flowable.bpmn.model.BpmnModel;
|
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
import org.flowable.bpmn.model.BpmnModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flowable流程模型接口
|
* Flowable流程模型接口
|
||||||
@ -38,6 +37,14 @@ public interface BpmModelService {
|
|||||||
*/
|
*/
|
||||||
BpmModelRespVO getModel(String id);
|
BpmModelRespVO getModel(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得流程模块
|
||||||
|
*
|
||||||
|
* @param key 流程标识
|
||||||
|
* @return 流程模型
|
||||||
|
*/
|
||||||
|
BpmModelRespVO getBpmnModelByKey(String key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改流程模型
|
* 修改流程模型
|
||||||
*
|
*
|
||||||
@ -62,7 +69,7 @@ public interface BpmModelService {
|
|||||||
/**
|
/**
|
||||||
* 修改模型的状态,实际更新的部署的流程定义的状态
|
* 修改模型的状态,实际更新的部署的流程定义的状态
|
||||||
*
|
*
|
||||||
* @param id 编号
|
* @param id 编号
|
||||||
* @param state 状态
|
* @param state 状态
|
||||||
*/
|
*/
|
||||||
void updateModelState(String id, Integer state);
|
void updateModelState(String id, Integer state);
|
||||||
|
@ -14,6 +14,8 @@ import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
|
|||||||
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
|
import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum;
|
||||||
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
|
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmModelMetaInfoRespDTO;
|
||||||
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
|
import cn.iocoder.yudao.module.bpm.service.definition.dto.BpmProcessDefinitionCreateReqDTO;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||||
import org.flowable.bpmn.model.BpmnModel;
|
import org.flowable.bpmn.model.BpmnModel;
|
||||||
@ -29,8 +31,6 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
@ -134,6 +134,19 @@ public class BpmModelServiceImpl implements BpmModelService {
|
|||||||
return modelRespVO;
|
return modelRespVO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BpmModelRespVO getBpmnModelByKey(String key) {
|
||||||
|
Model model = getModelByKey(key);
|
||||||
|
if (model == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BpmModelRespVO modelRespVO = BpmModelConvert.INSTANCE.convert(model);
|
||||||
|
// 拼接 bpmn XML
|
||||||
|
byte[] bpmnBytes = repositoryService.getModelEditorSource(model.getId());
|
||||||
|
modelRespVO.setBpmnXml(StrUtil.utf8Str(bpmnBytes));
|
||||||
|
return modelRespVO;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
|
@Transactional(rollbackFor = Exception.class) // 因为进行多个操作,所以开启事务
|
||||||
public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) {
|
public void updateModel(@Valid BpmModelUpdateReqVO updateReqVO) {
|
||||||
|
@ -11,6 +11,7 @@ public interface ErrorCodeConstants {
|
|||||||
|
|
||||||
// ========== 合同管理 1-020-000-000 ==========
|
// ========== 合同管理 1-020-000-000 ==========
|
||||||
ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
|
ErrorCode CONTRACT_NOT_EXISTS = new ErrorCode(1_020_000_000, "合同不存在");
|
||||||
|
ErrorCode CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED = new ErrorCode(1_020_000_001, "更新合同失败,原因:禁止编辑");
|
||||||
|
|
||||||
// ========== 线索管理 1-020-001-000 ==========
|
// ========== 线索管理 1-020-001-000 ==========
|
||||||
ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");
|
ErrorCode CLUE_NOT_EXISTS = new ErrorCode(1_020_001_000, "线索不存在");
|
||||||
@ -48,6 +49,9 @@ public interface ErrorCodeConstants {
|
|||||||
ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
|
ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
|
||||||
ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限");
|
ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限");
|
||||||
ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}");
|
ErrorCode CUSTOMER_DELETE_FAIL_HAVE_REFERENCE = new ErrorCode(1_020_006_011, "删除客户失败,有关联{}");
|
||||||
|
ErrorCode CUSTOMER_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_006_012, "导入客户数据不能为空!");
|
||||||
|
ErrorCode CUSTOMER_CREATE_NAME_NOT_NULL = new ErrorCode(1_020_006_013, "客户名称不能为空!");
|
||||||
|
ErrorCode CUSTOMER_NAME_EXISTS = new ErrorCode(1_020_006_014, "已存在名为【{}】的客户!");
|
||||||
|
|
||||||
// ========== 权限管理 1_020_007_000 ==========
|
// ========== 权限管理 1_020_007_000 ==========
|
||||||
ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");
|
ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");
|
||||||
|
@ -27,6 +27,11 @@
|
|||||||
<artifactId>yudao-module-crm-api</artifactId>
|
<artifactId>yudao-module-crm-api</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-module-bpm-api</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 业务组件 -->
|
<!-- 业务组件 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -37,6 +42,10 @@
|
|||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
|
<artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
|
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Web 相关 -->
|
<!-- Web 相关 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -70,11 +79,5 @@
|
|||||||
<groupId>cn.iocoder.boot</groupId>
|
<groupId>cn.iocoder.boot</groupId>
|
||||||
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
<artifactId>yudao-spring-boot-starter-test</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- TODO @puhui999:放的位置,要整齐哈。 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>cn.iocoder.boot</groupId>
|
|
||||||
<artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
@ -140,4 +140,12 @@ public class CrmContractController {
|
|||||||
return success(true);
|
return success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping("/approve")
|
||||||
|
@Operation(summary = "发起合同审批流程")
|
||||||
|
@PreAuthorize("@ss.hasPermission('crm:contract:update')")
|
||||||
|
public CommonResult<Boolean> transfer(@RequestParam("id") Long id) {
|
||||||
|
contractService.handleApprove(id, getLoginUserId());
|
||||||
|
return success(true);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,13 @@ import cn.iocoder.yudao.module.crm.framework.operatelog.core.SysAdminUserParseFu
|
|||||||
import com.mzt.logapi.starter.annotation.DiffLogField;
|
import com.mzt.logapi.starter.annotation.DiffLogField;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -35,10 +38,6 @@ public class CrmContractSaveReqVO {
|
|||||||
@DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME)
|
@DiffLogField(name = "商机", function = CrmBusinessParseFunction.NAME)
|
||||||
private Long businessId;
|
private Long businessId;
|
||||||
|
|
||||||
@Schema(description = "工作流编号", example = "1043")
|
|
||||||
@DiffLogField(name = "工作流编号")
|
|
||||||
private Long processInstanceId;
|
|
||||||
|
|
||||||
@Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "下单日期", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
@DiffLogField(name = "下单日期")
|
@DiffLogField(name = "下单日期")
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||||
@ -86,16 +85,33 @@ public class CrmContractSaveReqVO {
|
|||||||
@DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME)
|
@DiffLogField(name = "公司签约人", function = SysAdminUserParseFunction.NAME)
|
||||||
private Long signUserId;
|
private Long signUserId;
|
||||||
|
|
||||||
@Schema(description = "最后跟进时间")
|
|
||||||
@DiffLogField(name = "最后跟进时间")
|
|
||||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
|
||||||
private LocalDateTime contactLastTime;
|
|
||||||
|
|
||||||
@Schema(description = "备注", example = "你猜")
|
@Schema(description = "备注", example = "你猜")
|
||||||
@DiffLogField(name = "备注")
|
@DiffLogField(name = "备注")
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
// TODO @dhb52:增加一个 status 字段:具体有哪些值,你来枚举下;主要页面上有个【草稿】【提交审核】的流程,可以看看。然后要对接工作流,这块也可以看看,不确定的地方问我。
|
@Schema(description = "审批状态", example = "1")
|
||||||
|
private Integer auditStatus;
|
||||||
|
|
||||||
|
@Schema(description = "产品列表")
|
||||||
|
private List<CrmContractProductItem> productItems;
|
||||||
|
|
||||||
|
@Schema(description = "商品属性")
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public static class CrmContractProductItem {
|
||||||
|
|
||||||
|
@Schema(description = "产品编号", example = "20529")
|
||||||
|
@NotNull(message = "产品编号不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@Schema(description = "产品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8911")
|
||||||
|
@NotNull(message = "产品数量不能为空")
|
||||||
|
private Integer count;
|
||||||
|
|
||||||
|
@Schema(description = "产品折扣")
|
||||||
|
private Integer discountPercent;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ 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 io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
@ -29,9 +30,11 @@ import org.mapstruct.ap.internal.util.Collections;
|
|||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -198,6 +201,36 @@ public class CrmCustomerController {
|
|||||||
BeanUtils.toBean(list, CrmCustomerRespVO.class));
|
BeanUtils.toBean(list, CrmCustomerRespVO.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/get-import-template")
|
||||||
|
@Operation(summary = "获得导入客户模板")
|
||||||
|
public void importTemplate(HttpServletResponse response) throws IOException {
|
||||||
|
// 手动创建导出 demo
|
||||||
|
List<CrmCustomerImportExcelVO> list = Arrays.asList(
|
||||||
|
CrmCustomerImportExcelVO.builder().name("芋道").industryId(1).level(1).source(1).mobile("15601691300").telephone("")
|
||||||
|
.website("https://doc.iocoder.cn/").qq("").wechat("").email("yunai@iocoder.cn").description("").remark("")
|
||||||
|
.areaId(null).detailAddress("").build(),
|
||||||
|
CrmCustomerImportExcelVO.builder().name("源码").industryId(1).level(1).source(1).mobile("15601691300").telephone("")
|
||||||
|
.website("https://doc.iocoder.cn/").qq("").wechat("").email("yunai@iocoder.cn").description("").remark("")
|
||||||
|
.areaId(null).detailAddress("").build()
|
||||||
|
);
|
||||||
|
// 输出
|
||||||
|
ExcelUtils.write(response, "客户导入模板.xls", "客户列表", CrmCustomerImportExcelVO.class, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/import")
|
||||||
|
@Operation(summary = "导入客户")
|
||||||
|
@Parameters({
|
||||||
|
@Parameter(name = "file", description = "Excel 文件", required = true),
|
||||||
|
@Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
|
||||||
|
})
|
||||||
|
@PreAuthorize("@ss.hasPermission('system:customer:import')")
|
||||||
|
public CommonResult<CrmCustomerImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
|
||||||
|
@RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport) throws Exception {
|
||||||
|
List<CrmCustomerImportExcelVO> list = ExcelUtils.read(file, CrmCustomerImportExcelVO.class);
|
||||||
|
return success(customerService.importCustomerList(list, updateSupport, getLoginUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@PutMapping("/transfer")
|
@PutMapping("/transfer")
|
||||||
@Operation(summary = "转移客户")
|
@Operation(summary = "转移客户")
|
||||||
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
|
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
|
||||||
|
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||||
|
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
|
||||||
|
import com.alibaba.excel.annotation.ExcelProperty;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户 Excel 导入 VO
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
|
||||||
|
public class CrmCustomerImportExcelVO {
|
||||||
|
|
||||||
|
@ExcelProperty("客户名称")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "所属行业", converter = DictConvert.class)
|
||||||
|
@DictFormat(CRM_CUSTOMER_INDUSTRY)
|
||||||
|
private Integer industryId;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "客户等级", converter = DictConvert.class)
|
||||||
|
@DictFormat(CRM_CUSTOMER_LEVEL)
|
||||||
|
private Integer level;
|
||||||
|
|
||||||
|
@ExcelProperty(value = "客户来源", converter = DictConvert.class)
|
||||||
|
@DictFormat(CRM_CUSTOMER_SOURCE)
|
||||||
|
private Integer source;
|
||||||
|
|
||||||
|
@ExcelProperty("手机")
|
||||||
|
private String mobile;
|
||||||
|
|
||||||
|
@ExcelProperty("电话")
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
@ExcelProperty("网址")
|
||||||
|
private String website;
|
||||||
|
|
||||||
|
@Size(max = 20, message = "QQ长度不能超过 20 个字符")
|
||||||
|
@ExcelProperty("QQ")
|
||||||
|
private String qq;
|
||||||
|
|
||||||
|
@Size(max = 255, message = "微信长度不能超过 255 个字符")
|
||||||
|
@ExcelProperty("微信")
|
||||||
|
private String wechat;
|
||||||
|
|
||||||
|
@Size(max = 255, message = "邮箱长度不能超过 255 个字符")
|
||||||
|
@ExcelProperty("邮箱")
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Size(max = 4096, message = "客户描述长度不能超过 4096 个字符")
|
||||||
|
@ExcelProperty("客户描述")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@ExcelProperty("备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
@ExcelProperty("地区编号")
|
||||||
|
private Integer areaId;
|
||||||
|
|
||||||
|
@ExcelProperty("详细地址")
|
||||||
|
private String detailAddress;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Schema(description = "管理后台 - 客户导入 Response VO")
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class CrmCustomerImportRespVO {
|
||||||
|
|
||||||
|
@Schema(description = "创建成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private List<String> createCustomerNames;
|
||||||
|
|
||||||
|
@Schema(description = "更新成功的客户名数组", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private List<String> updateCustomerNames;
|
||||||
|
|
||||||
|
@Schema(description = "导入失败的客户集合,key 为客户名,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private Map<String, String> failureCustomerNames;
|
||||||
|
|
||||||
|
}
|
@ -2,13 +2,12 @@ package cn.iocoder.yudao.module.crm.dal.dataobject.business;
|
|||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
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 lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商机产品关联表 DO
|
* 商机产品关联表 DO
|
||||||
*
|
*
|
||||||
@ -29,14 +28,12 @@ public class CrmBusinessProductDO extends BaseDO {
|
|||||||
*/
|
*/
|
||||||
@TableId
|
@TableId
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 商机编号
|
* 商机编号
|
||||||
*
|
*
|
||||||
* 关联 {@link CrmBusinessDO#getId()}
|
* 关联 {@link CrmBusinessDO#getId()}
|
||||||
*/
|
*/
|
||||||
private Long businessId;
|
private Long businessId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 产品编号
|
* 产品编号
|
||||||
*
|
*
|
||||||
@ -50,29 +47,27 @@ public class CrmBusinessProductDO extends BaseDO {
|
|||||||
private Integer price;
|
private Integer price;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 销售价格
|
* 销售价格, 单位:分
|
||||||
*/
|
*/
|
||||||
private BigDecimal salesPrice;
|
private Integer salesPrice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数量
|
* 数量
|
||||||
*/
|
*/
|
||||||
private BigDecimal count;
|
private Integer count;
|
||||||
|
|
||||||
// TODO @lzxhqs:改成 discountPercent
|
|
||||||
/**
|
/**
|
||||||
* 折扣
|
* 折扣
|
||||||
*/
|
*/
|
||||||
private BigDecimal discountPercent;
|
private Integer discountPercent;
|
||||||
|
|
||||||
// TODO @lzxhqs:改成 totalPrice;总计价格,和现有项目风格一致;
|
|
||||||
/**
|
/**
|
||||||
* 小计(折扣后价格)
|
* 总计价格(折扣后价格)
|
||||||
*/
|
*/
|
||||||
private BigDecimal totalPrice;
|
private Integer totalPrice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单位
|
* 单位
|
||||||
|
*
|
||||||
|
* 字典 {@link DictTypeConstants#CRM_PRODUCT_UNIT}
|
||||||
*/
|
*/
|
||||||
private String unit;
|
private Integer unit;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public class CrmContractDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 工作流编号
|
* 工作流编号
|
||||||
*/
|
*/
|
||||||
private Long processInstanceId;
|
private String processInstanceId;
|
||||||
/**
|
/**
|
||||||
* 下单日期
|
* 下单日期
|
||||||
*/
|
*/
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.crm.dal.dataobject.product;
|
package cn.iocoder.yudao.module.crm.dal.dataobject.product;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.enums.DictTypeConstants;
|
||||||
import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum;
|
import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum;
|
||||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
@ -38,7 +39,7 @@ public class CrmProductDO extends BaseDO {
|
|||||||
/**
|
/**
|
||||||
* 单位
|
* 单位
|
||||||
*
|
*
|
||||||
* 字典 {@link cn.iocoder.yudao.module.crm.enums.DictTypeConstants#CRM_PRODUCT_UNIT}
|
* 字典 {@link DictTypeConstants#CRM_PRODUCT_UNIT}
|
||||||
*/
|
*/
|
||||||
private Integer unit;
|
private Integer unit;
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +41,7 @@ public interface CrmContractMapper extends BaseMapperX<CrmContractDO> {
|
|||||||
default PageResult<CrmContractDO> selectPage(CrmContractPageReqVO pageReqVO, Long userId) {
|
default PageResult<CrmContractDO> selectPage(CrmContractPageReqVO pageReqVO, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmContractDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmContractDO> mpjLambdaWrapperX = new MPJLambdaWrapperX<>();
|
||||||
// 拼接数据权限的查询条件
|
// 拼接数据权限的查询条件
|
||||||
CrmQueryWrapperUtils.appendPermissionCondition(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CONTACT.getType(),
|
CrmQueryWrapperUtils.appendPermissionCondition(mpjLambdaWrapperX, CrmBizTypeEnum.CRM_CONTRACT.getType(),
|
||||||
CrmContractDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE);
|
CrmContractDO::getId, userId, pageReqVO.getSceneType(), Boolean.FALSE);
|
||||||
// 拼接自身的查询条件
|
// 拼接自身的查询条件
|
||||||
mpjLambdaWrapperX.selectAll(CrmContractDO.class)
|
mpjLambdaWrapperX.selectAll(CrmContractDO.class)
|
||||||
@ -56,7 +56,7 @@ public interface CrmContractMapper extends BaseMapperX<CrmContractDO> {
|
|||||||
default List<CrmContractDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
default List<CrmContractDO> selectBatchIds(Collection<Long> ids, Long userId) {
|
||||||
MPJLambdaWrapperX<CrmContractDO> query = new MPJLambdaWrapperX<>();
|
MPJLambdaWrapperX<CrmContractDO> query = new MPJLambdaWrapperX<>();
|
||||||
// 构建数据权限连表条件
|
// 构建数据权限连表条件
|
||||||
CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTACT.getType(), ids, userId);
|
CrmQueryWrapperUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_CONTRACT.getType(), ids, userId);
|
||||||
// 拼接自身的查询条件
|
// 拼接自身的查询条件
|
||||||
query.selectAll(CrmContractDO.class).in(CrmContractDO::getId, ids).orderByDesc(CrmContractDO::getId);
|
query.selectAll(CrmContractDO.class).in(CrmContractDO::getId, ids).orderByDesc(CrmContractDO::getId);
|
||||||
return selectJoinList(CrmContractDO.class, query);
|
return selectJoinList(CrmContractDO.class, query);
|
||||||
|
@ -101,11 +101,15 @@ public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
|
|||||||
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
|
return selectJoinPage(pageReqVO, CrmCustomerDO.class, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<CrmCustomerDO> selectListByLockStatusAndOwnerUserIdNotNull(Boolean lockStatus) {
|
default List<CrmCustomerDO> selectListByLockAndDealStatusAndNotPool(Boolean lockStatus, Boolean dealStatus) {
|
||||||
return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
return selectList(new LambdaQueryWrapper<CrmCustomerDO>()
|
||||||
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
.eq(CrmCustomerDO::getLockStatus, lockStatus)
|
||||||
// TODO @puhui999:not null 可以转化成大于 0
|
.eq(CrmCustomerDO::getDealStatus, dealStatus)
|
||||||
.isNotNull(CrmCustomerDO::getOwnerUserId));
|
.gt(CrmCustomerDO::getOwnerUserId, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
default CrmCustomerDO selectByCustomerName(String name) {
|
||||||
|
return selectOne(CrmCustomerDO::getName, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
default PageResult<CrmCustomerDO> selectPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
|
default PageResult<CrmCustomerDO> selectPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageReqVO,
|
||||||
|
@ -1,17 +1,9 @@
|
|||||||
package cn.iocoder.yudao.module.crm.framework.permission.core.util;
|
package cn.iocoder.yudao.module.crm.framework.permission.core.util;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjUtil;
|
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
|
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
|
||||||
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
|
||||||
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionRoleCodeEnum;
|
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionRoleCodeEnum;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
|
||||||
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.anyMatch;
|
|
||||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,22 +22,6 @@ public class CrmPermissionUtils {
|
|||||||
return SingletonManager.getPermissionApi().hasAnyRoles(getLoginUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode());
|
return SingletonManager.getPermissionApi().hasAnyRoles(getLoginUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @puhui999:这个貌似直接放到 CrmPermissionService 会更好?
|
|
||||||
/**
|
|
||||||
* 校验权限
|
|
||||||
*
|
|
||||||
* @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
|
|
||||||
* @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
|
|
||||||
* @param userId 用户编号
|
|
||||||
* @param levelEnum 权限级别
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum) {
|
|
||||||
List<CrmPermissionDO> permissionList = SingletonManager.getCrmPermissionService().getPermissionListByBiz(bizType, bizId);
|
|
||||||
return anyMatch(permissionList, permission ->
|
|
||||||
ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), levelEnum.getLevel()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 静态内部类实现单例获取
|
* 静态内部类实现单例获取
|
||||||
*
|
*
|
||||||
@ -54,16 +30,11 @@ public class CrmPermissionUtils {
|
|||||||
private static class SingletonManager {
|
private static class SingletonManager {
|
||||||
|
|
||||||
private static final PermissionApi PERMISSION_API = SpringUtil.getBean(PermissionApi.class);
|
private static final PermissionApi PERMISSION_API = SpringUtil.getBean(PermissionApi.class);
|
||||||
private static final CrmPermissionService CRM_PERMISSION_SERVICE = SpringUtil.getBean(CrmPermissionService.class);
|
|
||||||
|
|
||||||
public static PermissionApi getPermissionApi() {
|
public static PermissionApi getPermissionApi() {
|
||||||
return PERMISSION_API;
|
return PERMISSION_API;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CrmPermissionService getCrmPermissionService() {
|
|
||||||
return CRM_PERMISSION_SERVICE;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public class CrmCustomerAutoPutPoolJob implements JobHandler {
|
|||||||
@Override
|
@Override
|
||||||
@TenantJob
|
@TenantJob
|
||||||
public String execute(String param) {
|
public String execute(String param) {
|
||||||
int count = customerService.customerAutoPutPoolBySystem();
|
int count = customerService.autoPutCustomerPool();
|
||||||
return String.format("掉入公海客户 %s 个", count);
|
return String.format("掉入公海客户 %s 个", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,14 @@ public interface CrmContractService {
|
|||||||
*/
|
*/
|
||||||
void updateContractFollowUp(CrmUpdateFollowUpReqBO contractUpdateFollowUpReqBO);
|
void updateContractFollowUp(CrmUpdateFollowUpReqBO contractUpdateFollowUpReqBO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发起合同审批流程
|
||||||
|
*
|
||||||
|
* @param id 合同编号
|
||||||
|
* @param userId 用户编号
|
||||||
|
*/
|
||||||
|
void handleApprove(Long id, Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得合同
|
* 获得合同
|
||||||
*
|
*
|
||||||
@ -111,9 +119,11 @@ public interface CrmContractService {
|
|||||||
Long getContractCountByCustomerId(Long customerId);
|
Long getContractCountByCustomerId(Long customerId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据商机ID获取关联客户的合同数量 TODO @lzxhqs:1)方法注释,和参数注释之间要有空行;2)中英文之间有空格,更清晰,例如说 商机 ID
|
* 根据商机ID获取关联客户的合同数量
|
||||||
* @param businessId 商机ID
|
*
|
||||||
|
* @param businessId 商机编号
|
||||||
* @return 数量
|
* @return 数量
|
||||||
*/
|
*/
|
||||||
Long selectCountByBusinessId(Long businessId);
|
Long selectCountByBusinessId(Long businessId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,33 @@ package cn.iocoder.yudao.module.crm.service.contract;
|
|||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.collection.ListUtil;
|
import cn.hutool.core.collection.ListUtil;
|
||||||
|
import cn.hutool.core.util.ObjUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
|
||||||
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.task.BpmProcessInstanceApi;
|
||||||
|
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractPageReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractSaveReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.CrmContractTransferReqVO;
|
||||||
import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
|
import cn.iocoder.yudao.module.crm.convert.contract.CrmContractConvert;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
|
||||||
|
import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
|
import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
|
||||||
|
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
|
||||||
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
|
||||||
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
|
import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessProductService;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
|
||||||
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
import cn.iocoder.yudao.module.crm.service.followup.bo.CrmUpdateFollowUpReqBO;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
|
||||||
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
|
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
|
||||||
|
import cn.iocoder.yudao.module.crm.service.product.CrmProductService;
|
||||||
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
||||||
import com.mzt.logapi.context.LogRecordContext;
|
import com.mzt.logapi.context.LogRecordContext;
|
||||||
import com.mzt.logapi.service.impl.DiffParseFunction;
|
import com.mzt.logapi.service.impl.DiffParseFunction;
|
||||||
import com.mzt.logapi.starter.annotation.LogRecord;
|
import com.mzt.logapi.starter.annotation.LogRecord;
|
||||||
@ -26,10 +39,14 @@ import org.springframework.validation.annotation.Validated;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
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.crm.enums.ErrorCodeConstants.CONTRACT_NOT_EXISTS;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||||
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
||||||
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CRM 合同 Service 实现类
|
* CRM 合同 Service 实现类
|
||||||
@ -40,21 +57,36 @@ import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
|||||||
@Validated
|
@Validated
|
||||||
public class CrmContractServiceImpl implements CrmContractService {
|
public class CrmContractServiceImpl implements CrmContractService {
|
||||||
|
|
||||||
|
public static final String CONTRACT_APPROVE = "contract-approve"; // 合同审批流程标识
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmContractMapper contractMapper;
|
private CrmContractMapper contractMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private CrmPermissionService crmPermissionService;
|
private CrmPermissionService crmPermissionService;
|
||||||
|
@Resource
|
||||||
|
private CrmBusinessProductService businessProductService;
|
||||||
|
@Resource
|
||||||
|
private CrmProductService productService;
|
||||||
|
@Resource
|
||||||
|
private BpmProcessInstanceApi bpmProcessInstanceApi;
|
||||||
|
@Resource
|
||||||
|
private CrmCustomerService customerService;
|
||||||
|
@Resource
|
||||||
|
private CrmContactService contactService;
|
||||||
|
@Resource
|
||||||
|
private CrmBusinessService businessService;
|
||||||
|
@Resource
|
||||||
|
private AdminUserApi adminUserApi;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}",
|
@LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_CREATE_SUB_TYPE, bizNo = "{{#contract.id}}",
|
||||||
success = CRM_CONTRACT_CREATE_SUCCESS)
|
success = CRM_CONTRACT_CREATE_SUCCESS)
|
||||||
public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) {
|
public Long createContract(CrmContractSaveReqVO createReqVO, Long userId) {
|
||||||
createReqVO.setId(null);
|
validateRelationDataExists(createReqVO);
|
||||||
// TODO @合同待定:插入合同商品;需要搞个 BusinessProductDO
|
|
||||||
// 插入合同
|
// 插入合同
|
||||||
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class);
|
CrmContractDO contract = BeanUtils.toBean(createReqVO, CrmContractDO.class).setId(null);
|
||||||
contractMapper.insert(contract);
|
contractMapper.insert(contract);
|
||||||
|
|
||||||
// 创建数据权限
|
// 创建数据权限
|
||||||
@ -62,6 +94,9 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||||||
.setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId())
|
.setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()).setBizId(contract.getId())
|
||||||
.setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
.setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
|
||||||
|
|
||||||
|
// 插入商机关联商品
|
||||||
|
List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(createReqVO);
|
||||||
|
businessProductService.insertBatch(businessProduct);
|
||||||
// 4. 记录操作日志上下文
|
// 4. 记录操作日志上下文
|
||||||
LogRecordContext.putVariable("contract", contract);
|
LogRecordContext.putVariable("contract", contract);
|
||||||
return contract.getId();
|
return contract.getId();
|
||||||
@ -74,12 +109,21 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||||||
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
|
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
|
||||||
public void updateContract(CrmContractSaveReqVO updateReqVO) {
|
public void updateContract(CrmContractSaveReqVO updateReqVO) {
|
||||||
// TODO @合同待定:只有草稿、审批中,可以编辑;
|
// TODO @合同待定:只有草稿、审批中,可以编辑;
|
||||||
|
if (ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) ||
|
||||||
|
ObjUtil.notEqual(updateReqVO.getAuditStatus(), CrmAuditStatusEnum.PROCESS.getStatus())) {
|
||||||
|
throw exception(CONTRACT_UPDATE_FAIL_EDITING_PROHIBITED);
|
||||||
|
}
|
||||||
|
validateRelationDataExists(updateReqVO);
|
||||||
// 校验存在
|
// 校验存在
|
||||||
CrmContractDO oldContract = validateContractExists(updateReqVO.getId());
|
CrmContractDO oldContract = validateContractExists(updateReqVO.getId());
|
||||||
// 更新合同
|
// 更新合同
|
||||||
CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
|
CrmContractDO updateObj = BeanUtils.toBean(updateReqVO, CrmContractDO.class);
|
||||||
contractMapper.updateById(updateObj);
|
contractMapper.updateById(updateObj);
|
||||||
// TODO @合同待定:插入合同商品;需要搞个 BusinessProductDO
|
|
||||||
|
// TODO puhui999: @芋艿:合同变更关联的商机后商品怎么处理?
|
||||||
|
//List<CrmBusinessProductDO> businessProduct = convertBusinessProductList(updateReqVO);
|
||||||
|
//businessProductService.selectListByBusinessId()
|
||||||
|
//diffList()
|
||||||
|
|
||||||
// 3. 记录操作日志上下文
|
// 3. 记录操作日志上下文
|
||||||
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
|
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldContract, CrmContractSaveReqVO.class));
|
||||||
@ -88,8 +132,55 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||||||
|
|
||||||
// TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
|
// TODO @合同待定:缺一个取消合同的接口;只有草稿、审批中可以取消;CrmAuditStatusEnum
|
||||||
|
|
||||||
// TODO @合同待定:缺一个发起审批的接口;只有草稿可以发起审批;CrmAuditStatusEnum
|
private List<CrmBusinessProductDO> convertBusinessProductList(CrmContractSaveReqVO reqVO) {
|
||||||
|
// 校验商品存在
|
||||||
|
Set<Long> productIds = convertSet(reqVO.getProductItems(), CrmContractSaveReqVO.CrmContractProductItem::getId);
|
||||||
|
List<CrmProductDO> productList = productService.getProductList(productIds);
|
||||||
|
if (CollUtil.isEmpty(productIds) || productList.size() != productIds.size()) {
|
||||||
|
throw exception(PRODUCT_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
Map<Long, CrmProductDO> productMap = convertMap(productList, CrmProductDO::getId);
|
||||||
|
return convertList(reqVO.getProductItems(), productItem -> {
|
||||||
|
CrmBusinessProductDO businessProduct = BeanUtils.toBean(productMap.get(productItem.getId()), CrmBusinessProductDO.class);
|
||||||
|
businessProduct.setId(null).setBusinessId(reqVO.getBusinessId()).setProductId(productItem.getId())
|
||||||
|
.setCount(productItem.getCount()).setDiscountPercent(productItem.getDiscountPercent()).setTotalPrice(calculator(businessProduct));
|
||||||
|
return businessProduct;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算商品总价
|
||||||
|
*
|
||||||
|
* @param businessProduct 关联商品
|
||||||
|
* @return 商品总价
|
||||||
|
*/
|
||||||
|
private Integer calculator(CrmBusinessProductDO businessProduct) {
|
||||||
|
int price = businessProduct.getPrice() * businessProduct.getCount();
|
||||||
|
if (businessProduct.getDiscountPercent() == null) {
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
return MoneyUtils.calculateRatePriceFloor(price, (double) (businessProduct.getDiscountPercent() / 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验关联数据是否存在
|
||||||
|
*
|
||||||
|
* @param reqVO 请求
|
||||||
|
*/
|
||||||
|
private void validateRelationDataExists(CrmContractSaveReqVO reqVO) {
|
||||||
|
// 1. 校验客户
|
||||||
|
if (reqVO.getCustomerId() != null && customerService.getCustomer(reqVO.getCustomerId()) == null) {
|
||||||
|
throw exception(CUSTOMER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
// 2. 校验负责人
|
||||||
|
if (reqVO.getOwnerUserId() != null && adminUserApi.getUser(reqVO.getOwnerUserId()) == null) {
|
||||||
|
throw exception(USER_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
// 4. 如果有关联商机,则需要校验存在
|
||||||
|
if (reqVO.getBusinessId() != null && businessService.getBusiness(reqVO.getBusinessId()) == null) {
|
||||||
|
throw exception(BUSINESS_NOT_EXISTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@ -141,6 +232,18 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||||||
contractMapper.updateById(BeanUtils.toBean(contractUpdateFollowUpReqBO, CrmContractDO.class).setId(contractUpdateFollowUpReqBO.getBizId()));
|
contractMapper.updateById(BeanUtils.toBean(contractUpdateFollowUpReqBO, CrmContractDO.class).setId(contractUpdateFollowUpReqBO.getBizId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void handleApprove(Long id, Long userId) {
|
||||||
|
// 创建合同审批流程实例
|
||||||
|
String processInstanceId = bpmProcessInstanceApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
|
||||||
|
.setProcessDefinitionKey(CONTRACT_APPROVE).setBusinessKey(String.valueOf(id)));
|
||||||
|
|
||||||
|
// 更新合同工作流编号
|
||||||
|
contractMapper.updateById(new CrmContractDO().setId(id).setProcessInstanceId(processInstanceId)
|
||||||
|
.setAuditStatus(CrmAuditStatusEnum.PROCESS.getStatus()));
|
||||||
|
}
|
||||||
|
|
||||||
//======================= 查询相关 =======================
|
//======================= 查询相关 =======================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -182,6 +285,5 @@ public class CrmContractServiceImpl implements CrmContractService {
|
|||||||
public Long selectCountByBusinessId(Long businessId) {
|
public Long selectCountByBusinessId(Long businessId) {
|
||||||
return contractMapper.selectCountByBusinessId(businessId);
|
return contractMapper.selectCountByBusinessId(businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒;
|
// TODO @合同待定:需要新增一个 ContractConfigDO 表,合同配置,重点是到期提醒;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package cn.iocoder.yudao.module.crm.service.contract.listener;
|
||||||
|
|
||||||
|
public class CrmContractResultListener {
|
||||||
|
// TODO puhui999: @芋艿: 艿艿写一下这个,没研究明白哈哈
|
||||||
|
}
|
@ -1,10 +1,7 @@
|
|||||||
package cn.iocoder.yudao.module.crm.service.customer;
|
package cn.iocoder.yudao.module.crm.service.customer;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO;
|
||||||
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
import cn.iocoder.yudao.module.crm.service.customer.bo.CrmCustomerCreateReqBO;
|
||||||
@ -109,6 +106,16 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId);
|
Long createCustomer(CrmCustomerCreateReqBO customerCreateReq, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量导入客户
|
||||||
|
*
|
||||||
|
* @param importCustomers 导入客户列表
|
||||||
|
* @param isUpdateSupport 是否支持更新
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @return 导入结果
|
||||||
|
*/
|
||||||
|
CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport, Long userId);
|
||||||
|
|
||||||
// ==================== 公海相关操作 ====================
|
// ==================== 公海相关操作 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,13 +134,12 @@ public interface CrmCustomerService {
|
|||||||
*/
|
*/
|
||||||
void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
|
void receiveCustomer(List<Long> ids, Long ownerUserId, Boolean isReceive);
|
||||||
|
|
||||||
// TODO @puhui999:autoPutCustomerPool,注释说明是系统就好哈;
|
|
||||||
/**
|
/**
|
||||||
* 【系统】客户自动掉入公海
|
* 【系统】客户自动掉入公海
|
||||||
*
|
*
|
||||||
* @return 掉入公海数量
|
* @return 掉入公海数量
|
||||||
*/
|
*/
|
||||||
int customerAutoPutPoolBySystem();
|
int autoPutCustomerPool();
|
||||||
|
|
||||||
PageResult<CrmCustomerDO> getPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO,
|
PageResult<CrmCustomerDO> getPutInPoolRemindCustomerPage(CrmCustomerPageReqVO pageVO,
|
||||||
CrmCustomerPoolConfigDO poolConfigDO,
|
CrmCustomerPoolConfigDO poolConfigDO,
|
||||||
|
@ -3,15 +3,14 @@ package cn.iocoder.yudao.module.crm.service.customer;
|
|||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.ObjUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerLockReqVO;
|
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerSaveReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
|
|
||||||
import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
|
import cn.iocoder.yudao.module.crm.convert.customer.CrmCustomerConvert;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
|
||||||
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
|
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
|
||||||
@ -41,12 +40,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
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.filterList;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
|
import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
|
||||||
@ -96,7 +93,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1);
|
validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1);
|
||||||
|
|
||||||
// 2. 插入客户
|
// 2. 插入客户
|
||||||
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class)
|
CrmCustomerDO customer = BeanUtils.toBean(createReqVO, CrmCustomerDO.class).setOwnerUserId(userId)
|
||||||
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
||||||
customerMapper.insert(customer);
|
customerMapper.insert(customer);
|
||||||
|
|
||||||
@ -235,7 +232,55 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
return customer.getId();
|
return customer.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 公海相关操作 ====================
|
@Override
|
||||||
|
public CrmCustomerImportRespVO importCustomerList(List<CrmCustomerImportExcelVO> importCustomers, Boolean isUpdateSupport, Long userId) {
|
||||||
|
if (CollUtil.isEmpty(importCustomers)) {
|
||||||
|
throw exception(CUSTOMER_IMPORT_LIST_IS_EMPTY);
|
||||||
|
}
|
||||||
|
CrmCustomerImportRespVO respVO = CrmCustomerImportRespVO.builder().createCustomerNames(new ArrayList<>())
|
||||||
|
.updateCustomerNames(new ArrayList<>()).failureCustomerNames(new LinkedHashMap<>()).build();
|
||||||
|
importCustomers.forEach(importCustomer -> {
|
||||||
|
// 校验,判断是否有不符合的原因
|
||||||
|
try {
|
||||||
|
validateCustomerForCreate(importCustomer);
|
||||||
|
} catch (ServiceException ex) {
|
||||||
|
respVO.getFailureCustomerNames().put(importCustomer.getName(), ex.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 判断如果不存在,在进行插入
|
||||||
|
CrmCustomerDO existCustomer = customerMapper.selectByCustomerName(importCustomer.getName());
|
||||||
|
if (existCustomer == null) {
|
||||||
|
CrmCustomerDO customer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class).setOwnerUserId(userId)
|
||||||
|
.setLockStatus(false).setDealStatus(false).setContactLastTime(LocalDateTime.now());
|
||||||
|
customerMapper.insert(customer);
|
||||||
|
respVO.getCreateCustomerNames().add(importCustomer.getName());
|
||||||
|
// 创建数据权限
|
||||||
|
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
|
||||||
|
.setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果存在,判断是否允许更新
|
||||||
|
if (!isUpdateSupport) {
|
||||||
|
respVO.getFailureCustomerNames().put(importCustomer.getName(),
|
||||||
|
StrUtil.format(CUSTOMER_NAME_EXISTS.getMsg(), importCustomer.getName()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CrmCustomerDO updateCustomer = BeanUtils.toBean(importCustomer, CrmCustomerDO.class);
|
||||||
|
updateCustomer.setId(existCustomer.getId());
|
||||||
|
customerMapper.updateById(updateCustomer);
|
||||||
|
respVO.getUpdateCustomerNames().add(importCustomer.getName());
|
||||||
|
});
|
||||||
|
return respVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateCustomerForCreate(CrmCustomerImportExcelVO importCustomer) {
|
||||||
|
// 校验客户名称不能为空
|
||||||
|
if (StrUtil.isEmptyIfStr(importCustomer.getName())) {
|
||||||
|
throw exception(CUSTOMER_CREATE_NAME_NOT_NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 公海相关操作 ====================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@ -313,23 +358,22 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int customerAutoPutPoolBySystem() {
|
public int autoPutCustomerPool() {
|
||||||
CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig();
|
CrmCustomerPoolConfigDO poolConfig = customerPoolConfigService.getCustomerPoolConfig();
|
||||||
if (poolConfig == null || !poolConfig.getEnabled()) {
|
if (poolConfig == null || !poolConfig.getEnabled()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// 1. 获取没有锁定的不在公海的客户
|
// 1.1 获取没有锁定的不在公海的客户且没有成交的
|
||||||
List<CrmCustomerDO> customerList = customerMapper.selectListByLockStatusAndOwnerUserIdNotNull(Boolean.FALSE);
|
List<CrmCustomerDO> notDealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.FALSE);
|
||||||
List<CrmCustomerDO> poolCustomerList = CollectionUtils.filterList(customerList, customer -> {
|
// 1.2 获取没有锁定的不在公海的客户且成交的
|
||||||
// TODO @puhui999:建议这里作为一个查询条件哈,不放内存里过滤;
|
List<CrmCustomerDO> dealCustomerList = customerMapper.selectListByLockAndDealStatusAndNotPool(Boolean.FALSE, Boolean.TRUE);
|
||||||
// 1.1 未成交放入公海
|
List<CrmCustomerDO> poolCustomerList = new ArrayList<>();
|
||||||
if (!customer.getDealStatus()) {
|
poolCustomerList.addAll(filterList(notDealCustomerList, customer ->
|
||||||
return (poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0;
|
(poolConfig.getDealExpireDays() - LocalDateTimeUtils.between(customer.getCreateTime())) <= 0));
|
||||||
}
|
poolCustomerList.addAll(filterList(dealCustomerList, customer -> {
|
||||||
// 1.2 未跟进放入公海
|
|
||||||
LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
|
LocalDateTime lastTime = ObjUtil.defaultIfNull(customer.getContactLastTime(), customer.getCreateTime());
|
||||||
return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0;
|
return (poolConfig.getContactExpireDays() - LocalDateTimeUtils.between(lastTime)) <= 0;
|
||||||
});
|
}));
|
||||||
|
|
||||||
// 2. 逐个放入公海
|
// 2. 逐个放入公海
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
@ -33,7 +33,6 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
|
|||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED;
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_DELETE_DENIED;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS;
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.FOLLOW_UP_RECORD_NOT_EXISTS;
|
||||||
import static cn.iocoder.yudao.module.crm.framework.permission.core.util.CrmPermissionUtils.hasPermission;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 跟进记录 Service 实现类
|
* 跟进记录 Service 实现类
|
||||||
@ -119,7 +118,7 @@ public class CrmFollowUpRecordServiceImpl implements CrmFollowUpRecordService {
|
|||||||
// 校验存在
|
// 校验存在
|
||||||
CrmFollowUpRecordDO followUpRecord = validateFollowUpRecordExists(id);
|
CrmFollowUpRecordDO followUpRecord = validateFollowUpRecordExists(id);
|
||||||
// 校验权限
|
// 校验权限
|
||||||
if (!hasPermission(followUpRecord.getBizType(), followUpRecord.getBizId(), userId, CrmPermissionLevelEnum.OWNER)) {
|
if (!permissionService.hasPermission(followUpRecord.getBizType(), followUpRecord.getBizId(), userId, CrmPermissionLevelEnum.OWNER)) {
|
||||||
throw exception(FOLLOW_UP_RECORD_DELETE_DENIED);
|
throw exception(FOLLOW_UP_RECORD_DELETE_DENIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,4 +108,15 @@ public interface CrmPermissionService {
|
|||||||
*/
|
*/
|
||||||
List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId);
|
List<CrmPermissionDO> getPermissionListByBizTypeAndUserId(Integer bizType, Long userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验权限
|
||||||
|
*
|
||||||
|
* @param bizType 数据类型,关联 {@link CrmBizTypeEnum}
|
||||||
|
* @param bizId 数据编号,关联 {@link CrmBizTypeEnum} 对应模块 DO#getId()
|
||||||
|
* @param userId 用户编号
|
||||||
|
* @param levelEnum 权限级别
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
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.anyMatch;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
|
||||||
import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isOwner;
|
import static cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum.isOwner;
|
||||||
@ -211,4 +212,11 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
|
|||||||
return permissionMapper.selectListByBizTypeAndUserId(bizType, userId);
|
return permissionMapper.selectListByBizTypeAndUserId(bizType, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPermission(Integer bizType, Long bizId, Long userId, CrmPermissionLevelEnum levelEnum) {
|
||||||
|
List<CrmPermissionDO> permissionList = permissionMapper.selectByBizTypeAndBizId(bizType, bizId);
|
||||||
|
return anyMatch(permissionList, permission ->
|
||||||
|
ObjUtil.equal(permission.getUserId(), userId) && ObjUtil.equal(permission.getLevel(), levelEnum.getLevel()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user