Merge remote-tracking branch 'yudao/develop' into develop

This commit is contained in:
puhui999 2024-01-04 09:59:50 +08:00
commit e6f4c1f0d5
65 changed files with 817 additions and 770 deletions

View File

@ -92,6 +92,8 @@
如果你想把【完整版】的功能,迁移到【精简版】,可以参考 [《迁移功能到精简版》](https://doc.iocoder.cn/migrate-module/) 文档。
如果你想把【完整版】的功能,迁移到【精简版】,可以参考 [《迁移功能到精简版》](https://doc.iocoder.cn/migrate-module/) 文档。
## 😎 开源协议
**为什么推荐使用本项目?**

View File

@ -1,6 +1,6 @@
-- `ruoyi-vue-pro`.crm_contact_business_link definition
CREATE TABLE `crm_contact_business_link` (
CREATE TABLE `crm_contact_business` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`contact_id` int(11) DEFAULT NULL COMMENT '联系人id',
`business_id` int(11) DEFAULT NULL COMMENT '商机id',
@ -10,6 +10,5 @@ CREATE TABLE `crm_contact_business_link` (
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '租户编号',
PRIMARY KEY (`id`),
UNIQUE KEY `crm_contact_business_link_un` (`contact_id`,`business_id`,`deleted`,`tenant_id`)
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='联系人商机关联表';

View File

@ -39,6 +39,10 @@ public interface ErrorCodeConstants {
ErrorCode CUSTOMER_IN_POOL = new ErrorCode(1_020_006_004, "客户【{}】放入公海失败,原因:已经是公海客户");
ErrorCode CUSTOMER_LOCKED_PUT_POOL_FAIL = new ErrorCode(1_020_006_005, "客户【{}】放入公海失败,原因:客户已锁定");
ErrorCode CUSTOMER_UPDATE_OWNER_USER_FAIL = new ErrorCode(1_020_006_006, "更新客户【{}】负责人失败, 原因:系统异常");
ErrorCode CUSTOMER_LOCK_FAIL_IS_LOCK = new ErrorCode(1_020_006_007, "锁定客户失败,它已经处于锁定状态");
ErrorCode CUSTOMER_UNLOCK_FAIL_IS_UNLOCK = new ErrorCode(1_020_006_008, "锁定客户失败,它已经处于未锁定状态");
ErrorCode CUSTOMER_LOCK_EXCEED_LIMIT = new ErrorCode(1_020_006_009, "锁定客户失败,超出锁定规则上限");
ErrorCode CUSTOMER_OWNER_EXCEED_LIMIT = new ErrorCode(1_020_006_010, "操作失败,超出客户数拥有上限");
// ========== 权限管理 1_020_007_000 ==========
ErrorCode CRM_PERMISSION_NOT_EXISTS = new ErrorCode(1_020_007_000, "数据权限不存在");

View File

@ -18,19 +18,19 @@ public enum CrmCustomerLimitConfigTypeEnum implements IntArrayValuable {
/**
* 拥有客户数限制
*/
CUSTOMER_QUANTITY_LIMIT(1, "拥有客户数限制"),
CUSTOMER_OWNER_LIMIT(1, "拥有客户数限制"),
/**
* 锁定客户数限制
*/
CUSTOMER_LOCK_LIMIT(2, "锁定客户数限制"),
;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLimitConfigTypeEnum::getCode).toArray();
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(CrmCustomerLimitConfigTypeEnum::getType).toArray();
/**
* 状态
*/
private final Integer code;
private final Integer type;
/**
* 状态名
*/

View File

@ -7,8 +7,6 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.*;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusinessStatusQueryVO;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO;
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
@ -30,12 +28,10 @@ import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
@ -47,16 +43,14 @@ public class CrmBusinessController {
@Resource
private CrmBusinessService businessService;
@Resource
private CrmCustomerService customerService;
@Resource
private CrmBusinessStatusTypeService businessStatusTypeService;
@Resource
private CrmBusinessStatusService businessStatusService;
// TODO @商机待定CrmBusinessCreateReqVOCrmBusinessUpdateReqVOCrmBusinessRespVO 按照新的 VO 规范
@PostMapping("/create")
@Operation(summary = "创建商机")
@PreAuthorize("@ss.hasPermission('crm:business:create')")
@ -95,27 +89,7 @@ public class CrmBusinessController {
@PreAuthorize("@ss.hasPermission('crm:business:query')")
public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) {
PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(pageVO, getLoginUserId());
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
// 处理客户名称回显
// TODO @ljlleo可以使用 CollectionUtils.convertSet 替代常用的 stream 操作更简洁一点下面几个也是哈
Set<Long> customerIds = pageResult.getList().stream()
.map(CrmBusinessDO::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet());
List<CrmCustomerDO> customerList = customerService.getCustomerList(customerIds, getLoginUserId());
// 处理商机状态类型名称回显
Set<Long> statusTypeIds = pageResult.getList().stream()
.map(CrmBusinessDO::getStatusTypeId).filter(Objects::nonNull).collect(Collectors.toSet());
CrmBusinessStatusTypeQueryVO queryStatusTypeVO = new CrmBusinessStatusTypeQueryVO();
queryStatusTypeVO.setIdList(statusTypeIds);
List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.selectList(queryStatusTypeVO);
// 处理商机状态名称回显
Set<Long> statusIds = pageResult.getList().stream()
.map(CrmBusinessDO::getStatusId).filter(Objects::nonNull).collect(Collectors.toSet());
CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO();
queryVO.setIdList(statusIds);
List<CrmBusinessStatusDO> statusList = businessStatusService.selectList(queryVO);
return success(CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList));
return success(buildBusinessDetailPageResult(pageResult));
}
@GetMapping("/page-by-customer")
@ -123,24 +97,15 @@ public class CrmBusinessController {
public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessPageByCustomer(@Valid CrmBusinessPageReqVO pageReqVO) {
Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空");
PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByCustomerId(pageReqVO);
// 处理客户名称回显
// TODO @ljlleo可以使用 CollectionUtils.convertSet 替代常用的 stream 操作更简洁一点下面几个也是哈
Set<Long> customerIds = pageResult.getList().stream()
.map(CrmBusinessDO::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet());
List<CrmCustomerDO> customerList = customerService.getCustomerList(customerIds, getLoginUserId());
// 处理商机状态类型名称回显
Set<Long> statusTypeIds = pageResult.getList().stream()
.map(CrmBusinessDO::getStatusTypeId).filter(Objects::nonNull).collect(Collectors.toSet());
CrmBusinessStatusTypeQueryVO queryStatusTypeVO = new CrmBusinessStatusTypeQueryVO();
queryStatusTypeVO.setIdList(statusTypeIds);
List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.selectList(queryStatusTypeVO);
// 处理商机状态名称回显
Set<Long> statusIds = pageResult.getList().stream()
.map(CrmBusinessDO::getStatusId).filter(Objects::nonNull).collect(Collectors.toSet());
CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO();
queryVO.setIdList(statusIds);
List<CrmBusinessStatusDO> statusList = businessStatusService.selectList(queryVO);
return success(CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList));
return success(buildBusinessDetailPageResult(pageResult));
}
@GetMapping("/page-by-contact")
@Operation(summary = "获得联系人的商机分页")
@PreAuthorize("@ss.hasPermission('crm:business:query')")
public CommonResult<PageResult<CrmBusinessRespVO>> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) {
PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPageByContact(pageReqVO);
return success(buildBusinessDetailPageResult(pageResult));
}
@GetMapping("/export-excel")
@ -152,8 +117,27 @@ public class CrmBusinessController {
exportReqVO.setPageSize(PAGE_SIZE_NONE);
PageResult<CrmBusinessDO> pageResult = businessService.getBusinessPage(exportReqVO, getLoginUserId());
// 导出 Excel
ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessExcelVO.class,
CrmBusinessConvert.INSTANCE.convertList02(pageResult.getList()));
ExcelUtils.write(response, "商机.xls", "数据", CrmBusinessRespVO.class,
buildBusinessDetailPageResult(pageResult).getList());
}
/**
* 构建详细的商机分页结果
*
* @param pageResult 简单的商机分页结果
* @return 详细的商机分页结果
*/
private PageResult<CrmBusinessRespVO> buildBusinessDetailPageResult(PageResult<CrmBusinessDO> pageResult) {
if (CollUtil.isEmpty(pageResult.getList())) {
return PageResult.empty(pageResult.getTotal());
}
List<CrmBusinessStatusTypeDO> statusTypeList = businessStatusTypeService.getBusinessStatusTypeList(
convertSet(pageResult.getList(), CrmBusinessDO::getStatusTypeId));
List<CrmBusinessStatusDO> statusList = businessStatusService.getBusinessStatusList(
convertSet(pageResult.getList(), CrmBusinessDO::getStatusId));
List<CrmCustomerDO> customerList = customerService.getCustomerList(
convertSet(pageResult.getList(), CrmBusinessDO::getCustomerId));
return CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList);
}
@PutMapping("/transfer")

View File

@ -20,6 +20,9 @@ public class CrmBusinessPageReqVO extends PageParam {
@Schema(description = "客户编号", example = "10795")
private Long customerId;
@Schema(description = "联系人编号", example = "10795")
private Long contactId;
@Schema(description = "场景类型", example = "1")
@InEnum(CrmSceneTypeEnum.class)
private Integer sceneType; // 场景类型 null 时则表示全部

View File

@ -6,6 +6,7 @@ import cn.hutool.core.util.NumberUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*;
@ -13,6 +14,7 @@ import cn.iocoder.yudao.module.crm.convert.contact.CrmContactConvert;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService;
import cn.iocoder.yudao.module.crm.service.contact.CrmContactService;
import cn.iocoder.yudao.module.crm.service.customer.CrmCustomerService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -54,10 +56,13 @@ public class CrmContactController {
private CrmContactService contactService;
@Resource
private CrmCustomerService customerService;
@Resource
private AdminUserApi adminUserApi;
@Resource
private CrmContactBusinessService contactBusinessLinkService;
// TODO @zynaCrmContactCreateReqVOCrmContactUpdateReqVOCrmContactRespVO 按照新的 VO 规范搞哈可以参考 dept 模块
@PostMapping("/create")
@Operation(summary = "创建联系人")
@PreAuthorize("@ss.hasPermission('crm:contact:create')")
@ -96,7 +101,7 @@ public class CrmContactController {
NumberUtil.parseLong(contact.getCreator()), contact.getOwnerUserId())));
// 2. 获取客户信息
List<CrmCustomerDO> customerList = customerService.getCustomerList(
Collections.singletonList(contact.getCustomerId()), getLoginUserId());
Collections.singletonList(contact.getCustomerId()));
// 3. 直属上级
List<CrmContactDO> parentContactList = contactService.getContactList(
Collections.singletonList(contact.getParentId()), getLoginUserId());
@ -107,10 +112,11 @@ public class CrmContactController {
@Operation(summary = "获得联系人列表")
@PreAuthorize("@ss.hasPermission('crm:contact:query')")
public CommonResult<List<CrmContactSimpleRespVO>> getSimpleContactList() {
// TODO @zyna建议 contactService 单独搞个 list 接口哈
CrmContactPageReqVO pageReqVO = new CrmContactPageReqVO();
pageReqVO.setPageSize(PAGE_SIZE_NONE);
List<CrmContactDO> list = contactService.getContactPage(pageReqVO, getLoginUserId()).getList();
return success(CrmContactConvert.INSTANCE.convertAllList(list));
return success(BeanUtils.toBean(list, CrmContactSimpleRespVO.class));
}
@GetMapping("/page")
@ -118,7 +124,7 @@ public class CrmContactController {
@PreAuthorize("@ss.hasPermission('crm:contact:query')")
public CommonResult<PageResult<CrmContactRespVO>> getContactPage(@Valid CrmContactPageReqVO pageVO) {
PageResult<CrmContactDO> pageResult = contactService.getContactPage(pageVO, getLoginUserId());
return success(convertDetailContactPage(pageResult));
return success(buildContactDetailPage(pageResult));
}
@GetMapping("/page-by-customer")
@ -126,7 +132,7 @@ public class CrmContactController {
public CommonResult<PageResult<CrmContactRespVO>> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) {
Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空");
PageResult<CrmContactDO> pageResult = contactService.getContactPageByCustomerId(pageVO);
return success(convertDetailContactPage(pageResult));
return success(buildContactDetailPage(pageResult));
}
@GetMapping("/export-excel")
@ -138,23 +144,23 @@ public class CrmContactController {
exportReqVO.setPageNo(PAGE_SIZE_NONE);
PageResult<CrmContactDO> pageResult = contactService.getContactPage(exportReqVO, getLoginUserId());
ExcelUtils.write(response, "联系人.xls", "数据", CrmContactRespVO.class,
convertDetailContactPage(pageResult).getList());
buildContactDetailPage(pageResult).getList());
}
/**
* 转换成详细的联系人分页即读取关联信息
* 构建详细的联系人分页结果
*
* @param pageResult 联系人分页
* @return 详细的联系人分页
* @param pageResult 简单的联系人分页结果
* @return 详细的联系人分页结果
*/
private PageResult<CrmContactRespVO> convertDetailContactPage(PageResult<CrmContactDO> pageResult) {
private PageResult<CrmContactRespVO> buildContactDetailPage(PageResult<CrmContactDO> pageResult) {
List<CrmContactDO> contactList = pageResult.getList();
if (CollUtil.isEmpty(contactList)) {
return PageResult.empty(pageResult.getTotal());
}
// 1. 获取客户列表
List<CrmCustomerDO> crmCustomerDOList = customerService.getCustomerList(
convertSet(contactList, CrmContactDO::getCustomerId), getLoginUserId());
convertSet(contactList, CrmContactDO::getCustomerId));
// 2. 获取创建人负责人列表
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList,
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));
@ -172,4 +178,22 @@ public class CrmContactController {
return success(true);
}
// ================== 关联/取关联系人 ===================
@PostMapping("/create-business-list")
@Operation(summary = "创建联系人与联系人的关联")
@PreAuthorize("@ss.hasPermission('crm:contact:create-business')")
public CommonResult<Boolean> createContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO createReqVO) {
contactBusinessLinkService.createContactBusinessList(createReqVO);
return success(true);
}
@DeleteMapping("/delete-business-list")
@Operation(summary = "删除联系人与联系人的关联")
@PreAuthorize("@ss.hasPermission('crm:contact:delete-business')")
public CommonResult<Boolean> deleteContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO deleteReqVO) {
contactBusinessLinkService.deleteContactBusinessList(deleteReqVO);
return success(true);
}
}

View File

@ -8,11 +8,11 @@ import cn.iocoder.yudao.module.infra.enums.DictTypeConstants;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY;
@ -75,29 +75,29 @@ public class CrmContactBaseVO {
@ExcelProperty(value = "邮箱",order = 4)
private String email;
@Schema(description = "地区编号", example = "20158")
private Integer areaId;
@ExcelProperty(value = "地址",order = 5)
@Schema(description = "地址")
private String address;
@Schema(description = "下次联系时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
@ExcelProperty(value = "下次联系时间",order = 6)
private LocalDateTime nextTime;
private String detailAddress;
@Schema(description = "备注", example = "你说的对")
@ExcelProperty(value = "备注",order = 6)
private String remark;
@Schema(description = "最后跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ExcelProperty(value = "最后跟进时间",order = 6)
private LocalDateTime lastTime;
@Schema(description = "负责人用户编号", example = "14334")
@NotNull(message = "负责人不能为空")
private Long ownerUserId;
@Schema(description = "地区编号", example = "20158")
private Integer areaId;
@Schema(description = "最后跟进时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@ExcelProperty(value = "最后跟进时间",order = 6)
private LocalDateTime contactLastTime;
@Schema(description = "下次联系时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY)
@ExcelProperty(value = "下次联系时间",order = 6)
private LocalDateTime contactNextTime;
}

View File

@ -0,0 +1,22 @@
package cn.iocoder.yudao.module.crm.controller.admin.contact.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Schema(description = "管理后台 - CRM 联系人商机 Request VO") // 用于关联取消关联的操作
@Data
public class CrmContactBusinessReqVO {
@Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878")
@NotNull(message="联系人不能为空")
private Long contactId;
@Schema(description = "商机编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638")
@NotEmpty(message="商机不能为空")
private List<Long> businessIds;
}

View File

@ -1,115 +0,0 @@
package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContactBusinessLinkDO;
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
import cn.iocoder.yudao.module.crm.service.contactbusinesslink.CrmContactBusinessLinkService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS;
@Tag(name = "管理后台 - CRM 联系人商机关联")
@RestController
@RequestMapping("/crm/contact-business-link")
@Validated
public class CrmContactBusinessLinkController {
@Resource
private CrmContactBusinessLinkService contactBusinessLinkService;
@Resource
private CrmBusinessService crmBusinessService;
// TODO @zynacreateContactBusinessLink createContactBusinessLinkBatch 是不是合并成一个接口contactIdList<businessId>
@PostMapping("/create")
@Operation(summary = "创建联系人商机关联")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:create')")
public CommonResult<Long> createContactBusinessLink(@Valid @RequestBody CrmContactBusinessLinkSaveReqVO createReqVO) {
return success(contactBusinessLinkService.createContactBusinessLink(createReqVO));
}
@PostMapping("/create-batch")
@Operation(summary = "创建联系人商机关联")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:create')")
@Transactional(rollbackFor = Exception.class)
public CommonResult<Boolean> createContactBusinessLinkBatch(
@Valid @RequestBody List<CrmContactBusinessLinkSaveReqVO> createReqVO) {
createReqVO.stream().forEach(item -> {
CrmBusinessDO crmBusinessDO = crmBusinessService.getBusiness(item.getBusinessId());
if(crmBusinessDO == null){
throw exception(BUSINESS_NOT_EXISTS);
}
});
contactBusinessLinkService.createContactBusinessLinkBatch(createReqVO);
return success(true);
}
// TODO @zyna这个接口是不是可以删除掉了哈应该不存在更新
@PutMapping("/update")
@Operation(summary = "更新联系人商机关联")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:update')")
public CommonResult<Boolean> updateContactBusinessLink(@Valid @RequestBody CrmContactBusinessLinkSaveReqVO updateReqVO) {
contactBusinessLinkService.updateContactBusinessLink(updateReqVO);
return success(true);
}
// TODO @zyna删除是不是传递 ids
@DeleteMapping("/delete-batch")
@Operation(summary = "批量删除联系人商机关联")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:delete')")
public CommonResult<Boolean> deleteContactBusinessLinkBatch(@Valid @RequestBody List<CrmContactBusinessLinkSaveReqVO> deleteList) {
contactBusinessLinkService.deleteContactBusinessLink(deleteList);
return success(true);
}
// TODO @zyna这个接口是不是可以删除掉了哈应该不存在单个读取
@GetMapping("/get")
@Operation(summary = "获得联系人商机关联")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:query')")
public CommonResult<CrmContactBusinessLinkRespVO> getContactBusinessLink(@RequestParam("id") Long id) {
CrmContactBusinessLinkDO contactBusinessLink = contactBusinessLinkService.getContactBusinessLink(id);
return success(BeanUtils.toBean(contactBusinessLink, CrmContactBusinessLinkRespVO.class));
}
// TODO @zyna这个可以转化下使用客户编号去查询就是使用 CrmBusinessController getBusinessPageByCustomer 接口目的是复用
@GetMapping("/page-by-contact")
@Operation(summary = "获得联系人商机关联")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:query')")
public CommonResult<PageResult<CrmBusinessRespVO>> getContactBusinessLinkByContact(
@Valid CrmContactBusinessLinkPageReqVO pageReqVO) {
PageResult<CrmBusinessRespVO> contactBusinessLink = contactBusinessLinkService.getContactBusinessLinkPageByContact(pageReqVO);
return success(contactBusinessLink);
}
// TODO @zyna这个优化下搞到 CrmBusinessController 里去加一个 CrmBusinessController getBusinessPageByContact 接口目的是
@GetMapping("/page")
@Operation(summary = "获得联系人商机关联分页")
@PreAuthorize("@ss.hasPermission('crm:contact-business-link:query')")
public CommonResult<PageResult<CrmContactBusinessLinkRespVO>> getContactBusinessLinkPage(
@Valid CrmContactBusinessLinkPageReqVO pageReqVO) {
PageResult<CrmContactBusinessLinkDO> pageResult = contactBusinessLinkService.getContactBusinessLinkPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, CrmContactBusinessLinkRespVO.class));
}
// TODO @zyna最终梳理完后应该就 2 个接口要不直接合并到 CrmContactController 不作为独立模块就关联接触关联其实和 user 设置它有哪些岗位部门是类似的
}

View File

@ -1,30 +0,0 @@
package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - CRM 联系人商机关联分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class CrmContactBusinessLinkPageReqVO extends PageParam {
@Schema(description = "联系人编号", example = "20878")
private Long contactId;
@Schema(description = "商机编号", example = "7638")
private Long businessId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -1,26 +0,0 @@
package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - CRM 联系人商机关联 Response VO")
@Data
public class CrmContactBusinessLinkRespVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "17220")
@ExcelProperty("主键")
private Long id;
@Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878")
private Long contactId;
@Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638")
private Long businessId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
}

View File

@ -1,23 +0,0 @@
package cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import jakarta.validation.constraints.NotNull;
@Schema(description = "管理后台 - CRM 联系人商机关联新增/修改 Request VO")
@Data
public class CrmContactBusinessLinkSaveReqVO {
@Schema(description = "主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "17220")
private Long id;
@Schema(description = "联系人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20878")
@NotNull(message="联系人不能为空")
private Long contactId;
@Schema(description = "商机编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7638")
@NotNull(message="商机不能为空")
private Long businessId;
}

View File

@ -88,7 +88,7 @@ public class CrmContractController {
@PreAuthorize("@ss.hasPermission('crm:contract:query')")
public CommonResult<PageResult<ContractRespVO>> getContractPage(@Valid CrmContractPageReqVO pageVO) {
PageResult<CrmContractDO> pageResult = contractService.getContractPage(pageVO, getLoginUserId());
return success(convertDetailContractPage(pageResult));
return success(buildContractDetailPage(pageResult));
}
@GetMapping("/page-by-customer")
@ -96,7 +96,7 @@ public class CrmContractController {
public CommonResult<PageResult<ContractRespVO>> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) {
Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空");
PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageVO);
return success(convertDetailContractPage(pageResult));
return success(buildContractDetailPage(pageResult));
}
@GetMapping("/export-excel")
@ -112,19 +112,19 @@ public class CrmContractController {
}
/**
* 转换成详细的合同分页即读取关联信息
* 构建详细的合同分页结果
*
* @param pageResult 合同分页
* @return 详细的合同分页
* @param pageResult 简单的合同分页结果
* @return 详细的合同分页结果
*/
private PageResult<ContractRespVO> convertDetailContractPage(PageResult<CrmContractDO> pageResult) {
private PageResult<ContractRespVO> buildContractDetailPage(PageResult<CrmContractDO> pageResult) {
List<CrmContractDO> contactList = pageResult.getList();
if (CollUtil.isEmpty(contactList)) {
return PageResult.empty(pageResult.getTotal());
}
// 1. 获取客户列表
List<CrmCustomerDO> customerList = customerService.getCustomerList(
convertSet(contactList, CrmContractDO::getCustomerId), getLoginUserId());
convertSet(contactList, CrmContractDO::getCustomerId));
// 2. 获取创建人负责人列表
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList,
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));

View File

@ -58,6 +58,7 @@ public class CrmCustomerController {
@Resource
private OperateLogApi operateLogApi;
// TODO @puhui999 CrmCustomerCreateReqVOCrmCustomerUpdateReqVOCrmCustomerRespVO 按照新的规范搞一下哈
@PostMapping("/create")
@Operation(summary = "创建客户")
@OperateLog(enable = false) // TODO 关闭原有日志记录@puhui999注解都先删除先记录没关系我们下个迭代就都删除掉操作日志了
@ -114,6 +115,7 @@ public class CrmCustomerController {
}
// 2. 拼接数据
// TODO @puhui999距离进入公海的时间
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSetByFlatMap(pageResult.getList(), user -> Stream.of(Long.parseLong(user.getCreator()), user.getOwnerUserId())));
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
@ -134,7 +136,7 @@ public class CrmCustomerController {
}
@PutMapping("/transfer")
@Operation(summary = "客户转移")
@Operation(summary = "转移客户")
@OperateLog(enable = false) // TODO 关闭原有日志记录
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
public CommonResult<Boolean> transfer(@Valid @RequestBody CrmCustomerTransferReqVO reqVO) {
@ -152,13 +154,12 @@ public class CrmCustomerController {
return success(operateLogApi.getOperateLogPage(BeanUtils.toBean(reqVO, OperateLogV2PageReqDTO.class)));
}
// TODO @Joey单独建一个属于自己业务的 ReqVO因为前端如果模拟请求是不是可以更新其它字段了
@PutMapping("/lock")
@Operation(summary = "锁定/解锁客户")
@OperateLog(enable = false) // TODO 关闭原有日志记录
@PreAuthorize("@ss.hasPermission('crm:customer:update')")
public CommonResult<Boolean> lockCustomer(@Valid @RequestBody CrmCustomerUpdateReqVO updateReqVO) {
customerService.lockCustomer(updateReqVO);
public CommonResult<Boolean> lockCustomer(@Valid @RequestBody CrmCustomerLockReqVO lockReqVO) {
customerService.lockCustomer(lockReqVO, getLoginUserId());
return success(true);
}
@ -183,6 +184,7 @@ public class CrmCustomerController {
return success(true);
}
// TODO @puhui999需要搞个 VO
@PutMapping("/distribute")
@Operation(summary = "分配公海给对应负责人")
@Parameters({
@ -192,7 +194,6 @@ public class CrmCustomerController {
@PreAuthorize("@ss.hasPermission('crm:customer:distribute')")
public CommonResult<Boolean> distributeCustomer(@RequestParam(value = "ids") List<Long> ids,
@RequestParam(value = "ownerUserId") Long ownerUserId) {
// 领取公海数据
customerService.receiveCustomer(ids, ownerUserId);
return success(true);
}

View File

@ -43,6 +43,7 @@ public class CrmCustomerLimitConfigController {
@Resource
private AdminUserApi adminUserApi;
// TODO @puhui999可以把 vo 改下哈
@PostMapping("/create")
@Operation(summary = "创建客户限制配置")
@PreAuthorize("@ss.hasPermission('crm:customer-limit-config:create')")

View File

@ -26,6 +26,7 @@ public class CrmCustomerPoolConfigController {
@Resource
private CrmCustomerPoolConfigService customerPoolConfigService;
// TODO @puhui999可以把 vo 改下哈
@GetMapping("/get")
@Operation(summary = "获取客户公海规则设置")
@PreAuthorize("@ss.hasPermission('crm:customer-pool-config:query')")

View File

@ -0,0 +1,16 @@
package cn.iocoder.yudao.module.crm.controller.admin.customer.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - CRM 客户锁定/解锁 Request VO")
@Data
public class CrmCustomerLockReqVO {
@Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "13563")
private Long id;
@Schema(description = "客户锁定状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
private Boolean lockStatus;
}

View File

@ -28,4 +28,6 @@ public class CrmCustomerTransferReqVO {
@Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer oldOwnerPermissionLevel;
// TODO @puhui999联系人商机合同的转移
}

View File

@ -16,9 +16,9 @@ import java.util.Objects;
@ToString(callSuper = true)
public class CrmCustomerPoolConfigSaveReqVO extends CrmCustomerPoolConfigBaseVO {
// TODO @wanwanAssertTrue 必须 is 开头哈注意需要 json 忽略下避免被序列化
// TODO @puhui999AssertTrue 必须 is 开头哈注意需要 json 忽略下避免被序列化
@AssertTrue(message = "客户公海规则设置不正确")
// TODO @wanwan这个方法是不是拆成 2 一个校验 contactExpireDays一个校验 dealExpireDays
// TODO @puhui999这个方法是不是拆成 2 一个校验 contactExpireDays一个校验 dealExpireDays
public boolean poolEnableValid() {
if (!BooleanUtil.isTrue(getEnabled())) {
return true;
@ -27,7 +27,7 @@ public class CrmCustomerPoolConfigSaveReqVO extends CrmCustomerPoolConfigBaseVO
}
@AssertTrue(message = "客户公海规则设置不正确")
// TODO @wanwan这个方法是不是改成 isNotifyDaysValid() 更好点本质校验的是 notifyDays 是否为空
// TODO @puhui999这个方法是不是改成 isNotifyDaysValid() 更好点本质校验的是 notifyDays 是否为空
public boolean notifyEnableValid() {
if (!BooleanUtil.isTrue(getNotifyEnabled())) {
return true;

View File

@ -103,6 +103,7 @@ public class CrmPermissionController {
// 拼接数据
List<AdminUserRespDTO> userList = adminUserApi.getUserList(convertSet(permission, CrmPermissionDO::getUserId));
Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userList, AdminUserRespDTO::getDeptId));
// TODO @puhui999可能 postIds 为空的时候会导致报错看看怎么 fix
Set<Long> postIds = CollectionUtils.convertSetByFlatMap(userList, AdminUserRespDTO::getPostIds, Collection::stream);
Map<Long, PostRespDTO> postMap = postApi.getPostMap(postIds);
return success(CrmPermissionConvert.INSTANCE.convert(permission, userList, deptMap, postMap));

View File

@ -93,7 +93,7 @@ public class CrmReceivableController {
@PreAuthorize("@ss.hasPermission('crm:receivable:query')")
public CommonResult<PageResult<CrmReceivableRespVO>> getReceivablePage(@Valid CrmReceivablePageReqVO pageReqVO) {
PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePage(pageReqVO, getLoginUserId());
return success(convertDetailReceivablePage(pageResult));
return success(buildReceivableDetailPage(pageResult));
}
@GetMapping("/page-by-customer")
@ -101,7 +101,7 @@ public class CrmReceivableController {
public CommonResult<PageResult<CrmReceivableRespVO>> getReceivablePageByCustomer(@Valid CrmReceivablePageReqVO pageReqVO) {
Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空");
PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePageByCustomerId(pageReqVO);
return success(convertDetailReceivablePage(pageResult));
return success(buildReceivableDetailPage(pageResult));
}
// TODO 芋艿后面在优化导出
@ -115,23 +115,23 @@ public class CrmReceivableController {
PageResult<CrmReceivableDO> pageResult = receivableService.getReceivablePage(exportReqVO, getLoginUserId());
// 导出 Excel
ExcelUtils.write(response, "回款.xls", "数据", CrmReceivableRespVO.class,
convertDetailReceivablePage(pageResult).getList());
buildReceivableDetailPage(pageResult).getList());
}
/**
* 转换成详细的回款分页即读取关联信息
* 构建详细的回款分页结果
*
* @param pageResult 回款分页
* @return 详细的回款分页
* @param pageResult 简单的回款分页结果
* @return 详细的回款分页结果
*/
private PageResult<CrmReceivableRespVO> convertDetailReceivablePage(PageResult<CrmReceivableDO> pageResult) {
private PageResult<CrmReceivableRespVO> buildReceivableDetailPage(PageResult<CrmReceivableDO> pageResult) {
List<CrmReceivableDO> receivableList = pageResult.getList();
if (CollUtil.isEmpty(receivableList)) {
return PageResult.empty(pageResult.getTotal());
}
// 1. 获取客户列表
List<CrmCustomerDO> customerList = customerService.getCustomerList(
convertSet(receivableList, CrmReceivableDO::getCustomerId), getLoginUserId());
convertSet(receivableList, CrmReceivableDO::getCustomerId));
// 2. 获取创建人负责人列表
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(receivableList,
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));

View File

@ -123,10 +123,10 @@ public class CrmReceivablePlanController {
}
/**
* 转换成详细的回款计划分页即读取关联信息
* 构建详细的回款计划分页结果
*
* @param pageResult 回款计划分页
* @return 详细的回款计划分页
* @param pageResult 简单的回款计划分页结果
* @return 详细的回款计划分页结果
*/
private PageResult<CrmReceivablePlanRespVO> convertDetailReceivablePlanPage(PageResult<CrmReceivablePlanDO> pageResult) {
List<CrmReceivablePlanDO> receivablePlanList = pageResult.getList();
@ -135,7 +135,7 @@ public class CrmReceivablePlanController {
}
// 1. 获取客户列表
List<CrmCustomerDO> customerList = customerService.getCustomerList(
convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId), getLoginUserId());
convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId));
// 2. 获取创建人负责人列表
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(receivablePlanList,
contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId())));

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.convert.business;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
@ -9,7 +10,6 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionTransferReqBO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@ -34,25 +34,23 @@ public interface CrmBusinessConvert {
CrmBusinessRespVO convert(CrmBusinessDO bean);
List<CrmBusinessRespVO> convert(List<CrmBusinessDO> bean);
PageResult<CrmBusinessRespVO> convertPage(PageResult<CrmBusinessDO> page);
List<CrmBusinessExcelVO> convertList02(List<CrmBusinessDO> list);
@Mapping(target = "bizId", source = "reqVO.id")
CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId);
default PageResult<CrmBusinessRespVO> convertPage(PageResult<CrmBusinessDO> page, List<CrmCustomerDO> customerList,
default PageResult<CrmBusinessRespVO> convertPage(PageResult<CrmBusinessDO> pageResult, List<CrmCustomerDO> customerList,
List<CrmBusinessStatusTypeDO> statusTypeList, List<CrmBusinessStatusDO> statusList) {
PageResult<CrmBusinessRespVO> result = convertPage(page);
PageResult<CrmBusinessRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmBusinessRespVO.class);
// 拼接关联字段
Map<Long, String> customerMap = convertMap(customerList, CrmCustomerDO::getId, CrmCustomerDO::getName);
Map<Long, String> statusTypeMap = convertMap(statusTypeList, CrmBusinessStatusTypeDO::getId, CrmBusinessStatusTypeDO::getName);
Map<Long, String> statusMap = convertMap(statusList, CrmBusinessStatusDO::getId, CrmBusinessStatusDO::getName);
result.getList().forEach(type -> type
voPageResult.getList().forEach(type -> type
.setCustomerName(customerMap.get(type.getCustomerId()))
.setStatusTypeName(statusTypeMap.get(type.getStatusTypeId()))
.setStatusName(statusMap.get(type.getStatusId())));
return result;
return voPageResult;
}
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.crm.convert.contact;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
@ -13,12 +15,10 @@ import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
// TODO 芋艿convert 后面在梳理下略微有点乱
/**
* CRM 联系人 Convert
*
@ -39,64 +39,37 @@ public interface CrmContactConvert {
PageResult<CrmContactRespVO> convertPage(PageResult<CrmContactDO> page);
default PageResult<CrmContactRespVO> convertPage(PageResult<CrmContactDO> pageResult, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContactDO> parentContactList) {
List<CrmContactRespVO> list = converList(pageResult.getList(), userMap, customerList, parentContactList);
return convertPage(pageResult).setList(list);
}
List<CrmContactSimpleRespVO> convertAllList(List<CrmContactDO> list);
@Mapping(target = "bizId", source = "reqVO.id")
CrmPermissionTransferReqBO convert(CrmContactTransferReqVO reqVO, Long userId);
/**
* 转换详情信息
*
* @param contactDO 联系人
* @param userMap 用户列表
* @param crmCustomerDOList 客户
* @return ContactRespVO
*/
default CrmContactRespVO convert(CrmContactDO contactDO, Map<Long, AdminUserRespDTO> userMap, List<CrmCustomerDO> crmCustomerDOList,
List<CrmContactDO> contactList) {
default PageResult<CrmContactRespVO> convertPage(PageResult<CrmContactDO> pageResult, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContactDO> parentContactList) {
PageResult<CrmContactRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmContactRespVO.class);
// 拼接关联字段
Map<Long, CrmContactDO> parentContactMap = convertMap(parentContactList, CrmContactDO::getId);
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
voPageResult.getList().forEach(item -> {
setUserInfo(item, userMap);
findAndThen(customerMap, item.getCustomerId(), customer -> item.setCustomerName(customer.getName()));
findAndThen(parentContactMap, item.getParentId(), contactDO -> item.setParentName(contactDO.getName()));
});
return voPageResult;
}
default CrmContactRespVO convert(CrmContactDO contactDO, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContactDO> parentContactList) {
CrmContactRespVO contactVO = convert(contactDO);
setUserInfo(contactVO, userMap);
Map<Long, CrmCustomerDO> ustomerMap = crmCustomerDOList.stream().collect(Collectors.toMap(CrmCustomerDO::getId, v -> v));
Map<Long, CrmContactDO> contactMap = contactList.stream().collect(Collectors.toMap(CrmContactDO::getId, v -> v));
findAndThen(ustomerMap, contactDO.getCustomerId(), customer -> contactVO.setCustomerName(customer.getName()));
Map<Long, CrmCustomerDO> customerMap = CollectionUtils.convertMap(customerList, CrmCustomerDO::getId);
Map<Long, CrmContactDO> contactMap = CollectionUtils.convertMap(parentContactList, CrmContactDO::getId);
findAndThen(customerMap, contactDO.getCustomerId(), customer -> contactVO.setCustomerName(customer.getName()));
findAndThen(contactMap, contactDO.getParentId(), contact -> contactVO.setParentName(contact.getName()));
return contactVO;
}
default List<CrmContactRespVO> converList(List<CrmContactDO> contactList, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContactDO> parentContactList) {
List<CrmContactRespVO> result = convertList(contactList);
Map<Long, CrmContactDO> parentContactMap = convertMap(parentContactList, CrmContactDO::getId);
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
result.forEach(item -> {
setUserInfo(item, userMap);
findAndThen(customerMap, item.getCustomerId(), customer -> { // TODO @zyna这里的 { 可以去掉
item.setCustomerName(customer.getName());
});
findAndThen(parentContactMap, item.getParentId(), contactDO -> { // TODO @zyna这里的 { 可以去掉
item.setParentName(contactDO.getName());
});
});
return result;
}
/**
* 设置用户信息
*
* @param contactRespVO 联系人Response VO
* @param userMap 用户信息 map
*/
static void setUserInfo(CrmContactRespVO contactRespVO, Map<Long, AdminUserRespDTO> userMap) {
contactRespVO.setAreaName(AreaUtils.format(contactRespVO.getAreaId()));
findAndThen(userMap, contactRespVO.getOwnerUserId(), user -> {
contactRespVO.setOwnerUserName(user == null ? "" : user.getNickname());
});
findAndThen(userMap, contactRespVO.getOwnerUserId(), user -> contactRespVO.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(contactRespVO.getCreator()), user -> contactRespVO.setCreatorName(user.getNickname()));
}

View File

@ -1,16 +0,0 @@
package cn.iocoder.yudao.module.crm.convert.contactbusinessslink;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContactBusinessLinkDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
// TODO @zyna使用 BeanUtils 慢慢替代现有的 mapstruct
@Mapper
public interface CrmContactBusinessLinkConvert {
CrmContactBusinessLinkConvert INSTANCE = Mappers.getMapper(CrmContactBusinessLinkConvert.class);
CrmContactBusinessLinkDO convert(CrmContactBusinessLinkSaveReqVO bean);
List<CrmContactBusinessLinkDO> convert(List<CrmContactBusinessLinkSaveReqVO> bean);
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.convert.contract;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.contract.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
@ -43,23 +44,15 @@ public interface CrmContractConvert {
default PageResult<ContractRespVO> convertPage(PageResult<CrmContractDO> pageResult, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList) {
return new PageResult<>(converList(pageResult.getList(), userMap, customerList), pageResult.getTotal());
}
default List<ContractRespVO> converList(List<CrmContractDO> contractList, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList) {
List<ContractRespVO> result = convertList(contractList);
PageResult<ContractRespVO> voPageResult = BeanUtils.toBean(pageResult, ContractRespVO.class);
// 拼接关联字段
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
result.forEach(item -> {
setUserInfo(item, userMap);
findAndThen(customerMap, item.getCustomerId(), customer -> item.setCustomerName(customer.getName()));
voPageResult.getList().forEach(contract -> {
findAndThen(userMap, contract.getOwnerUserId(), user -> contract.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(contract.getCreator()), user -> contract.setCreatorName(user.getNickname()));
findAndThen(customerMap, contract.getCustomerId(), customer -> contract.setCustomerName(customer.getName()));
});
return result;
}
static void setUserInfo(ContractRespVO contract, Map<Long, AdminUserRespDTO> userMap) {
findAndThen(userMap, contract.getOwnerUserId(), user -> contract.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(contract.getCreator()), user -> contract.setCreatorName(user.getNickname()));
return voPageResult;
}
}

View File

@ -12,7 +12,6 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.convert.receivable;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableCreateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.receivable.CrmReceivableTransferReqVO;
@ -36,29 +37,19 @@ public interface CrmReceivableConvert {
CrmReceivableRespVO convert(CrmReceivableDO bean);
List<CrmReceivableRespVO> convertList(List<CrmReceivableDO> list);
default PageResult<CrmReceivableRespVO> convertPage(PageResult<CrmReceivableDO> pageResult, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContractDO> contractList) {
return new PageResult<>(converList(pageResult.getList(), userMap, customerList, contractList), pageResult.getTotal());
}
default List<CrmReceivableRespVO> converList(List<CrmReceivableDO> receivableList, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContractDO> contractList) {
List<CrmReceivableRespVO> result = convertList(receivableList);
PageResult<CrmReceivableRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmReceivableRespVO.class);
// 拼接关联字段
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
Map<Long, CrmContractDO> contractMap = convertMap(contractList, CrmContractDO::getId);
result.forEach(item -> {
setUserInfo(item, userMap);
findAndThen(customerMap, item.getCustomerId(), customer -> item.setCustomerName(customer.getName()));
findAndThen(contractMap, item.getContractId(), contract -> item.setContractNo(contract.getNo()));
voPageResult.getList().forEach(receivable -> {
findAndThen(userMap, receivable.getOwnerUserId(), user -> receivable.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(receivable.getCreator()), user -> receivable.setCreatorName(user.getNickname()));
findAndThen(customerMap, receivable.getCustomerId(), customer -> receivable.setCustomerName(customer.getName()));
findAndThen(contractMap, receivable.getContractId(), contract -> receivable.setContractNo(contract.getNo()));
});
return result;
}
static void setUserInfo(CrmReceivableRespVO receivable, Map<Long, AdminUserRespDTO> userMap) {
findAndThen(userMap, receivable.getOwnerUserId(), user -> receivable.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(receivable.getCreator()), user -> receivable.setCreatorName(user.getNickname()));
return voPageResult;
}
@Mapping(target = "bizId", source = "reqVO.id")

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.convert.receivable;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanCreateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.receivable.vo.plan.CrmReceivablePlanTransferReqVO;
@ -37,33 +38,22 @@ public interface CrmReceivablePlanConvert {
CrmReceivablePlanRespVO convert(CrmReceivablePlanDO bean);
List<CrmReceivablePlanRespVO> convertList(List<CrmReceivablePlanDO> list);
default PageResult<CrmReceivablePlanRespVO> convertPage(PageResult<CrmReceivablePlanDO> pageResult, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContractDO> contractList,
List<CrmReceivableDO> receivableList) {
return new PageResult<>(converList(pageResult.getList(), userMap, customerList, contractList, receivableList), pageResult.getTotal());
}
default List<CrmReceivablePlanRespVO> converList(List<CrmReceivablePlanDO> receivablePlanList, Map<Long, AdminUserRespDTO> userMap,
List<CrmCustomerDO> customerList, List<CrmContractDO> contractList,
List<CrmReceivableDO> receivableList) {
List<CrmReceivablePlanRespVO> result = convertList(receivablePlanList);
PageResult<CrmReceivablePlanRespVO> voPageResult = BeanUtils.toBean(pageResult, CrmReceivablePlanRespVO.class);
// 拼接关联字段
Map<Long, CrmCustomerDO> customerMap = convertMap(customerList, CrmCustomerDO::getId);
Map<Long, CrmContractDO> contractMap = convertMap(contractList, CrmContractDO::getId);
Map<Long, CrmReceivableDO> receivableMap = convertMap(receivableList, CrmReceivableDO::getId);
result.forEach(item -> {
setUserInfo(item, userMap);
findAndThen(customerMap, item.getCustomerId(), customer -> item.setCustomerName(customer.getName()));
findAndThen(contractMap, item.getContractId(), contract -> item.setContractNo(contract.getNo()));
findAndThen(receivableMap, item.getReceivableId(), receivable -> item.setReturnType(receivable.getReturnType()));
voPageResult.getList().forEach(receivablePlan -> {
findAndThen(userMap, receivablePlan.getOwnerUserId(), user -> receivablePlan.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(receivablePlan.getCreator()), user -> receivablePlan.setCreatorName(user.getNickname()));
findAndThen(customerMap, receivablePlan.getCustomerId(), customer -> receivablePlan.setCustomerName(customer.getName()));
findAndThen(contractMap, receivablePlan.getContractId(), contract -> receivablePlan.setContractNo(contract.getNo()));
findAndThen(receivableMap, receivablePlan.getReceivableId(), receivable -> receivablePlan.setReturnType(receivable.getReturnType()));
});
return result;
}
static void setUserInfo(CrmReceivablePlanRespVO receivablePlan, Map<Long, AdminUserRespDTO> userMap) {
findAndThen(userMap, receivablePlan.getOwnerUserId(), user -> receivablePlan.setOwnerUserName(user.getNickname()));
findAndThen(userMap, Long.parseLong(receivablePlan.getCreator()), user -> receivablePlan.setCreatorName(user.getNickname()));
return voPageResult;
}
@Mapping(target = "bizId", source = "reqVO.id")

View File

@ -1,4 +0,0 @@
/**
* 商机销售机会
*/
package cn.iocoder.yudao.module.crm.dal.dataobject.business;

View File

@ -1,28 +1,26 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink;
package cn.iocoder.yudao.module.crm.dal.dataobject.contact;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
// TODO @zyna可以放到 contact 包下
/**
* CRM 联系人商机关联 DO
* CRM 联系人商机关联 DO
*
* @author 芋道源码
*/
@TableName("crm_contact_business_link")
@KeySequence("crm_contact_business_link_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@TableName("crm_contact_business")
@KeySequence("crm_contact_business_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CrmContactBusinessLinkDO extends BaseDO {
public class CrmContactBusinessDO extends BaseDO {
/**
* 主键

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.contact;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -29,9 +30,11 @@ public class CrmContactDO extends BaseDO {
@TableId
private Long id;
/**
* 下次联系时间
* 客户编号
*
* 关联 {@link CrmCustomerDO#getId()}
*/
private LocalDateTime nextTime;
private Long customerId;
/**
* 手机号
*/
@ -45,21 +48,20 @@ public class CrmContactDO extends BaseDO {
*/
private String email;
/**
* 客户编号
* 所在地
*
* 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段
*/
private Long customerId;
private Integer areaId;
/**
* 地址
* 详细地址
*/
private String address;
private String detailAddress;
/**
* 备注
*/
private String remark;
/**
* 最后跟进时间
*/
private LocalDateTime lastTime;
/**
* 直属上级
*
@ -100,10 +102,13 @@ public class CrmContactDO extends BaseDO {
private Long ownerUserId;
/**
* 所在地
*
* 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段
* 最后跟进时间
*/
private Integer areaId;
private LocalDateTime contactLastTime;
// TODO @puhui999增加一个字段 contactLastContent最后跟进内容
/**
* 下次联系时间
*/
private LocalDateTime contactNextTime;
}

View File

@ -12,7 +12,7 @@ import java.time.LocalDateTime;
// TODO 芋艿调整下字段
/**
* 客户 DO
* CRM 客户 DO
*
* @author Wanwan
*/
@ -104,17 +104,21 @@ public class CrmCustomerDO extends BaseDO {
*/
private Long ownerUserId;
/**
* 地区编号
* 所在地
*
* 关联 {@link cn.iocoder.yudao.framework.ip.core.Area#getId()} 字段
*/
private Integer areaId;
/**
* 详细地址
*/
private String detailAddress;
/**
* 最后跟进时间
*/
private LocalDateTime contactLastTime;
// TODO @puhui999增加一个字段 contactLastContent最后跟进内容
/**
* 下次联系时间
*/

View File

@ -0,0 +1,81 @@
package cn.iocoder.yudao.module.crm.dal.dataobject.followup;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.time.LocalDateTime;
import java.util.List;
// TODO @puhui999界面做成一个 list 列表字段是 id跟进人跟进方式跟进时间跟进内容下次联系时间关联联系人关联商机
// TODO @puhui999界面记录时弹窗表单字段是跟进方式跟进内容下次联系时间关联联系人关联商机其中关联联系人关联商机要做成对应的组件列
/**
* 跟进记录 DO
*
* 用于记录客户联系人的每一次跟进
*
* @author 芋道源码
*/
@TableName(value = "crm_follow_up_record")
@KeySequence("crm_follow_up_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CrmFollowUpRecordDO extends BaseDO {
/**
* 编号
*/
@TableId
private Long id;
/**
* 数据类型
*
* 枚举 {@link CrmBizTypeEnum}
*/
private Integer bizType;
/**
* 数据编号
*
* 关联 {@link CrmBizTypeEnum} 对应模块 DO id 字段
*/
private Long bizId;
/**
* 跟进类型
*
* TODO @puhui999可以搞个数据字典打电话发短信上门拜访微信邮箱QQ
*/
private Integer type;
/**
* 跟进内容
*/
private String content;
/**
* 下次联系时间
*/
private LocalDateTime nextTime;
/**
* 关联的商机编号数组
*
* 关联 {@link CrmBusinessDO#getId()}
*/
private List<Long> businessIds;
/**
* 关联的联系人编号数组
*
* 关联 {@link CrmContactDO#getId()}
*/
private List<Long> contactIds;
}

View File

@ -30,7 +30,14 @@ public interface CrmBusinessMapper extends BaseMapperX<CrmBusinessDO> {
default PageResult<CrmBusinessDO> selectPageByCustomerId(CrmBusinessPageReqVO pageReqVO) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<CrmBusinessDO>()
.eq(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号
.eq(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号
.likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName())
.orderByDesc(CrmBusinessDO::getId));
}
default PageResult<CrmBusinessDO> selectPageByContactId(CrmBusinessPageReqVO pageReqVO, Collection<Long> businessIds) {
return selectPage(pageReqVO, new LambdaQueryWrapperX<CrmBusinessDO>()
.in(CrmBusinessDO::getId, businessIds) // 指定商机编号
.likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName())
.orderByDesc(CrmBusinessDO::getId));
}

View File

@ -1,30 +0,0 @@
package cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkPageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContactBusinessLinkDO;
import org.apache.ibatis.annotations.Mapper;
/**
* CRM 联系人商机关联 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface CrmContactBusinessLinkMapper extends BaseMapperX<CrmContactBusinessLinkDO> {
default PageResult<CrmContactBusinessLinkDO> selectPage(CrmContactBusinessLinkPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CrmContactBusinessLinkDO>()
.eqIfPresent(CrmContactBusinessLinkDO::getContactId, reqVO.getContactId())
.eqIfPresent(CrmContactBusinessLinkDO::getBusinessId, reqVO.getBusinessId())
.betweenIfPresent(CrmContactBusinessLinkDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(CrmContactBusinessLinkDO::getId));
} // TODO @zyna方法和方法之间要有空行
default PageResult<CrmContactBusinessLinkDO> selectPageByContact(CrmContactBusinessLinkPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<CrmContactBusinessLinkDO>()
.eqIfPresent(CrmContactBusinessLinkDO::getContactId, reqVO.getContactId())
.orderByDesc(CrmContactBusinessLinkDO::getId));
}
}

View File

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
/**
* CRM 联系人与商机的关联 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface CrmContactBusinessMapper extends BaseMapperX<CrmContactBusinessDO> {
default CrmContactBusinessDO selectByContactIdAndBusinessId(Long contactId, Long businessId) {
return selectOne(CrmContactBusinessDO::getContactId, contactId,
CrmContactBusinessDO::getBusinessId, businessId);
}
default void deleteByContactIdAndBusinessId(Long contactId, Collection<Long> businessIds) {
delete(new LambdaQueryWrapper<CrmContactBusinessDO>()
.eq(CrmContactBusinessDO::getContactId, contactId)
.in(CrmContactBusinessDO::getBusinessId, businessIds));
}
default List<CrmContactBusinessDO> selectListByContactId(Long contactId) {
return selectList(CrmContactBusinessDO::getContactId, contactId);
}
}

View File

@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmC
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 客户限制配置 Mapper
*
@ -21,4 +23,15 @@ public interface CrmCustomerLimitConfigMapper extends BaseMapperX<CrmCustomerLim
.orderByDesc(CrmCustomerLimitConfigDO::getId));
}
default List<CrmCustomerLimitConfigDO> selectListByTypeAndUserIdAndDeptId(
Integer type, Long userId, Long deptId) {
LambdaQueryWrapperX<CrmCustomerLimitConfigDO> query = new LambdaQueryWrapperX<CrmCustomerLimitConfigDO>()
.eq(CrmCustomerLimitConfigDO::getType, type);
query.apply("FIND_IN_SET({0}, user_ids) > 0", userId);
if (deptId != null) {
query.apply("FIND_IN_SET({0}, dept_ids) > 0", deptId);
}
return selectList(query);
}
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.crm.dal.mysql.customer;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
@ -9,6 +10,7 @@ import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.crm.util.CrmQueryWrapperUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.lang.Nullable;
import java.util.Collection;
import java.util.List;
@ -21,6 +23,18 @@ import java.util.List;
@Mapper
public interface CrmCustomerMapper extends BaseMapperX<CrmCustomerDO> {
default Long selectCountByLockStatusAndOwnerUserId(Boolean lockStatus, Long ownerUserId) {
return selectCount(new LambdaUpdateWrapper<CrmCustomerDO>()
.eq(CrmCustomerDO::getLockStatus, lockStatus)
.eq(CrmCustomerDO::getOwnerUserId, ownerUserId));
}
default Long selectCountByDealStatusAndOwnerUserId(@Nullable Boolean dealStatus, Long ownerUserId) {
return selectCount(new LambdaQueryWrapperX<CrmCustomerDO>()
.eqIfPresent(CrmCustomerDO::getDealStatus, dealStatus)
.eq(CrmCustomerDO::getOwnerUserId, ownerUserId));
}
default int updateOwnerUserIdById(Long id, Long ownerUserId) {
return update(new LambdaUpdateWrapper<CrmCustomerDO>()
.eq(CrmCustomerDO::getId, id)

View File

@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessTransferReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import jakarta.validation.Valid;
@ -75,10 +76,20 @@ public interface CrmBusinessService {
* 数据权限基于 {@link CrmCustomerDO} 读取
*
* @param pageReqVO 分页查询
* @return 联系人分页
* @return 商机分页
*/
PageResult<CrmBusinessDO> getBusinessPageByCustomerId(CrmBusinessPageReqVO pageReqVO);
/**
* 获得商机分页基于指定联系人
*
* 数据权限基于 {@link CrmContactDO} 读取
*
* @param pageReqVO 分页参数
* @return 商机分页
*/
PageResult<CrmBusinessDO> getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO);
/**
* 商机转移
*

View File

@ -9,11 +9,12 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusi
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessUpdateReqVO;
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
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.service.customer.CrmCustomerService;
import cn.iocoder.yudao.module.crm.service.contact.CrmContactBusinessService;
import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
import jakarta.annotation.Resource;
@ -25,6 +26,7 @@ import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS;
/**
@ -38,24 +40,26 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
@Resource
private CrmBusinessMapper businessMapper;
@Resource
private CrmCustomerService customerService;
@Resource
private CrmPermissionService crmPermissionService;
private CrmPermissionService permissionService;
@Resource
private CrmContactBusinessService contactBusinessService;
@Override
@Transactional(rollbackFor = Exception.class)
// TODO @商机待定操作日志
public Long createBusiness(CrmBusinessCreateReqVO createReqVO, Long userId) {
// 插入
// 1. 插入商机
CrmBusinessDO business = CrmBusinessConvert.INSTANCE.convert(createReqVO);
businessMapper.insert(business);
// TODO 商机待定插入商机与产品的关联表校验商品存在
// 创建数据权限
crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())
// TODO 商机待定在联系人的详情页如果直接新建商机则需要关联下这里要搞个 CrmContactBusinessDO
// 2. 创建数据权限
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType())
.setBizId(business.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
// 返回
return business.getId();
}
@ -63,12 +67,17 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
@Transactional(rollbackFor = Exception.class)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id",
level = CrmPermissionLevelEnum.WRITE)
// TODO @商机待定操作日志
public void updateBusiness(CrmBusinessUpdateReqVO updateReqVO) {
// 校验存在
// 1. 校验存在
validateBusinessExists(updateReqVO.getId());
// 更新
// 2. 更新商机
CrmBusinessDO updateObj = CrmBusinessConvert.INSTANCE.convert(updateReqVO);
businessMapper.updateById(updateObj);
// TODO 商机待定插入商机与产品的关联表校验商品存在
// TODO @商机待定如果状态发生变化插入商机状态变更记录表
}
@Override
@ -77,10 +86,12 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
public void deleteBusiness(Long id) {
// 校验存在
validateBusinessExists(id);
// TODO @商机待定需要校验有没关联合同CrmContractDO businessId 字段
// 删除
businessMapper.deleteById(id);
// 删除数据权限
crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id);
permissionService.deletePermission(CrmBizTypeEnum.CRM_BUSINESS.getType(), id);
}
private CrmBusinessDO validateBusinessExists(Long id) {
@ -116,19 +127,32 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
return businessMapper.selectPageByCustomerId(pageReqVO);
}
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#pageReqVO.contactId", level = CrmPermissionLevelEnum.READ)
public PageResult<CrmBusinessDO> getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO) {
// 1. 查询关联的商机编号
List<CrmContactBusinessDO> contactBusinessList = contactBusinessService.getContactBusinessListByContactId(
pageReqVO.getContactId());
if (CollUtil.isEmpty(contactBusinessList)) {
return PageResult.empty();
}
// 2. 查询商机分页
return businessMapper.selectPageByContactId(pageReqVO,
convertSet(contactBusinessList, CrmContactBusinessDO::getBusinessId));
}
@Override
@Transactional(rollbackFor = Exception.class)
// TODO @puhui999操作日志
public void transferBusiness(CrmBusinessTransferReqVO reqVO, Long userId) {
// 1 校验商机是否存在
validateBusinessExists(reqVO.getId());
// 2.1 数据权限转移
crmPermissionService.transferPermission(
permissionService.transferPermission(
CrmBusinessConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_BUSINESS.getType()));
// 2.2 设置新的负责人
businessMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
// 3. TODO 记录转移日志
}
}

View File

@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.status.CrmBusine
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusDO;
import jakarta.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
@ -64,4 +66,12 @@ public interface CrmBusinessStatusService {
*/
List<CrmBusinessStatusDO> selectList(CrmBusinessStatusQueryVO queryVO);
/**
* 获得商机状态列表
*
* @param ids 编号数组
* @return 商机状态列表
*/
List<CrmBusinessStatusDO> getBusinessStatusList(Collection<Long> ids);
}

View File

@ -12,6 +12,7 @@ import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -77,4 +78,9 @@ public class CrmBusinessStatusServiceImpl implements CrmBusinessStatusService {
return businessStatusMapper.selectList(queryVO);
}
@Override
public List<CrmBusinessStatusDO> getBusinessStatusList(Collection<Long> ids) {
return businessStatusMapper.selectBatchIds(ids);
}
}

View File

@ -5,8 +5,9 @@ import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusiness
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeQueryVO;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.type.CrmBusinessStatusTypeSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessStatusTypeDO;
import jakarta.validation.Valid;
import java.util.Collection;
import java.util.List;
/**
@ -63,4 +64,12 @@ public interface CrmBusinessStatusTypeService {
*/
List<CrmBusinessStatusTypeDO> selectList(CrmBusinessStatusTypeQueryVO queryVO);
/**
* 获得商机状态类型列表
*
* @param ids 编号数组
* @return 商机状态类型列表
*/
List<CrmBusinessStatusTypeDO> getBusinessStatusTypeList(Collection<Long> ids);
}

View File

@ -17,6 +17,8 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -118,4 +120,9 @@ public class CrmBusinessStatusTypeServiceImpl implements CrmBusinessStatusTypeSe
return businessStatusTypeMapper.selectList(queryVO);
}
@Override
public List<CrmBusinessStatusTypeDO> getBusinessStatusTypeList(Collection<Long> ids) {
return businessStatusTypeMapper.selectBatchIds(ids);
}
}

View File

@ -1,4 +0,0 @@
/**
* 商机销售机会
*/
package cn.iocoder.yudao.module.crm.service.business;

View File

@ -1,4 +0,0 @@
/**
* 线索
*/
package cn.iocoder.yudao.module.crm.service.clue;

View File

@ -0,0 +1,38 @@
package cn.iocoder.yudao.module.crm.service.contact;
import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
import jakarta.validation.Valid;
import java.util.List;
/**
* CRM 联系人与商机的关联 Service 接口
*
* @author 芋道源码
*/
public interface CrmContactBusinessService {
/**
* 创建联系人与商机的关联
*
* @param createReqVO 创建信息
*/
void createContactBusinessList(@Valid CrmContactBusinessReqVO createReqVO);
/**
* 删除联系人与商机的关联
*
* @param deleteReqVO 删除信息
*/
void deleteContactBusinessList(@Valid CrmContactBusinessReqVO deleteReqVO);
/**
* 获得联系人与商机的关联列表基于联系人编号
*
* @param contactId 联系人编号
* @return 联系人商机关联
*/
List<CrmContactBusinessDO> getContactBusinessListByContactId(Long contactId);
}

View File

@ -0,0 +1,83 @@
package cn.iocoder.yudao.module.crm.service.contact;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.crm.controller.admin.contact.vo.CrmContactBusinessReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
import cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink.CrmContactBusinessMapper;
import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.ArrayList;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.BUSINESS_NOT_EXISTS;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTACT_NOT_EXISTS;
// TODO @puhui999数据权限的校验每个操作
/**
* 联系人与商机的关联 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class CrmContactBusinessServiceImpl implements CrmContactBusinessService {
@Resource
private CrmContactBusinessMapper contactBusinessMapper;
@Resource
@Lazy // 延迟加载为了解决延迟加载
private CrmBusinessService businessService;
@Resource
@Lazy // 延迟加载为了解决延迟加载
private CrmContactService contactService;
@Override
public void createContactBusinessList(CrmContactBusinessReqVO createReqVO) {
CrmContactDO contact = contactService.getContact(createReqVO.getContactId());
if (contact == null) {
throw exception(CONTACT_NOT_EXISTS);
}
// 遍历处理考虑到一般数量不会太多代码处理简单
List<CrmContactBusinessDO> saveDOList = new ArrayList<>();
createReqVO.getBusinessIds().forEach(businessId -> {
CrmBusinessDO business = businessService.getBusiness(businessId);
if (business == null) {
throw exception(BUSINESS_NOT_EXISTS);
}
// 关联判重
if (contactBusinessMapper.selectByContactIdAndBusinessId(createReqVO.getContactId(), businessId) != null) {
return;
}
saveDOList.add(new CrmContactBusinessDO(null, createReqVO.getContactId(), businessId));
});
// 批量插入
if (CollUtil.isNotEmpty(saveDOList)) {
contactBusinessMapper.insertBatch(saveDOList);
}
}
@Override
public void deleteContactBusinessList(CrmContactBusinessReqVO deleteReqVO) {
CrmContactDO contact = contactService.getContact(deleteReqVO.getContactId());
if (contact == null) {
throw exception(CONTACT_NOT_EXISTS);
}
// 直接删除
contactBusinessMapper.deleteByContactIdAndBusinessId(
deleteReqVO.getContactId(), deleteReqVO.getBusinessIds());
}
@Override
public List<CrmContactBusinessDO> getContactBusinessListByContactId(Long contactId) {
return contactBusinessMapper.selectListByContactId(contactId);
}
}

View File

@ -43,33 +43,38 @@ public class CrmContactServiceImpl implements CrmContactService {
private CrmCustomerService customerService;
@Resource
private CrmPermissionService crmPermissionService;
@Resource
private AdminUserApi adminUserApi;
@Override
@Transactional(rollbackFor = Exception.class)
// TODO @zyna增加操作日志可以参考 CustomerService内容是 新建了联系人名字
public Long createContact(CrmContactCreateReqVO createReqVO, Long userId) {
// 1.1 校验
// 1. 校验
validateRelationDataExists(createReqVO);
// 1.2 插入
// 2. 插入联系人
CrmContactDO contact = CrmContactConvert.INSTANCE.convert(createReqVO);
contactMapper.insert(contact);
// 2. 创建数据权限
// 3. 创建数据权限
crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setUserId(userId)
.setBizType(CrmBizTypeEnum.CRM_CONTACT.getType()).setBizId(contact.getId())
.setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
// TODO @zyna特殊逻辑如果在商机详情那点击新增联系人可以自动绑定商机
return contact.getId();
}
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
// TODO @zyna增加操作日志可以参考 CustomerService需要 diff 出字段
public void updateContact(CrmContactUpdateReqVO updateReqVO) {
// 1. 校验存在
validateContactExists(updateReqVO.getId());
validateRelationDataExists(updateReqVO);
// 2. 更新
// 2. 更新联系人
CrmContactDO updateObj = CrmContactConvert.INSTANCE.convert(updateReqVO);
contactMapper.updateById(updateObj);
}
@ -99,10 +104,15 @@ public class CrmContactServiceImpl implements CrmContactService {
public void deleteContact(Long id) {
// 校验存在
validateContactExists(id);
// TODO @zyna如果有关联的合同不允许删除Contract.contactId
// 删除
contactMapper.deleteById(id);
// 删除数据权限
crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CONTACT.getType(), id);
// TODO @zyna删除商机联系人关联
// TODO @puhui999删除跟进记录
}
private void validateContactExists(Long id) {
@ -137,6 +147,8 @@ public class CrmContactServiceImpl implements CrmContactService {
}
@Override
// TODO @puhui999权限校验
// TODO @puhui999记录操作日志将联系人名字转移给新负责人
public void transferContact(CrmContactTransferReqVO reqVO, Long userId) {
// 1 校验联系人是否存在
validateContactExists(reqVO.getId());
@ -150,4 +162,4 @@ public class CrmContactServiceImpl implements CrmContactService {
// 3. TODO 记录转移日志
}
}
}

View File

@ -1,72 +0,0 @@
package cn.iocoder.yudao.module.crm.service.contactbusinesslink;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContactBusinessLinkDO;
import jakarta.validation.Valid;
import java.util.List;
/**
* CRM 联系人商机关联 Service 接口
*
* @author 芋道源码
*/
public interface CrmContactBusinessLinkService {
/**
* 创建联系人商机关联
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createContactBusinessLink(@Valid CrmContactBusinessLinkSaveReqVO createReqVO);
/**
* 创建联系人商机关联
*
* @param createReqVO 创建信息
*/
void createContactBusinessLinkBatch(@Valid List<CrmContactBusinessLinkSaveReqVO> createReqVO);
/**
* 更新联系人商机关联
*
* @param updateReqVO 更新信息
*/
void updateContactBusinessLink(@Valid CrmContactBusinessLinkSaveReqVO updateReqVO);
/**
* 删除联系人商机关联
*
* @param createReqVO 删除列表
*/
void deleteContactBusinessLink(@Valid List<CrmContactBusinessLinkSaveReqVO> createReqVO);
/**
* 获得联系人商机关联
*
* @param id 编号
* @return 联系人商机关联
*/
CrmContactBusinessLinkDO getContactBusinessLink(Long id);
/**
* 获得联系人商机关联分页
*
* @param pageReqVO 编号
* @return 联系人商机关联
*/
PageResult<CrmBusinessRespVO> getContactBusinessLinkPageByContact(CrmContactBusinessLinkPageReqVO pageReqVO);
/**
* 获得联系人商机关联分页
*
* @param pageReqVO 分页查询
* @return 联系人商机关联分页
*/
PageResult<CrmContactBusinessLinkDO> getContactBusinessLinkPage(CrmContactBusinessLinkPageReqVO pageReqVO);
}

View File

@ -1,112 +0,0 @@
package cn.iocoder.yudao.module.crm.service.contactbusinesslink;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.crm.controller.admin.business.vo.business.CrmBusinessRespVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.contactbusinesslink.vo.CrmContactBusinessLinkSaveReqVO;
import cn.iocoder.yudao.module.crm.convert.business.CrmBusinessConvert;
import cn.iocoder.yudao.module.crm.convert.contactbusinessslink.CrmContactBusinessLinkConvert;
import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
import cn.iocoder.yudao.module.crm.dal.dataobject.contactbusinesslink.CrmContactBusinessLinkDO;
import cn.iocoder.yudao.module.crm.dal.mysql.contactbusinesslink.CrmContactBusinessLinkMapper;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
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.service.business.CrmBusinessService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CONTACT_BUSINESS_LINK_NOT_EXISTS;
// TODO @puhui999数据权限的校验每个操作
/**
* 联系人商机关联 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class CrmContactBusinessLinkServiceImpl implements CrmContactBusinessLinkService {
@Resource
private CrmContactBusinessLinkMapper contactBusinessLinkMapper;
@Resource
private CrmBusinessService crmBusinessService;
@Override
public Long createContactBusinessLink(CrmContactBusinessLinkSaveReqVO createReqVO) {
CrmContactBusinessLinkDO contactBusinessLink = BeanUtils.toBean(createReqVO, CrmContactBusinessLinkDO.class);
contactBusinessLinkMapper.insert(contactBusinessLink);
return contactBusinessLink.getId();
}
@Override
public void createContactBusinessLinkBatch(List<CrmContactBusinessLinkSaveReqVO> createReqVOList) {
// 插入
// TODO @zyna如果已经关联过不用重复插入
// TODO @zynacontact business 存在校验挪到这里Controller 不用 @Transactional 注解添加到这里哈尽量业务都在 Service
List<CrmContactBusinessLinkDO> saveDoList = CrmContactBusinessLinkConvert.INSTANCE.convert(createReqVOList);
contactBusinessLinkMapper.insertBatch(saveDoList);
}
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
public void updateContactBusinessLink(CrmContactBusinessLinkSaveReqVO updateReqVO) {
// 校验存在
validateContactBusinessLinkExists(updateReqVO.getId());
// 更新
CrmContactBusinessLinkDO updateObj = BeanUtils.toBean(updateReqVO, CrmContactBusinessLinkDO.class);
contactBusinessLinkMapper.updateById(updateObj);
}
@Override
public void deleteContactBusinessLink(List<CrmContactBusinessLinkSaveReqVO> createReqVO) {
// 删除
createReqVO.forEach(item -> {
contactBusinessLinkMapper.delete(new LambdaQueryWrapperX<CrmContactBusinessLinkDO>()
.eq(CrmContactBusinessLinkDO::getBusinessId,item.getBusinessId())
.eq(CrmContactBusinessLinkDO::getContactId,item.getContactId())
.eq(CrmContactBusinessLinkDO::getDeleted,0));
});
}
private void validateContactBusinessLinkExists(Long id) {
if (contactBusinessLinkMapper.selectById(id) == null) {
throw exception(CONTACT_BUSINESS_LINK_NOT_EXISTS);
}
}
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_BUSINESS, bizId = "#id", level = CrmPermissionLevelEnum.READ)
public CrmContactBusinessLinkDO getContactBusinessLink(Long id) {
return contactBusinessLinkMapper.selectById(id);
}
@Override
public PageResult<CrmBusinessRespVO> getContactBusinessLinkPageByContact(CrmContactBusinessLinkPageReqVO pageReqVO) {
CrmContactBusinessLinkPageReqVO crmContactBusinessLinkPageReqVO = new CrmContactBusinessLinkPageReqVO();
crmContactBusinessLinkPageReqVO.setContactId(pageReqVO.getContactId());
PageResult<CrmContactBusinessLinkDO> businessLinkDOS = contactBusinessLinkMapper.selectPageByContact(crmContactBusinessLinkPageReqVO);
List<CrmBusinessDO> businessDOS = crmBusinessService.getBusinessList(CollectionUtils.convertList(businessLinkDOS.getList(),
CrmContactBusinessLinkDO::getBusinessId), getLoginUserId());
PageResult<CrmBusinessRespVO> pageResult = new PageResult<CrmBusinessRespVO>();
pageResult.setList(CrmBusinessConvert.INSTANCE.convert(businessDOS));
pageResult.setTotal(businessLinkDOS.getTotal());
return pageResult;
}
@Override
public PageResult<CrmContactBusinessLinkDO> getContactBusinessLinkPage(CrmContactBusinessLinkPageReqVO pageReqVO) {
return contactBusinessLinkMapper.selectPage(pageReqVO);
}
}

View File

@ -42,8 +42,10 @@ public class CrmContractServiceImpl implements CrmContractService {
private CrmPermissionService crmPermissionService;
@Override
// TODO @puhui999添加操作日志
public Long createContract(CrmContractCreateReqVO createReqVO, Long userId) {
// 插入
// TODO @合同待定插入合同商品需要搞个 BusinessProductDO
// 插入合同
CrmContractDO contract = CrmContractConvert.INSTANCE.convert(createReqVO);
contractMapper.insert(contract);
@ -57,18 +59,26 @@ public class CrmContractServiceImpl implements CrmContractService {
@Override
@Transactional(rollbackFor = Exception.class)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
// TODO @puhui999添加操作日志
public void updateContract(CrmContractUpdateReqVO updateReqVO) {
// TODO @合同待定只有草稿审批中可以编辑
// 校验存在
validateContractExists(updateReqVO.getId());
// 更新
// 更新合同
CrmContractDO updateObj = CrmContractConvert.INSTANCE.convert(updateReqVO);
contractMapper.updateById(updateObj);
// TODO @合同待定插入合同商品需要搞个 BusinessProductDO
}
// TODO @合同待定缺一个取消合同的接口只有草稿审批中可以取消CrmAuditStatusEnum
// TODO @合同待定缺一个发起审批的接口只有草稿可以发起审批CrmAuditStatusEnum
@Override
@Transactional(rollbackFor = Exception.class)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
public void deleteContract(Long id) {
// TODO @合同待定如果被 CrmReceivableDO 所使用则不允许删除
// 校验存在
validateContractExists(id);
// 删除
@ -112,6 +122,8 @@ public class CrmContractServiceImpl implements CrmContractService {
@Override
@Transactional(rollbackFor = Exception.class)
// 3. TODO @puhui999记录转移日志
// TODO @puhui999权限校验这里要搞哇
public void transferContract(CrmContractTransferReqVO reqVO, Long userId) {
// 1. 校验合同是否存在
validateContractExists(reqVO.getId());
@ -121,9 +133,7 @@ public class CrmContractServiceImpl implements CrmContractService {
CrmContractConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CONTRACT.getType()));
// 2.2 设置负责人
contractMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
// 3. TODO 记录转移日志
}
// TODO @合同待定需要新增一个 ContractConfigDO 合同配置重点是到期提醒
}

View File

@ -5,9 +5,10 @@ import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmC
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigUpdateReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfigDO;
import jakarta.validation.Valid;
import java.util.List;
/**
* 客户限制配置 Service 接口
*
@ -53,4 +54,12 @@ public interface CrmCustomerLimitConfigService {
*/
PageResult<CrmCustomerLimitConfigDO> getCustomerLimitConfigPage(CrmCustomerLimitConfigPageReqVO pageReqVO);
/**
* 查询用户对应的配置列表
*
* @param type 类型
* @param userId 用户类型
*/
List<CrmCustomerLimitConfigDO> getCustomerLimitConfigListByUserId(Integer type, Long userId);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.crm.service.customer;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigCreateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.limitconfig.CrmCustomerLimitConfigPageReqVO;
@ -9,12 +10,14 @@ import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerLimitConfi
import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerLimitConfigMapper;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.util.Collection;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.CUSTOMER_LIMIT_CONFIG_NOT_EXISTS;
@ -30,12 +33,14 @@ public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfig
@Resource
private CrmCustomerLimitConfigMapper customerLimitConfigMapper;
@Resource
private DeptApi deptApi;
@Resource
private AdminUserApi adminUserApi;
@Override
// TODO @puhui999操作日志
public Long createCustomerLimitConfig(CrmCustomerLimitConfigCreateReqVO createReqVO) {
validateUserAndDept(createReqVO.getUserIds(), createReqVO.getDeptIds());
// 插入
@ -46,6 +51,7 @@ public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfig
}
@Override
// TODO @puhui999操作日志
public void updateCustomerLimitConfig(CrmCustomerLimitConfigUpdateReqVO updateReqVO) {
// 校验存在
validateCustomerLimitConfigExists(updateReqVO.getId());
@ -56,6 +62,7 @@ public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfig
}
@Override
// TODO @puhui999操作日志
public void deleteCustomerLimitConfig(Long id) {
// 校验存在
validateCustomerLimitConfigExists(id);
@ -90,4 +97,11 @@ public class CrmCustomerLimitConfigServiceImpl implements CrmCustomerLimitConfig
adminUserApi.validateUserList(userIds);
}
@Override
public List<CrmCustomerLimitConfigDO> getCustomerLimitConfigListByUserId(Integer type, Long userId) {
AdminUserRespDTO user = adminUserApi.getUser(userId);
Assert.notNull(user, "用户({})不存在", userId);
return customerLimitConfigMapper.selectListByTypeAndUserIdAndDeptId(type, userId, user.getDeptId());
}
}

View File

@ -38,6 +38,7 @@ public class CrmCustomerPoolConfigServiceImpl implements CrmCustomerPoolConfigSe
* @param saveReqVO 更新信息
*/
@Override
// TODO @puhui999操作日志
public void saveCustomerPoolConfig(CrmCustomerPoolConfigSaveReqVO saveReqVO) {
// 存在则进行更新
CrmCustomerPoolConfigDO dbConfig = getCustomerPoolConfig();

View File

@ -1,10 +1,7 @@
package cn.iocoder.yudao.module.crm.service.customer;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerUpdateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
import jakarta.validation.Valid;
@ -56,7 +53,7 @@ public interface CrmCustomerService {
* @return 客户列表
* @author ljlleo
*/
List<CrmCustomerDO> getCustomerList(Collection<Long> ids, Long userId);
List<CrmCustomerDO> getCustomerList(Collection<Long> ids);
/**
* 获得客户分页
@ -85,9 +82,10 @@ public interface CrmCustomerService {
/**
* 锁定/解锁客户
*
* @param updateReqVO 更新信息
* @param lockReqVO 更新信息
* @param userId 用户编号
*/
void lockCustomer(@Valid CrmCustomerUpdateReqVO updateReqVO);
void lockCustomer(@Valid CrmCustomerLockReqVO lockReqVO, Long userId);
// ==================== 公海相关操作 ====================

View File

@ -2,13 +2,12 @@ package cn.iocoder.yudao.module.crm.service.customer;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerCreateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerPageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerTransferReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.CrmCustomerUpdateReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.*;
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.CrmCustomerLimitConfigDO;
import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
@ -24,12 +23,15 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.crm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.CRM_CUSTOMER;
import static cn.iocoder.yudao.module.crm.enums.LogRecordConstants.TRANSFER_CUSTOMER_LOG_SUCCESS;
import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_LOCK_LIMIT;
import static cn.iocoder.yudao.module.crm.enums.customer.CrmCustomerLimitConfigTypeEnum.CUSTOMER_OWNER_LIMIT;
import static java.util.Collections.singletonList;
/**
@ -45,24 +47,32 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
private CrmCustomerMapper customerMapper;
@Resource
private CrmPermissionService crmPermissionService;
private CrmPermissionService permissionService;
@Resource
private CrmCustomerLimitConfigService customerLimitConfigService;
@Resource
private AdminUserApi adminUserApi;
@Override
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_CUSTOMER, subType = "创建客户", bizNo = "{{#customerId}}", success = "创建了客户")
@LogRecord(type = CRM_CUSTOMER, subType = "创建客户", bizNo = "{{#customerId}}", success = "创建了客户") // TODO @puhui999创建了客户客户名要记录进去不然在展示操作日志的全列表看不清楚是哪个客户哈
public Long createCustomer(CrmCustomerCreateReqVO createReqVO, Long userId) {
// 插入
CrmCustomerDO customer = CrmCustomerConvert.INSTANCE.convert(createReqVO);
// 1. 校验拥有客户是否到达上限
validateCustomerExceedOwnerLimit(createReqVO.getOwnerUserId(), 1);
// 2. 插入客户
CrmCustomerDO customer = CrmCustomerConvert.INSTANCE.convert(createReqVO)
.setLockStatus(false).setDealStatus(false)
.setContactLastTime(LocalDateTime.now());
// TODO @puhui999可能要加个 receiveTime 字段记录最后接收时间
customerMapper.insert(customer);
// 创建数据权限
crmPermissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
// 3. 创建数据权限
permissionService.createPermission(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
.setBizId(customer.getId()).setUserId(userId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel())); // 设置当前操作的人为负责人
// 记录操作日志
// 4. 记录操作日志
LogRecordContext.putVariable("customerId", customer.getId());
return customer.getId();
}
@ -72,14 +82,15 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
@LogRecord(type = CRM_CUSTOMER, subType = "更新客户", bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}", extra = "{{#extra}}")
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
public void updateCustomer(CrmCustomerUpdateReqVO updateReqVO) {
// 校验存在
// TODO @puhui999更新的时候要把 updateReqVO 负责人设置为空避免修改
// 1. 校验存在
CrmCustomerDO oldCustomer = validateCustomerExists(updateReqVO.getId());
// 更新
// 2. 更新客户
CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
customerMapper.updateById(updateObj);
// 记录操作日志
// 3. 记录操作日志
LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(oldCustomer, CrmCustomerUpdateReqVO.class));
// TODO 扩展信息测试 @puhui999看着没啥问题可以删除啦
HashMap<String, Object> extra = new HashMap<>();
@ -94,11 +105,13 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
public void deleteCustomer(Long id) {
// 校验存在
validateCustomerExists(id);
// TODO @puhui999如果有联系人商机则不允许删除
// 删除
customerMapper.deleteById(id);
// 删除数据权限
crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id);
permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), id);
// TODO @puhui999删除跟进记录
}
private CrmCustomerDO validateCustomerExists(Long id) {
@ -116,11 +129,11 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
}
@Override
public List<CrmCustomerDO> getCustomerList(Collection<Long> ids, Long userId) {
public List<CrmCustomerDO> getCustomerList(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return Collections.emptyList();
}
return customerMapper.selectBatchIds(ids, userId);
return customerMapper.selectBatchIds(ids);
}
@Override
@ -140,38 +153,91 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
@Override
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_CUSTOMER, subType = "客户转移", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
@LogRecord(type = CRM_CUSTOMER, subType = "转移客户", bizNo = "{{#reqVO.id}}", success = TRANSFER_CUSTOMER_LOG_SUCCESS)
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#reqVO.id", level = CrmPermissionLevelEnum.OWNER)
public void transferCustomer(CrmCustomerTransferReqVO reqVO, Long userId) {
// 1. 校验客户是否存在
CrmCustomerDO customerDO = validateCustomerExists(reqVO.getId());
// 1.1 校验客户是否存在
CrmCustomerDO customer = validateCustomerExists(reqVO.getId());
// 1.2 校验拥有客户是否到达上限
validateCustomerExceedOwnerLimit(reqVO.getNewOwnerUserId(), 1);
// 2.1 数据权限转移
crmPermissionService.transferPermission(
permissionService.transferPermission(
CrmCustomerConvert.INSTANCE.convert(reqVO, userId).setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType()));
// 2.2 转移后重新设置负责人
customerMapper.updateOwnerUserIdById(reqVO.getId(), reqVO.getNewOwnerUserId());
// 3. TODO 记录转移日志
LogRecordContext.putVariable("crmCustomer", customerDO);
LogRecordContext.putVariable("crmCustomer", customer);
}
@Override
// TODO @puhui999看看这个能不能根据条件写操作日志
// TODO 如果是 锁定 subType 锁定客户success 将客户锁定
// TODO 如果是 解锁 subType 解锁客户success 将客户解锁
@LogRecord(type = CRM_CUSTOMER, subType = "锁定/解锁客户", bizNo = "{{#updateReqVO.id}}", success = "锁定了客户")
public void lockCustomer(CrmCustomerUpdateReqVO updateReqVO) {
// 校验存在
validateCustomerExists(updateReqVO.getId());
// TODO @Joey可以校验下如果已经对应的锁定状态报个业务异常原因是后续这个业务会记录操作日志会记录多了
// TODO @芋艿业务完善增加锁定上限
// TODO @puhui999数据权限
public void lockCustomer(CrmCustomerLockReqVO lockReqVO, Long userId) {
// 1.1 校验当前客户是否存在
validateCustomerExists(lockReqVO.getId());
// 1.2 校验当前是否重复操作锁定/解锁状态
CrmCustomerDO customer = customerMapper.selectById(lockReqVO.getId());
if (customer.getLockStatus().equals(lockReqVO.getLockStatus())) {
throw exception(customer.getLockStatus() ? CUSTOMER_LOCK_FAIL_IS_LOCK : CUSTOMER_UNLOCK_FAIL_IS_UNLOCK);
}
// 1.3 校验锁定上限
if (lockReqVO.getLockStatus()) {
validateCustomerExceedLockLimit(userId);
}
// 更新
CrmCustomerDO updateObj = CrmCustomerConvert.INSTANCE.convert(updateReqVO);
customerMapper.updateById(updateObj);
// 2. 更新锁定状态
customerMapper.updateById(BeanUtils.toBean(lockReqVO, CrmCustomerDO.class));
}
/**
* 校验用户拥有的客户数量是否到达上限
*
* @param userId 用户编号
* @param newCount 附加数量
*/
private void validateCustomerExceedOwnerLimit(Long userId, int newCount) {
List<CrmCustomerLimitConfigDO> limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId(
CUSTOMER_OWNER_LIMIT.getType(), userId);
if (CollUtil.isEmpty(limitConfigs)) {
return;
}
Long ownerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(null, userId);
Long dealOwnerCount = customerMapper.selectCountByDealStatusAndOwnerUserId(true, userId);
limitConfigs.forEach(limitConfig -> {
long nowCount = limitConfig.getDealCountEnabled() ? ownerCount : ownerCount - dealOwnerCount;
if (nowCount + newCount > limitConfig.getMaxCount()) {
throw exception(CUSTOMER_OWNER_EXCEED_LIMIT);
}
});
}
/**
* 校验用户锁定的客户数量是否到达上限
*
* @param userId 用户编号
*/
private void validateCustomerExceedLockLimit(Long userId) {
List<CrmCustomerLimitConfigDO> limitConfigs = customerLimitConfigService.getCustomerLimitConfigListByUserId(
CUSTOMER_LOCK_LIMIT.getType(), userId);
if (CollUtil.isEmpty(limitConfigs)) {
return;
}
Long lockCount = customerMapper.selectCountByLockStatusAndOwnerUserId(true, userId);
Integer maxCount = CollectionUtils.getMaxValue(limitConfigs, CrmCustomerLimitConfigDO::getMaxCount);
assert maxCount != null;
if (lockCount >= maxCount) {
throw exception(CUSTOMER_LOCK_EXCEED_LIMIT);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
@LogRecord(type = CRM_CUSTOMER, subType = "客户放入公海", bizNo = "{{#id}}", success = "将客户放入了公海")
@LogRecord(type = CRM_CUSTOMER, subType = "客户放入公海", bizNo = "{{#id}}", success = "将客户放入了公海") // TODO @puhui999将客户放入了公海
@CrmPermission(bizType = CrmBizTypeEnum.CRM_CUSTOMER, bizId = "#id", level = CrmPermissionLevelEnum.OWNER)
public void putCustomerPool(Long id) {
// 1. 校验存在
@ -190,12 +256,18 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
throw exception(CUSTOMER_UPDATE_OWNER_USER_FAIL);
}
// 3. 删除负责人数据权限
crmPermissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(),
permissionService.deletePermission(CrmBizTypeEnum.CRM_CUSTOMER.getType(), customer.getId(),
CrmPermissionLevelEnum.OWNER.getLevel());
// TODO @puhui999联系人的负责人也要设置为 null这块和领取是对应的因为领取后负责人也要关联过来
}
@Override
@Transactional(rollbackFor = Exception.class)
// TODO @puhui999权限校验
// TODO @puhui999如果是分配操作日志是 将客户分配给
// TODO @puhui999如果是领取操作日志是领取客户
// TODO @puhui999如果是多条则需要记录多条操作日志不然 bizId 不好关联
public void receiveCustomer(List<Long> ids, Long ownerUserId) {
// 1.1 校验存在
List<CrmCustomerDO> customers = customerMapper.selectBatchIds(ids);
@ -213,8 +285,10 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
// 校验成交状态
validateCustomerDeal(customer);
});
// 1.4 校验负责人是否到达上限
validateCustomerExceedOwnerLimit(ownerUserId, customers.size());
// 2. 领取公海数据
// 2.1 领取公海数据
List<CrmCustomerDO> updateCustomers = new ArrayList<>();
List<CrmPermissionCreateReqBO> createPermissions = new ArrayList<>();
customers.forEach(customer -> {
@ -224,11 +298,11 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
createPermissions.add(new CrmPermissionCreateReqBO().setBizType(CrmBizTypeEnum.CRM_CUSTOMER.getType())
.setBizId(customer.getId()).setUserId(ownerUserId).setLevel(CrmPermissionLevelEnum.OWNER.getLevel()));
});
// 3.1 更新客户负责人
// 2.2 更新客户负责人
customerMapper.updateBatch(updateCustomers);
// 3.2 创建负责人数据权限
crmPermissionService.createPermissionBatch(createPermissions);
// 2.3 创建负责人数据权限
permissionService.createPermissionBatch(createPermissions);
// TODO @芋艿要不要处理关联的联系人
}
private void validateCustomerOwnerExists(CrmCustomerDO customer, Boolean pool) {

View File

@ -35,18 +35,20 @@ public class CrmProductCategoryServiceImpl implements CrmProductCategoryService
private CrmProductService crmProductService;
@Override
// TODO @puhui999操作日志
public Long createProductCategory(CrmProductCategoryCreateReqVO createReqVO) {
// 1.1 校验父分类存在
validateParentProductCategory(createReqVO.getParentId());
// 1.2 分类名称是否存在
validateProductNameExists(null, createReqVO.getParentId(), createReqVO.getName());
// 2. 插入
// 2. 插入分类
CrmProductCategoryDO category = BeanUtils.toBean(createReqVO, CrmProductCategoryDO.class);
productCategoryMapper.insert(category);
return category.getId();
}
@Override
// TODO @puhui999操作日志
public void updateProductCategory(CrmProductCategoryCreateReqVO updateReqVO) {
// 1.1 校验存在
validateProductCategoryExists(updateReqVO.getId());
@ -54,7 +56,7 @@ public class CrmProductCategoryServiceImpl implements CrmProductCategoryService
validateParentProductCategory(updateReqVO.getParentId());
// 1.3 分类名称是否存在
validateProductNameExists(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
// 2. 更新
// 2. 更新分类
CrmProductCategoryDO updateObj = BeanUtils.toBean(updateReqVO, CrmProductCategoryDO.class);
productCategoryMapper.updateById(updateObj);
}
@ -91,19 +93,19 @@ public class CrmProductCategoryServiceImpl implements CrmProductCategoryService
}
@Override
// TODO @puhui999操作日志
public void deleteProductCategory(Long id) {
// TODO zange参考 mall ProductCategoryServiceImpl 补充下必要的参数校验
// 校验存在
// 1.1 校验存在
validateProductCategoryExists(id);
// 校验是否还有子分类
// 1.2 校验是否还有子分类
if (productCategoryMapper.selectCountByParentId(id) > 0) {
throw exception(product_CATEGORY_EXISTS_CHILDREN);
}
// 校验是否被产品使用
// 1.3 校验是否被产品使用
if (crmProductService.getProductByCategoryId(id) !=null) {
throw exception(PRODUCT_CATEGORY_USED);
}
// 删除
// 2. 删除
productCategoryMapper.deleteById(id);
}

View File

@ -48,6 +48,7 @@ public class CrmProductServiceImpl implements CrmProductService {
private AdminUserApi adminUserApi;
@Override
// TODO @puhui999操作日志
public Long createProduct(CrmProductSaveReqVO createReqVO) {
// 校验产品
adminUserApi.validateUserList(Collections.singleton(createReqVO.getOwnerUserId()));
@ -66,6 +67,7 @@ public class CrmProductServiceImpl implements CrmProductService {
}
@Override
// TODO @puhui999操作日志
public void updateProduct(CrmProductSaveReqVO updateReqVO) {
// 校验产品
updateReqVO.setOwnerUserId(null); // 不修改负责人
@ -102,6 +104,7 @@ public class CrmProductServiceImpl implements CrmProductService {
}
@Override
// TODO @puhui999操作日志
public void deleteProduct(Long id) {
// 校验存在
validateProductExists(id);

View File

@ -1,4 +0,0 @@
/**
* 产品表
*/
package cn.iocoder.yudao.module.crm.service.product;

View File

@ -52,7 +52,10 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
private CrmPermissionService crmPermissionService;
@Override
// TODO @puhui999操作日志
public Long createReceivablePlan(CrmReceivablePlanCreateReqVO createReqVO, Long userId) {
// TODO @liuhongfeng第几期的计算基于是 contractId + contractDO 的第几个还款
// TODO @liuhongfeng contractId校验合同是否存在
// 插入
CrmReceivablePlanDO receivablePlan = CrmReceivablePlanConvert.INSTANCE.convert(createReqVO);
receivablePlan.setFinishStatus(false);
@ -87,7 +90,9 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
@Override
@CrmPermission(bizType = CrmBizTypeEnum.CRM_RECEIVABLE_PLAN, bizId = "#updateReqVO.id", level = CrmPermissionLevelEnum.WRITE)
// TODO @puhui999操作日志
public void updateReceivablePlan(CrmReceivablePlanUpdateReqVO updateReqVO) {
// TODO @liuhongfeng如果已经有对应的还款则不允许编辑
// 校验存在
validateReceivablePlanExists(updateReqVO.getId());
@ -136,6 +141,7 @@ public class CrmReceivablePlanServiceImpl implements CrmReceivablePlanService {
return receivablePlanMapper.selectPageByCustomerId(pageReqVO);
}
// TODO @puhui999这个没有 transfer 接口可能是的哈
@Override
public void transferReceivablePlan(CrmReceivablePlanTransferReqVO reqVO, Long userId) {
// 1 校验回款计划是否存在

View File

@ -53,10 +53,10 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
@Resource
private CrmPermissionService crmPermissionService;
// TODO @liuhongfeng创建还款后是不是什么时候要更新 plan
@Override
// TODO @puhui999操作日志
public Long createReceivable(CrmReceivableCreateReqVO createReqVO) {
// 插入
// 插入还款
CrmReceivableDO receivable = CrmReceivableConvert.INSTANCE.convert(createReqVO);
if (ObjectUtil.isNull(receivable.getAuditStatus())) {
receivable.setAuditStatus(CommonStatusEnum.ENABLE.getStatus());
@ -64,15 +64,17 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
receivable.setAuditStatus(CrmAuditStatusEnum.DRAFT.getStatus());
// TODO @liuhongfeng一般来说逻辑的写法是要先检查后操作 db所以你这个 check 应该放到 CrmReceivableDO receivable 之前
// 校验
checkReceivable(receivable);
receivableMapper.insert(receivable);
// TODO @liuhongfeng需要更新关联的 plan
return receivable.getId();
}
// TODO @liuhongfeng这里的括号要注意排版
private void checkReceivable(CrmReceivableDO receivable) {
// TODO @liuhongfeng校验 no 的唯一性
// TODO @liuhongfeng这个放在参数校验合适
if (ObjectUtil.isNull(receivable.getContractId())) {
throw exception(CONTRACT_NOT_EXISTS);
@ -96,17 +98,29 @@ public class CrmReceivableServiceImpl implements CrmReceivableService {
}
@Override
// TODO @puhui999操作日志
// TODO @puhui999权限校验
public void updateReceivable(CrmReceivableUpdateReqVO updateReqVO) {
// 校验存在
validateReceivableExists(updateReqVO.getId());
// TODO @liuhongfeng只有在草稿审核中可以提交修改
// 更新
// 更新还款
CrmReceivableDO updateObj = CrmReceivableConvert.INSTANCE.convert(updateReqVO);
receivableMapper.updateById(updateObj);
// TODO @liuhongfeng需要更新关联的 plan
}
// TODO @liuhongfeng缺一个取消合同的接口只有草稿审批中可以取消CrmAuditStatusEnum
// TODO @liuhongfeng缺一个发起审批的接口只有草稿可以发起审批CrmAuditStatusEnum
@Override
// TODO @puhui999操作日志
// TODO @puhui999权限校验
public void deleteReceivable(Long id) {
// TODO @liuhongfeng如果被 CrmReceivablePlanDO 所使用则不允许删除
// 校验存在
validateReceivableExists(id);
// 删除

View File

@ -1,4 +0,0 @@
/**
* 回款
*/
package cn.iocoder.yudao.module.crm.service.receivable;