diff --git a/README.md b/README.md index 2ae3cf9cea..a06fba5679 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,8 @@ 如果你想把【完整版】的功能,迁移到【精简版】,可以参考 [《迁移功能到精简版》](https://doc.iocoder.cn/migrate-module/) 文档。 +如果你想把【完整版】的功能,迁移到【精简版】,可以参考 [《迁移功能到精简版》](https://doc.iocoder.cn/migrate-module/) 文档。 + ## 😎 开源协议 **为什么推荐使用本项目?** diff --git a/sql/mysql/optinal/crm.sql b/sql/mysql/optinal/crm.sql index 1cb1371aed..77ec46d97a 100644 --- a/sql/mysql/optinal/crm.sql +++ b/sql/mysql/optinal/crm.sql @@ -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='联系人商机关联表'; \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java index a7494dc8d4..137acee108 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java @@ -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, "数据权限不存在"); diff --git a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java index 6300dee0ee..ec362d4846 100644 --- a/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java +++ b/yudao-module-crm/yudao-module-crm-api/src/main/java/cn/iocoder/yudao/module/crm/enums/customer/CrmCustomerLimitConfigTypeEnum.java @@ -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; /** * 状态名 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java index e4e24d29df..5a5a423cde 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/CrmBusinessController.java @@ -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 @商机待定:CrmBusinessCreateReqVO、CrmBusinessUpdateReqVO、CrmBusinessRespVO 按照新的 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> getBusinessPage(@Valid CrmBusinessPageReqVO pageVO) { PageResult pageResult = businessService.getBusinessPage(pageVO, getLoginUserId()); - if (CollUtil.isEmpty(pageResult.getList())) { - return success(PageResult.empty(pageResult.getTotal())); - } - // 处理客户名称回显 - // TODO @ljlleo:可以使用 CollectionUtils.convertSet 替代常用的 stream 操作,更简洁一点;下面几个也是哈; - Set customerIds = pageResult.getList().stream() - .map(CrmBusinessDO::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet()); - List customerList = customerService.getCustomerList(customerIds, getLoginUserId()); - // 处理商机状态类型名称回显 - Set statusTypeIds = pageResult.getList().stream() - .map(CrmBusinessDO::getStatusTypeId).filter(Objects::nonNull).collect(Collectors.toSet()); - CrmBusinessStatusTypeQueryVO queryStatusTypeVO = new CrmBusinessStatusTypeQueryVO(); - queryStatusTypeVO.setIdList(statusTypeIds); - List statusTypeList = businessStatusTypeService.selectList(queryStatusTypeVO); - // 处理商机状态名称回显 - Set statusIds = pageResult.getList().stream() - .map(CrmBusinessDO::getStatusId).filter(Objects::nonNull).collect(Collectors.toSet()); - CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); - queryVO.setIdList(statusIds); - List 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> getBusinessPageByCustomer(@Valid CrmBusinessPageReqVO pageReqVO) { Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); PageResult pageResult = businessService.getBusinessPageByCustomerId(pageReqVO); - // 处理客户名称回显 - // TODO @ljlleo:可以使用 CollectionUtils.convertSet 替代常用的 stream 操作,更简洁一点;下面几个也是哈; - Set customerIds = pageResult.getList().stream() - .map(CrmBusinessDO::getCustomerId).filter(Objects::nonNull).collect(Collectors.toSet()); - List customerList = customerService.getCustomerList(customerIds, getLoginUserId()); - // 处理商机状态类型名称回显 - Set statusTypeIds = pageResult.getList().stream() - .map(CrmBusinessDO::getStatusTypeId).filter(Objects::nonNull).collect(Collectors.toSet()); - CrmBusinessStatusTypeQueryVO queryStatusTypeVO = new CrmBusinessStatusTypeQueryVO(); - queryStatusTypeVO.setIdList(statusTypeIds); - List statusTypeList = businessStatusTypeService.selectList(queryStatusTypeVO); - // 处理商机状态名称回显 - Set statusIds = pageResult.getList().stream() - .map(CrmBusinessDO::getStatusId).filter(Objects::nonNull).collect(Collectors.toSet()); - CrmBusinessStatusQueryVO queryVO = new CrmBusinessStatusQueryVO(); - queryVO.setIdList(statusIds); - List 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> getBusinessContactPage(@Valid CrmBusinessPageReqVO pageReqVO) { + PageResult pageResult = businessService.getBusinessPageByContact(pageReqVO); + return success(buildBusinessDetailPageResult(pageResult)); } @GetMapping("/export-excel") @@ -152,8 +117,27 @@ public class CrmBusinessController { exportReqVO.setPageSize(PAGE_SIZE_NONE); PageResult 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 buildBusinessDetailPageResult(PageResult pageResult) { + if (CollUtil.isEmpty(pageResult.getList())) { + return PageResult.empty(pageResult.getTotal()); + } + List statusTypeList = businessStatusTypeService.getBusinessStatusTypeList( + convertSet(pageResult.getList(), CrmBusinessDO::getStatusTypeId)); + List statusList = businessStatusService.getBusinessStatusList( + convertSet(pageResult.getList(), CrmBusinessDO::getStatusId)); + List customerList = customerService.getCustomerList( + convertSet(pageResult.getList(), CrmBusinessDO::getCustomerId)); + return CrmBusinessConvert.INSTANCE.convertPage(pageResult, customerList, statusTypeList, statusList); } @PutMapping("/transfer") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java index 3c9520607e..0e47bf5bed 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/business/vo/business/CrmBusinessPageReqVO.java @@ -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 时则表示全部 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java index 9bb06a1bc3..dfb269c8f4 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/CrmContactController.java @@ -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 @zyna:CrmContactCreateReqVO、CrmContactUpdateReqVO、CrmContactRespVO 按照新的 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 customerList = customerService.getCustomerList( - Collections.singletonList(contact.getCustomerId()), getLoginUserId()); + Collections.singletonList(contact.getCustomerId())); // 3. 直属上级 List 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> getSimpleContactList() { + // TODO @zyna:建议 contactService 单独搞个 list 接口哈 CrmContactPageReqVO pageReqVO = new CrmContactPageReqVO(); pageReqVO.setPageSize(PAGE_SIZE_NONE); List 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> getContactPage(@Valid CrmContactPageReqVO pageVO) { PageResult 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> getContactPageByCustomer(@Valid CrmContactPageReqVO pageVO) { Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); PageResult 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 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 convertDetailContactPage(PageResult pageResult) { + private PageResult buildContactDetailPage(PageResult pageResult) { List contactList = pageResult.getList(); if (CollUtil.isEmpty(contactList)) { return PageResult.empty(pageResult.getTotal()); } // 1. 获取客户列表 List crmCustomerDOList = customerService.getCustomerList( - convertSet(contactList, CrmContactDO::getCustomerId), getLoginUserId()); + convertSet(contactList, CrmContactDO::getCustomerId)); // 2. 获取创建人、负责人列表 Map 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 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 deleteContactBusinessList(@Valid @RequestBody CrmContactBusinessReqVO deleteReqVO) { + contactBusinessLinkService.deleteContactBusinessList(deleteReqVO); + return success(true); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBaseVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBaseVO.java index eb984884dd..f210bfd8f3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBaseVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBaseVO.java @@ -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; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java new file mode 100644 index 0000000000..9b360f84b2 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contact/vo/CrmContactBusinessReqVO.java @@ -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 businessIds; + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/CrmContactBusinessLinkController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/CrmContactBusinessLinkController.java deleted file mode 100644 index cc9ae8cd1b..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/CrmContactBusinessLinkController.java +++ /dev/null @@ -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 @zyna:createContactBusinessLink 和 createContactBusinessLinkBatch 是不是合并成一个接口?contactId、List - @PostMapping("/create") - @Operation(summary = "创建联系人商机关联") - @PreAuthorize("@ss.hasPermission('crm:contact-business-link:create')") - public CommonResult 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 createContactBusinessLinkBatch( - @Valid @RequestBody List 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 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 deleteContactBusinessLinkBatch(@Valid @RequestBody List 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 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> getContactBusinessLinkByContact( - @Valid CrmContactBusinessLinkPageReqVO pageReqVO) { - PageResult 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> getContactBusinessLinkPage( - @Valid CrmContactBusinessLinkPageReqVO pageReqVO) { - PageResult pageResult = contactBusinessLinkService.getContactBusinessLinkPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, CrmContactBusinessLinkRespVO.class)); - } - - // TODO @zyna:最终梳理完后,应该就 2 个接口,要不直接合并到 CrmContactController 中,不作为独立模块,就关联、接触关联。其实和 user 设置它有哪些岗位、部门是类似的。 - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkPageReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkPageReqVO.java deleted file mode 100644 index c8e98c15a7..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkPageReqVO.java +++ /dev/null @@ -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; - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkRespVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkRespVO.java deleted file mode 100644 index 17aadf667e..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkRespVO.java +++ /dev/null @@ -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; - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkSaveReqVO.java deleted file mode 100644 index 6f867c5115..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contactbusinesslink/vo/CrmContactBusinessLinkSaveReqVO.java +++ /dev/null @@ -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; - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java index f0442c4d3a..0a40437720 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/contract/CrmContractController.java @@ -88,7 +88,7 @@ public class CrmContractController { @PreAuthorize("@ss.hasPermission('crm:contract:query')") public CommonResult> getContractPage(@Valid CrmContractPageReqVO pageVO) { PageResult 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> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) { Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); PageResult 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 convertDetailContractPage(PageResult pageResult) { + private PageResult buildContractDetailPage(PageResult pageResult) { List contactList = pageResult.getList(); if (CollUtil.isEmpty(contactList)) { return PageResult.empty(pageResult.getTotal()); } // 1. 获取客户列表 List customerList = customerService.getCustomerList( - convertSet(contactList, CrmContractDO::getCustomerId), getLoginUserId()); + convertSet(contactList, CrmContractDO::getCustomerId)); // 2. 获取创建人、负责人列表 Map userMap = adminUserApi.getUserMap(convertListByFlatMap(contactList, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java index cc40ae2579..1ba9cc010f 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerController.java @@ -58,6 +58,7 @@ public class CrmCustomerController { @Resource private OperateLogApi operateLogApi; + // TODO @puhui999:把 CrmCustomerCreateReqVO、CrmCustomerUpdateReqVO、CrmCustomerRespVO 按照新的规范,搞一下哈; @PostMapping("/create") @Operation(summary = "创建客户") @OperateLog(enable = false) // TODO 关闭原有日志记录;@puhui999:注解都先删除。先记录,没关系。我们下个迭代,就都删除掉操作日志了; @@ -114,6 +115,7 @@ public class CrmCustomerController { } // 2. 拼接数据 + // TODO @puhui999:距离进入公海的时间 Map userMap = adminUserApi.getUserMap( convertSetByFlatMap(pageResult.getList(), user -> Stream.of(Long.parseLong(user.getCreator()), user.getOwnerUserId()))); Map 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 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 lockCustomer(@Valid @RequestBody CrmCustomerUpdateReqVO updateReqVO) { - customerService.lockCustomer(updateReqVO); + public CommonResult 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 distributeCustomer(@RequestParam(value = "ids") List ids, @RequestParam(value = "ownerUserId") Long ownerUserId) { - // 领取公海数据 customerService.receiveCustomer(ids, ownerUserId); return success(true); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java index ec86c99d58..7636bc200c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerLimitConfigController.java @@ -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')") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java index a6da45b7d0..8ae8093379 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/CrmCustomerPoolConfigController.java @@ -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')") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerLockReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerLockReqVO.java new file mode 100644 index 0000000000..1cf9ff382b --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerLockReqVO.java @@ -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; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java index 9bdc43532c..09eca73eac 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/CrmCustomerTransferReqVO.java @@ -28,4 +28,6 @@ public class CrmCustomerTransferReqVO { @Schema(description = "老负责人加入团队后的权限级别", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private Integer oldOwnerPermissionLevel; + // TODO @puhui999:联系人、商机、合同的转移 + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java index fa72f5f746..93b6557a40 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/customer/vo/poolconfig/CrmCustomerPoolConfigSaveReqVO.java @@ -16,9 +16,9 @@ import java.util.Objects; @ToString(callSuper = true) public class CrmCustomerPoolConfigSaveReqVO extends CrmCustomerPoolConfigBaseVO { - // TODO @wanwan:AssertTrue 必须 is 开头哈;注意需要 json 忽略下,避免被序列化; + // TODO @puhui999:AssertTrue 必须 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; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java index 5dc3807f5d..7350e69152 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/permission/CrmPermissionController.java @@ -103,6 +103,7 @@ public class CrmPermissionController { // 拼接数据 List userList = adminUserApi.getUserList(convertSet(permission, CrmPermissionDO::getUserId)); Map deptMap = deptApi.getDeptMap(convertSet(userList, AdminUserRespDTO::getDeptId)); + // TODO @puhui999:可能 postIds 为空的时候,会导致报错,看看怎么 fix 下 Set postIds = CollectionUtils.convertSetByFlatMap(userList, AdminUserRespDTO::getPostIds, Collection::stream); Map postMap = postApi.getPostMap(postIds); return success(CrmPermissionConvert.INSTANCE.convert(permission, userList, deptMap, postMap)); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java index a353491e79..e5ae4fd9be 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivableController.java @@ -93,7 +93,7 @@ public class CrmReceivableController { @PreAuthorize("@ss.hasPermission('crm:receivable:query')") public CommonResult> getReceivablePage(@Valid CrmReceivablePageReqVO pageReqVO) { PageResult 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> getReceivablePageByCustomer(@Valid CrmReceivablePageReqVO pageReqVO) { Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); PageResult pageResult = receivableService.getReceivablePageByCustomerId(pageReqVO); - return success(convertDetailReceivablePage(pageResult)); + return success(buildReceivableDetailPage(pageResult)); } // TODO 芋艿:后面在优化导出 @@ -115,23 +115,23 @@ public class CrmReceivableController { PageResult 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 convertDetailReceivablePage(PageResult pageResult) { + private PageResult buildReceivableDetailPage(PageResult pageResult) { List receivableList = pageResult.getList(); if (CollUtil.isEmpty(receivableList)) { return PageResult.empty(pageResult.getTotal()); } // 1. 获取客户列表 List customerList = customerService.getCustomerList( - convertSet(receivableList, CrmReceivableDO::getCustomerId), getLoginUserId()); + convertSet(receivableList, CrmReceivableDO::getCustomerId)); // 2. 获取创建人、负责人列表 Map userMap = adminUserApi.getUserMap(convertListByFlatMap(receivableList, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java index 9f3c238954..7ff0a93857 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/controller/admin/receivable/CrmReceivablePlanController.java @@ -123,10 +123,10 @@ public class CrmReceivablePlanController { } /** - * 转换成详细的回款计划分页,即读取关联信息 + * 构建详细的回款计划分页结果 * - * @param pageResult 回款计划分页 - * @return 详细的回款计划分页 + * @param pageResult 简单的回款计划分页结果 + * @return 详细的回款计划分页结果 */ private PageResult convertDetailReceivablePlanPage(PageResult pageResult) { List receivablePlanList = pageResult.getList(); @@ -135,7 +135,7 @@ public class CrmReceivablePlanController { } // 1. 获取客户列表 List customerList = customerService.getCustomerList( - convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId), getLoginUserId()); + convertSet(receivablePlanList, CrmReceivablePlanDO::getCustomerId)); // 2. 获取创建人、负责人列表 Map userMap = adminUserApi.getUserMap(convertListByFlatMap(receivablePlanList, contact -> Stream.of(NumberUtils.parseLong(contact.getCreator()), contact.getOwnerUserId()))); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java index 3effb21e02..a67812f8b8 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/business/CrmBusinessConvert.java @@ -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 convert(List bean); - PageResult convertPage(PageResult page); - List convertList02(List list); @Mapping(target = "bizId", source = "reqVO.id") CrmPermissionTransferReqBO convert(CrmBusinessTransferReqVO reqVO, Long userId); - default PageResult convertPage(PageResult page, List customerList, + default PageResult convertPage(PageResult pageResult, List customerList, List statusTypeList, List statusList) { - PageResult result = convertPage(page); + PageResult voPageResult = BeanUtils.toBean(pageResult, CrmBusinessRespVO.class); // 拼接关联字段 Map customerMap = convertMap(customerList, CrmCustomerDO::getId, CrmCustomerDO::getName); Map statusTypeMap = convertMap(statusTypeList, CrmBusinessStatusTypeDO::getId, CrmBusinessStatusTypeDO::getName); Map 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; } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/CrmContactConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/CrmContactConvert.java index 421e3cd989..de248d2c64 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/CrmContactConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contact/CrmContactConvert.java @@ -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 convertPage(PageResult page); - default PageResult convertPage(PageResult pageResult, Map userMap, - List customerList, List parentContactList) { - List list = converList(pageResult.getList(), userMap, customerList, parentContactList); - return convertPage(pageResult).setList(list); - } - - List convertAllList(List 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 userMap, List crmCustomerDOList, - List contactList) { + default PageResult convertPage(PageResult pageResult, Map userMap, + List customerList, List parentContactList) { + PageResult voPageResult = BeanUtils.toBean(pageResult, CrmContactRespVO.class); + // 拼接关联字段 + Map parentContactMap = convertMap(parentContactList, CrmContactDO::getId); + Map 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 userMap, + List customerList, List parentContactList) { CrmContactRespVO contactVO = convert(contactDO); setUserInfo(contactVO, userMap); - Map ustomerMap = crmCustomerDOList.stream().collect(Collectors.toMap(CrmCustomerDO::getId, v -> v)); - Map contactMap = contactList.stream().collect(Collectors.toMap(CrmContactDO::getId, v -> v)); - findAndThen(ustomerMap, contactDO.getCustomerId(), customer -> contactVO.setCustomerName(customer.getName())); + Map customerMap = CollectionUtils.convertMap(customerList, CrmCustomerDO::getId); + Map 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 converList(List contactList, Map userMap, - List customerList, List parentContactList) { - List result = convertList(contactList); - Map parentContactMap = convertMap(parentContactList, CrmContactDO::getId); - Map 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 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())); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contactbusinessslink/CrmContactBusinessLinkConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contactbusinessslink/CrmContactBusinessLinkConvert.java deleted file mode 100644 index dfb71bad56..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contactbusinessslink/CrmContactBusinessLinkConvert.java +++ /dev/null @@ -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 convert(List bean); -} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/CrmContractConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/CrmContractConvert.java index 74b7a46635..b898ef4e32 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/CrmContractConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/contract/CrmContractConvert.java @@ -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 convertPage(PageResult pageResult, Map userMap, List customerList) { - return new PageResult<>(converList(pageResult.getList(), userMap, customerList), pageResult.getTotal()); - } - - default List converList(List contractList, Map userMap, - List customerList) { - List result = convertList(contractList); + PageResult voPageResult = BeanUtils.toBean(pageResult, ContractRespVO.class); + // 拼接关联字段 Map 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 userMap) { - findAndThen(userMap, contract.getOwnerUserId(), user -> contract.setOwnerUserName(user.getNickname())); - findAndThen(userMap, Long.parseLong(contract.getCreator()), user -> contract.setCreatorName(user.getNickname())); + return voPageResult; } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java index 55e2a35189..6c8fdcbefb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/customer/CrmCustomerConvert.java @@ -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; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java index e7340fc86c..9f343238a1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivableConvert.java @@ -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 convertList(List list); - default PageResult convertPage(PageResult pageResult, Map userMap, List customerList, List contractList) { - return new PageResult<>(converList(pageResult.getList(), userMap, customerList, contractList), pageResult.getTotal()); - } - - default List converList(List receivableList, Map userMap, - List customerList, List contractList) { - List result = convertList(receivableList); + PageResult voPageResult = BeanUtils.toBean(pageResult, CrmReceivableRespVO.class); + // 拼接关联字段 Map customerMap = convertMap(customerList, CrmCustomerDO::getId); Map 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 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") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivablePlanConvert.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivablePlanConvert.java index 70e9308805..eb459e0711 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivablePlanConvert.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/convert/receivable/CrmReceivablePlanConvert.java @@ -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 convertList(List list); - default PageResult convertPage(PageResult pageResult, Map userMap, List customerList, List contractList, List receivableList) { - return new PageResult<>(converList(pageResult.getList(), userMap, customerList, contractList, receivableList), pageResult.getTotal()); - } - - default List converList(List receivablePlanList, Map userMap, - List customerList, List contractList, - List receivableList) { - List result = convertList(receivablePlanList); + PageResult voPageResult = BeanUtils.toBean(pageResult, CrmReceivablePlanRespVO.class); + // 拼接关联字段 Map customerMap = convertMap(customerList, CrmCustomerDO::getId); Map contractMap = convertMap(contractList, CrmContractDO::getId); Map 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 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") diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/package-info.java deleted file mode 100644 index df6e44536f..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/business/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 商机(销售机会) - */ -package cn.iocoder.yudao.module.crm.dal.dataobject.business; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contactbusinesslink/CrmContactBusinessLinkDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactBusinessDO.java similarity index 61% rename from yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contactbusinesslink/CrmContactBusinessLinkDO.java rename to yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactBusinessDO.java index ad6c898d7a..46185a5ac3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contactbusinesslink/CrmContactBusinessLinkDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactBusinessDO.java @@ -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") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@TableName("crm_contact_business") +@KeySequence("crm_contact_business_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @Builder @NoArgsConstructor @AllArgsConstructor -public class CrmContactBusinessLinkDO extends BaseDO { +public class CrmContactBusinessDO extends BaseDO { /** * 主键 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java index 75d6bd565a..74ced60321 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/contact/CrmContactDO.java @@ -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; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java index c5826b7c39..c35778e3e2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/customer/CrmCustomerDO.java @@ -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;最后跟进内容 /** * 下次联系时间 */ diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java new file mode 100644 index 0000000000..b9138da92c --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/followup/CrmFollowUpRecordDO.java @@ -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") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 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 businessIds; + /** + * 关联的联系人编号数组 + * + * 关联 {@link CrmContactDO#getId()} + */ + private List contactIds; + +} diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java index eb9d50a649..d013520078 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/business/CrmBusinessMapper.java @@ -30,7 +30,14 @@ public interface CrmBusinessMapper extends BaseMapperX { default PageResult selectPageByCustomerId(CrmBusinessPageReqVO pageReqVO) { return selectPage(pageReqVO, new LambdaQueryWrapperX() - .eq(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号 + .eq(CrmBusinessDO::getCustomerId, pageReqVO.getCustomerId()) // 指定客户编号 + .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) + .orderByDesc(CrmBusinessDO::getId)); + } + + default PageResult selectPageByContactId(CrmBusinessPageReqVO pageReqVO, Collection businessIds) { + return selectPage(pageReqVO, new LambdaQueryWrapperX() + .in(CrmBusinessDO::getId, businessIds) // 指定商机编号 .likeIfPresent(CrmBusinessDO::getName, pageReqVO.getName()) .orderByDesc(CrmBusinessDO::getId)); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contactbusinesslink/CrmContactBusinessLinkMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contactbusinesslink/CrmContactBusinessLinkMapper.java deleted file mode 100644 index 1692def86d..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contactbusinesslink/CrmContactBusinessLinkMapper.java +++ /dev/null @@ -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 { - - default PageResult selectPage(CrmContactBusinessLinkPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(CrmContactBusinessLinkDO::getContactId, reqVO.getContactId()) - .eqIfPresent(CrmContactBusinessLinkDO::getBusinessId, reqVO.getBusinessId()) - .betweenIfPresent(CrmContactBusinessLinkDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(CrmContactBusinessLinkDO::getId)); - } // TODO @zyna:方法和方法之间要有空行 - default PageResult selectPageByContact(CrmContactBusinessLinkPageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(CrmContactBusinessLinkDO::getContactId, reqVO.getContactId()) - .orderByDesc(CrmContactBusinessLinkDO::getId)); - } -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contactbusinesslink/CrmContactBusinessMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contactbusinesslink/CrmContactBusinessMapper.java new file mode 100644 index 0000000000..3eae483bcd --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/contactbusinesslink/CrmContactBusinessMapper.java @@ -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 { + + default CrmContactBusinessDO selectByContactIdAndBusinessId(Long contactId, Long businessId) { + return selectOne(CrmContactBusinessDO::getContactId, contactId, + CrmContactBusinessDO::getBusinessId, businessId); + } + + default void deleteByContactIdAndBusinessId(Long contactId, Collection businessIds) { + delete(new LambdaQueryWrapper() + .eq(CrmContactBusinessDO::getContactId, contactId) + .in(CrmContactBusinessDO::getBusinessId, businessIds)); + } + + default List selectListByContactId(Long contactId) { + return selectList(CrmContactBusinessDO::getContactId, contactId); + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java index f5fb31b61c..08beaf8088 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerLimitConfigMapper.java @@ -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 selectListByTypeAndUserIdAndDeptId( + Integer type, Long userId, Long deptId) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .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); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java index 77304575c5..8acd92b3e0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/mysql/customer/CrmCustomerMapper.java @@ -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 { + default Long selectCountByLockStatusAndOwnerUserId(Boolean lockStatus, Long ownerUserId) { + return selectCount(new LambdaUpdateWrapper() + .eq(CrmCustomerDO::getLockStatus, lockStatus) + .eq(CrmCustomerDO::getOwnerUserId, ownerUserId)); + } + + default Long selectCountByDealStatusAndOwnerUserId(@Nullable Boolean dealStatus, Long ownerUserId) { + return selectCount(new LambdaQueryWrapperX() + .eqIfPresent(CrmCustomerDO::getDealStatus, dealStatus) + .eq(CrmCustomerDO::getOwnerUserId, ownerUserId)); + } + default int updateOwnerUserIdById(Long id, Long ownerUserId) { return update(new LambdaUpdateWrapper() .eq(CrmCustomerDO::getId, id) diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java index d81a75d9a4..fad8930e4e 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java @@ -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 getBusinessPageByCustomerId(CrmBusinessPageReqVO pageReqVO); + /** + * 获得商机分页,基于指定联系人 + * + * 数据权限:基于 {@link CrmContactDO} 读取 + * + * @param pageReqVO 分页参数 + * @return 商机分页 + */ + PageResult getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO); + /** * 商机转移 * diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java index 5281084b9b..58c2bccfe5 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java @@ -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 getBusinessPageByContact(CrmBusinessPageReqVO pageReqVO) { + // 1. 查询关联的商机编号 + List 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 记录转移日志 } } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java index ffad53556b..a2fc2d18d0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusService.java @@ -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 selectList(CrmBusinessStatusQueryVO queryVO); + /** + * 获得商机状态列表 + * + * @param ids 编号数组 + * @return 商机状态列表 + */ + List getBusinessStatusList(Collection ids); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java index fa6ad3d03a..2e49e99d77 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusServiceImpl.java @@ -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 getBusinessStatusList(Collection ids) { + return businessStatusMapper.selectBatchIds(ids); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeService.java index 39dc3128c5..20509994e2 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeService.java @@ -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 selectList(CrmBusinessStatusTypeQueryVO queryVO); + /** + * 获得商机状态类型列表 + * + * @param ids 编号数组 + * @return 商机状态类型列表 + */ + List getBusinessStatusTypeList(Collection ids); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeServiceImpl.java index 501780abde..0ebcda87c7 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessStatusTypeServiceImpl.java @@ -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 getBusinessStatusTypeList(Collection ids) { + return businessStatusTypeMapper.selectBatchIds(ids); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/package-info.java deleted file mode 100644 index 8995e12421..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/business/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 商机(销售机会) - */ -package cn.iocoder.yudao.module.crm.service.business; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/package-info.java deleted file mode 100644 index 5cb8b6ec7a..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/clue/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 线索 - */ -package cn.iocoder.yudao.module.crm.service.clue; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java new file mode 100644 index 0000000000..4a4d7a42d4 --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessService.java @@ -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 getContactBusinessListByContactId(Long contactId); + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java new file mode 100644 index 0000000000..d0c92b548c --- /dev/null +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactBusinessServiceImpl.java @@ -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 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 getContactBusinessListByContactId(Long contactId) { + return contactBusinessMapper.selectListByContactId(contactId); + } + +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java index 5edf22a2e6..d55ce447b9 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contact/CrmContactServiceImpl.java @@ -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 记录转移日志 } -} +} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkService.java deleted file mode 100644 index c265c43559..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkService.java +++ /dev/null @@ -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 createReqVO); - - /** - * 更新联系人商机关联 - * - * @param updateReqVO 更新信息 - */ - void updateContactBusinessLink(@Valid CrmContactBusinessLinkSaveReqVO updateReqVO); - - /** - * 删除联系人商机关联 - * - * @param createReqVO 删除列表 - */ - void deleteContactBusinessLink(@Valid List createReqVO); - - /** - * 获得联系人商机关联 - * - * @param id 编号 - * @return 联系人商机关联 - */ - CrmContactBusinessLinkDO getContactBusinessLink(Long id); - - /** - * 获得联系人商机关联分页 - * - * @param pageReqVO 编号 - * @return 联系人商机关联 - */ - PageResult getContactBusinessLinkPageByContact(CrmContactBusinessLinkPageReqVO pageReqVO); - - /** - * 获得联系人商机关联分页 - * - * @param pageReqVO 分页查询 - * @return 联系人商机关联分页 - */ - PageResult getContactBusinessLinkPage(CrmContactBusinessLinkPageReqVO pageReqVO); - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java deleted file mode 100644 index 94de4d7bef..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contactbusinesslink/CrmContactBusinessLinkServiceImpl.java +++ /dev/null @@ -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 createReqVOList) { - // 插入 - // TODO @zyna:如果已经关联过,不用重复插入; - // TODO @zyna:contact 和 business 存在校验,挪到这里,Controller 不用 @Transactional 注解,添加到这里哈。尽量业务都在 Service; - List 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 createReqVO) { - // 删除 - createReqVO.forEach(item -> { - contactBusinessLinkMapper.delete(new LambdaQueryWrapperX() - .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 getContactBusinessLinkPageByContact(CrmContactBusinessLinkPageReqVO pageReqVO) { - CrmContactBusinessLinkPageReqVO crmContactBusinessLinkPageReqVO = new CrmContactBusinessLinkPageReqVO(); - crmContactBusinessLinkPageReqVO.setContactId(pageReqVO.getContactId()); - PageResult businessLinkDOS = contactBusinessLinkMapper.selectPageByContact(crmContactBusinessLinkPageReqVO); - List businessDOS = crmBusinessService.getBusinessList(CollectionUtils.convertList(businessLinkDOS.getList(), - CrmContactBusinessLinkDO::getBusinessId), getLoginUserId()); - PageResult pageResult = new PageResult(); - pageResult.setList(CrmBusinessConvert.INSTANCE.convert(businessDOS)); - pageResult.setTotal(businessLinkDOS.getTotal()); - return pageResult; - - } - - @Override - public PageResult getContactBusinessLinkPage(CrmContactBusinessLinkPageReqVO pageReqVO) { - return contactBusinessLinkMapper.selectPage(pageReqVO); - } - -} \ No newline at end of file diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java index 00d6c5e4c5..bb010265f0 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java @@ -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 表,合同配置,重点是到期提醒; } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java index 96090cdfc1..585d49f0a3 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigService.java @@ -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 getCustomerLimitConfigPage(CrmCustomerLimitConfigPageReqVO pageReqVO); + /** + * 查询用户对应的配置列表 + * + * @param type 类型 + * @param userId 用户类型 + */ + List getCustomerLimitConfigListByUserId(Integer type, Long userId); + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java index 4528eafada..d9f1775499 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerLimitConfigServiceImpl.java @@ -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 getCustomerLimitConfigListByUserId(Integer type, Long userId) { + AdminUserRespDTO user = adminUserApi.getUser(userId); + Assert.notNull(user, "用户({})不存在", userId); + return customerLimitConfigMapper.selectListByTypeAndUserIdAndDeptId(type, userId, user.getDeptId()); + } + } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java index 069bb9ab6e..82aa4378fb 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerPoolConfigServiceImpl.java @@ -38,6 +38,7 @@ public class CrmCustomerPoolConfigServiceImpl implements CrmCustomerPoolConfigSe * @param saveReqVO 更新信息 */ @Override + // TODO @puhui999:操作日志 public void saveCustomerPoolConfig(CrmCustomerPoolConfigSaveReqVO saveReqVO) { // 存在,则进行更新 CrmCustomerPoolConfigDO dbConfig = getCustomerPoolConfig(); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java index 73be189513..c7eeaaf4a1 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerService.java @@ -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 getCustomerList(Collection ids, Long userId); + List getCustomerList(Collection 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); // ==================== 公海相关操作 ==================== diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java index 0ab626b8f6..ad0ee9a76c 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerServiceImpl.java @@ -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 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 getCustomerList(Collection ids, Long userId) { + public List getCustomerList(Collection 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 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 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 ids, Long ownerUserId) { // 1.1 校验存在 List 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 updateCustomers = new ArrayList<>(); List 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) { diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java index 388f6133b4..c91ab87e1a 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductCategoryServiceImpl.java @@ -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); } diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java index ba7b8ac836..e604a47acc 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java @@ -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); diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/package-info.java deleted file mode 100644 index cae179aeaa..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/product/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 产品表 - */ -package cn.iocoder.yudao.module.crm.service.product; diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java index e6940e793a..453c82d396 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivablePlanServiceImpl.java @@ -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 校验回款计划是否存在 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java index 6071c2615e..5100ddd6ef 100644 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java +++ b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/CrmReceivableServiceImpl.java @@ -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); // 删除 diff --git a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/package-info.java b/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/package-info.java deleted file mode 100644 index 4004b301d0..0000000000 --- a/yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/service/receivable/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * 回款 - */ -package cn.iocoder.yudao.module.crm.service.receivable;